summaryrefslogtreecommitdiffstats
path: root/source/slang/compiler.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-07-25 16:21:23 -0700
committerTim Foley <tfoley@nvidia.com>2017-07-25 16:21:23 -0700
commit941b834f3ba15eba9bfa80eb370077ec9c845efd (patch)
tree7ca17a6655621a11eaa4806e0d9e11b011803dc5 /source/slang/compiler.cpp
parent29fb1d781a763a8ca3369d03a75dbe1976571368 (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.cpp209
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