diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-07-25 16:21:23 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-07-25 16:21:23 -0700 |
| commit | 941b834f3ba15eba9bfa80eb370077ec9c845efd (patch) | |
| tree | 7ca17a6655621a11eaa4806e0d9e11b011803dc5 /source/slang/compiler.cpp | |
| parent | 29fb1d781a763a8ca3369d03a75dbe1976571368 (diff) | |
Add a `-o` option to command-line `slangc`
Fixes #11
- This adds a `-o` command-line option for specifying an output file.
- The code tries to be a bit smart, to glean an output format from a file extension, and also to associate multiple `-o` options with multiple `-entry` options if needed.
- There is a restriction that all the output files need to agree on the code generation target. This is reasonable for now, but might be something to lift eventualy
- There is a restriction that only one output file is allowed per entry point
- Together with the previous item this means you can't output both a `.spv` and a `.spv.asm` in one pass, even though both should be possible
- There is currently a restriction that output paths only apply to entry points
- This means there is no way to output reflection JSON to a file with `-o` (but that is mostly just a debugging feature for now)
- This also means we don't support any "container" formats that can encapsulate multiple compiled entry points
Diffstat (limited to 'source/slang/compiler.cpp')
| -rw-r--r-- | source/slang/compiler.cpp | 209 |
1 files changed, 203 insertions, 6 deletions
diff --git a/source/slang/compiler.cpp b/source/slang/compiler.cpp index 81f107bd8..6bb8abe7e 100644 --- a/source/slang/compiler.cpp +++ b/source/slang/compiler.cpp @@ -26,6 +26,9 @@ #include <d3dcompiler.h> #endif +#include <io.h> +#include <fcntl.h> + #ifdef _MSC_VER #pragma warning(disable: 4996) #endif @@ -318,7 +321,7 @@ namespace Slang if (codeBlob) { char const* codeBegin = (char const*)codeBlob->GetBufferPointer(); - char const* codeEnd = codeBegin + codeBlob->GetBufferSize(); + char const* codeEnd = codeBegin + codeBlob->GetBufferSize() - 1; result.append(codeBegin, codeEnd); codeBlob->Release(); } @@ -592,6 +595,183 @@ namespace Slang return result; } + enum class OutputFileKind + { + Text, + Binary, + }; + + static void writeOutputFile( + CompileRequest* compileRequest, + FILE* file, + String const& path, + void const* data, + size_t size) + { + size_t count = fwrite(data, size, 1, file); + if (count != 1) + { + compileRequest->mSink.diagnose( + CodePosition(), + Diagnostics::cannotWriteOutputFile, + path); + } + } + + static void writeOutputFile( + CompileRequest* compileRequest, + String const& path, + void const* data, + size_t size, + OutputFileKind kind) + { + FILE* file = fopen( + path.Buffer(), + kind == OutputFileKind::Binary ? "wb" : "w"); + if (!file) + { + compileRequest->mSink.diagnose( + CodePosition(), + Diagnostics::cannotWriteOutputFile, + path); + return; + } + + writeOutputFile(compileRequest, file, path, data, size); + fclose(file); + } + + static void writeEntryPointResultToFile( + EntryPointRequest* entryPoint) + { + auto compileRequest = entryPoint->compileRequest; + auto outputPath = entryPoint->outputPath; + auto result = entryPoint->result; + switch (result.format) + { + case ResultFormat::Text: + { + auto text = result.outputString; + writeOutputFile(compileRequest, + outputPath, + text.begin(), + text.end() - text.begin(), + OutputFileKind::Text); + } + break; + + case ResultFormat::Binary: + { + auto& data = result.outputBinary; + writeOutputFile(compileRequest, + outputPath, + data.begin(), + data.end() - data.begin(), + OutputFileKind::Binary); + } + break; + + default: + SLANG_UNEXPECTED("unhandled output format"); + break; + } + + } + + static void writeOutputToConsole( + CompileRequest*, + String const& text) + { + fwrite( + text.begin(), + text.end() - text.begin(), + 1, + stdout); + } + + static void writeEntryPointResultToStandardOutput( + EntryPointRequest* entryPoint) + { + auto compileRequest = entryPoint->compileRequest; + auto result = entryPoint->result; + + switch (result.format) + { + case ResultFormat::Text: + writeOutputToConsole(compileRequest, result.outputString); + break; + + case ResultFormat::Binary: + { + auto& data = result.outputBinary; + int stdoutFileDesc = _fileno(stdout); + if (_isatty(stdoutFileDesc)) + { + // Writing to console, so we need to generate text output. + + switch (compileRequest->Target) + { + case CodeGenTarget::DXBytecode: + { + String assembly = dissassembleDXBC(compileRequest, + data.begin(), + data.end() - data.begin()); + writeOutputToConsole(compileRequest, assembly); + } + break; + + case CodeGenTarget::SPIRV: + { + String assembly = dissassembleSPIRV(compileRequest, + data.begin(), + data.end() - data.begin()); + writeOutputToConsole(compileRequest, assembly); + } + break; + + default: + SLANG_UNEXPECTED("unhandled output format"); + return; + } + } + else + { + // Redirecting stdout to a file, so do the usual thing + _setmode(stdoutFileDesc, _O_BINARY); + writeOutputFile( + compileRequest, + stdout, + "stdout", + data.begin(), + data.end() - data.begin()); + } + } + break; + + default: + SLANG_UNEXPECTED("unhandled output format"); + break; + } + + } + + static void writeEntryPointResult( + EntryPointRequest* entryPoint) + { + // Skip the case with no output + if (entryPoint->result.format == ResultFormat::None) + return; + + if (entryPoint->outputPath.Length()) + { + writeEntryPointResultToFile(entryPoint); + } + else + { + writeEntryPointResultToStandardOutput(entryPoint); + } + } + CompileResult emitTranslationUnitEntryPoints( TranslationUnitRequest* translationUnit) { @@ -645,6 +825,7 @@ namespace Slang // Allow for an "extra" target to verride things before we finish. + String extraResult; switch (compileRequest->extraTarget) { case CodeGenTarget::ReflectionJSON: @@ -661,11 +842,7 @@ namespace Slang entryPoint->result = CompileResult(); } - // HACK(tfoley): just print it out since that is what people probably expect. - // TODO: need a way to control where output gets routed across all possible targets. - fprintf(stdout, "%s", reflectionJSON.begin()); - - return; + extraResult = reflectionJSON; } break; @@ -673,6 +850,26 @@ namespace Slang break; } + // If we are in command-line mode, we might be expected to actually + // write output to one or more files here. + + if (compileRequest->isCommandLineCompile) + { + switch (compileRequest->extraTarget) + { + case CodeGenTarget::ReflectionJSON: + fprintf(stdout, "%s", extraResult.begin()); + break; + + default: + for( auto entryPoint : compileRequest->entryPoints ) + { + writeEntryPointResult(entryPoint); + } + break; + } + } + } // Debug logic for dumping intermediate outputs |
