diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2018-07-06 11:51:19 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-07-06 11:51:19 -0400 |
| commit | 7b2a549fcf04263e07127315d72c8570e8063828 (patch) | |
| tree | 8dd94dc20d8537f1c8406f5a9e561c9a68d599db | |
| parent | 338a7701b37fe133eba2f72455ba7c1790a8a1f5 (diff) | |
spCompile/spProcessCommandLineArguments return SlangResult (#610)
* * Make spCompile return SlangResult
* Make spProcessCommandLineArguments return SlangResult (and not internally exit)
* Remove calls to exit()
* Fix typos
* Make all output from spProcessCommandLineArguments get sent to diagnostic sink.
| -rw-r--r-- | examples/hello/hello.cpp | 68 | ||||
| -rw-r--r-- | slang.h | 44 | ||||
| -rw-r--r-- | source/slang/compiler.h | 4 | ||||
| -rw-r--r-- | source/slang/diagnostic-defs.h | 29 | ||||
| -rw-r--r-- | source/slang/options.cpp | 213 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 49 | ||||
| -rw-r--r-- | source/slangc/main.cpp | 43 | ||||
| -rw-r--r-- | tools/render-test/slang-support.cpp | 20 | ||||
| -rw-r--r-- | tools/slang-eval-test/main.cpp | 20 | ||||
| -rw-r--r-- | tools/slang-reflection-test/main.cpp | 42 |
10 files changed, 297 insertions, 235 deletions
diff --git a/examples/hello/hello.cpp b/examples/hello/hello.cpp index a5d90a3f4..8f2fbca0b 100644 --- a/examples/hello/hello.cpp +++ b/examples/hello/hello.cpp @@ -85,28 +85,28 @@ ShaderProgram* loadShaderProgram(Renderer* renderer) // translation unit in which that function can be found, and the stage // that we need to compile for (e.g., vertex, fragment, geometry, ...). // - char const* vertexEntryPointName = "vertexMain"; - char const* fragmentEntryPointName = "fragmentMain"; - int vertexIndex = spAddEntryPoint(slangRequest, translationUnitIndex, vertexEntryPointName, SLANG_STAGE_VERTEX); + char const* vertexEntryPointName = "vertexMain"; + char const* fragmentEntryPointName = "fragmentMain"; + int vertexIndex = spAddEntryPoint(slangRequest, translationUnitIndex, vertexEntryPointName, SLANG_STAGE_VERTEX); int fragmentIndex = spAddEntryPoint(slangRequest, translationUnitIndex, fragmentEntryPointName, SLANG_STAGE_FRAGMENT); - // Once all of the input options for hte compiler have been specified, + // Once all of the input options for the compiler have been specified, // we can invoke `spCompile` to run the compiler and see if any errors // were detected. // - int compileErr = spCompile(slangRequest); + const SlangResult compileRes = spCompile(slangRequest); // Even if there were no errors that forced compilation to fail, the // compiler may have produced "diagnostic" output such as warnings. // We will go ahead and print that output here. // - if(auto diagnostics = spGetDiagnosticOutput(slangRequest)) + if (auto diagnostics = spGetDiagnosticOutput(slangRequest)) { reportError("%s", diagnostics); } // If compilation failed, there is no point in continuing any further. - if(compileErr) + if (SLANG_FAILED(compileRes)) { spDestroyCompileRequest(slangRequest); spDestroySession(slangSession); @@ -128,10 +128,10 @@ ShaderProgram* loadShaderProgram(Renderer* renderer) // We extract the begin/end pointers to the output code buffers // using operations on the `ISlangBlob` interface. - char const* vertexCode = (char const*) vertexShaderBlob->getBufferPointer(); + char const* vertexCode = (char const*)vertexShaderBlob->getBufferPointer(); char const* vertexCodeEnd = vertexCode + vertexShaderBlob->getBufferSize(); - char const* fragmentCode = (char const*) fragmentShaderBlob->getBufferPointer(); + char const* fragmentCode = (char const*)fragmentShaderBlob->getBufferPointer(); char const* fragmentCodeEnd = fragmentCode + fragmentShaderBlob->getBufferSize(); // Once we have extract the output blobs, it is safe to destroy @@ -148,8 +148,8 @@ ShaderProgram* loadShaderProgram(Renderer* renderer) ShaderProgram::KernelDesc kernelDescs[] = { - { StageType::Vertex, vertexCode, vertexCodeEnd}, - { StageType::Fragment, fragmentCode, fragmentCodeEnd}, + { StageType::Vertex, vertexCode, vertexCodeEnd }, + { StageType::Fragment, fragmentCode, fragmentCodeEnd }, }; ShaderProgram::Desc programDesc; @@ -196,9 +196,9 @@ struct Vertex static const int kVertexCount = 3; static const Vertex kVertexData[kVertexCount] = { - { { 0, 0, 0.5 }, {1, 0, 0} }, - { { 0, 1, 0.5 }, {0, 0, 1} }, - { { 1, 0, 0.5 }, {0, 1, 0} }, + { { 0, 0, 0.5 },{ 1, 0, 0 } }, + { { 0, 1, 0.5 },{ 0, 0, 1 } }, + { { 1, 0, 0.5 },{ 0, 1, 0 } }, }; // We will define global variables for the various platform and @@ -217,13 +217,7 @@ BufferResource* gVertexBuffer; ShaderProgram* gShaderProgram; BindingState* gBindingState; -enum -{ - OKAY, - FAILURE, -}; - -int initialize() +SlangResult initialize() { // Create a window for our application to render into. WindowDesc windowDesc; @@ -243,7 +237,10 @@ int initialize() Renderer::Desc rendererDesc; rendererDesc.width = gWindowWidth; rendererDesc.height = gWindowHeight; - gRenderer->initialize(rendererDesc, getPlatformWindowHandle(gWindow)); + { + const SlangResult res = gRenderer->initialize(rendererDesc, getPlatformWindowHandle(gWindow)); + if (SLANG_FAILED(res)) return res; + } // Create a constant buffer for passing the model-view-projection matrix. // @@ -261,20 +258,20 @@ int initialize() gConstantBuffer = gRenderer->createBufferResource( Resource::Usage::ConstantBuffer, constantBufferDesc); - if(!gConstantBuffer) return FAILURE; + if (!gConstantBuffer) return SLANG_FAIL; // Input Assembler (IA) // Input Layout InputElementDesc inputElements[] = { - {"POSITION", 0, Format::RGB_Float32, offsetof(Vertex, position) }, - {"COLOR", 0, Format::RGB_Float32, offsetof(Vertex, color) }, + { "POSITION", 0, Format::RGB_Float32, offsetof(Vertex, position) }, + { "COLOR", 0, Format::RGB_Float32, offsetof(Vertex, color) }, }; gInputLayout = gRenderer->createInputLayout( &inputElements[0], 2); - if(!gInputLayout) return FAILURE; + if (!gInputLayout) return SLANG_FAIL; // Vertex Buffer @@ -286,12 +283,12 @@ int initialize() Resource::Usage::VertexBuffer, vertexBufferDesc, &kVertexData[0]); - if(!gVertexBuffer) return FAILURE; + if (!gVertexBuffer) return SLANG_FAIL; // Shaders (VS, PS, ...) gShaderProgram = loadShaderProgram(gRenderer); - if(!gShaderProgram) return FAILURE; + if (!gShaderProgram) return SLANG_FAIL; // Resource binding state @@ -304,7 +301,7 @@ int initialize() showWindow(gWindow); - return OKAY; + return SLANG_OK; } void renderFrame() @@ -315,15 +312,14 @@ void renderFrame() gRenderer->setClearColor(kClearColor); gRenderer->clearFrame(); - // We update our constant buffer per-frame, just for the purposes // of the example, but we don't actually load different data // per-frame (we always use an identity projection). // - if(float* data = (float*) gRenderer->map(gConstantBuffer, MapFlavor::WriteDiscard)) + if (float* data = (float*)gRenderer->map(gConstantBuffer, MapFlavor::WriteDiscard)) { - static const float kIdentity[] = - { 1, 0, 0, 0, + static const float kIdentity[] = { + 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; @@ -365,12 +361,12 @@ void finalize() // void innerMain(ApplicationContext* context) { - if(initialize() != OKAY) + if (SLANG_FAILED(initialize())) { - exitApplication(context, 1); + return exitApplication(context, 1); } - while(dispatchEvents(context)) + while (dispatchEvents(context)) { renderFrame(); } @@ -418,7 +418,7 @@ extern "C" SLANG_COMPILE_FLAG_NO_CODEGEN = 1 << 4, /* Deprecated flags: kept around to allow existing applications to - compmile. Note that the relevant features will still be left in + compile. Note that the relevant features will still be left in their default state. */ SLANG_COMPILE_FLAG_NO_CHECKING = 0, SLANG_COMPILE_FLAG_SPLIT_MIXED_TYPES = 0, @@ -534,7 +534,10 @@ extern "C" /*! Facilities numbers must be unique across a project to make the resulting result a unique number. It can be useful to have a consistent short name for a facility, as used in the name prefix */ -#define SLANG_FACILITY_CORE SLANG_FACILITY_BASE +#define SLANG_FACILITY_CORE SLANG_FACILITY_BASE + /* Facility for codes, that are not uniquely defined/protected. Can be used to pass back a specific error without requiring system wide facility uniqueness. Codes + should never be part of a public API. */ +#define SLANG_FACILITY_INTERNAL SLANG_FACILITY_BASE + 1 /// Base for external facilities. Facilities should be unique across modules. #define SLANG_FACILITY_EXTERNAL_BASE 0x210 @@ -635,7 +638,7 @@ extern "C" /** A (real or virtual) file system. Slang can make use of this interface whenever it would otherwise try to load files - from disk, allowing applications to hook and/or overide filesystem access from + from disk, allowing applications to hook and/or override filesystem access from the compiler. */ struct ISlangFileSystem : public ISlangUnknown @@ -643,7 +646,7 @@ extern "C" public: /** Load a file from `path` and return a blob of its contents - @param path The path to load from, as a nul-terminated UTF-8 string. + @param path The path to load from, as a null-terminated UTF-8 string. @param outBlob A destination pointer to receive the blob of the file contents. @returns A `SlangResult` to indicate success or failure in loading the file. @@ -664,7 +667,7 @@ extern "C" typedef struct SlangSession SlangSession; /*! - @bref A request for one or more compilation actions to be performed. + @brief A request for one or more compilation actions to be performed. */ typedef struct SlangCompileRequest SlangCompileRequest; @@ -731,7 +734,7 @@ extern "C" int enable); /*! - @brief Set whether (and how) `#line` directives hsould be output. + @brief Set whether (and how) `#line` directives should be output. */ SLANG_API void spSetLineDirectiveMode( SlangCompileRequest* request, @@ -739,15 +742,15 @@ extern "C" /*! @brief Sets the target for code generation. - @param ctx The compilation context. + @param request The compilation context. @param target The code generation target. Possible values are: - SLANG_GLSL. Generates GLSL code. - SLANG_HLSL. Generates HLSL code. - SLANG_SPIRV. Generates SPIR-V code. - */ + */ SLANG_API void spSetCodeGenTarget( SlangCompileRequest* request, - int target); + SlangCompileTarget target); /*! @brief Add a code-generation target to be used. @@ -813,8 +816,9 @@ extern "C" /*! @brief Set options using arguments as if specified via command line. + @return Returns SlangResult. On success SLANG_SUCCEEDED(result) is true. */ - SLANG_API int spProcessCommandLineArguments( + SLANG_API SlangResult spProcessCommandLineArguments( SlangCompileRequest* request, char const* const* args, int argCount); @@ -860,10 +864,10 @@ extern "C" /** Add a source string to the given translation unit. - @param request The comile request that owns the translation unit. + @param request The compile request that owns the translation unit. @param translationUnitIndex The index of the translation unit to add source to. @param path The file-system path that should be assumed for the source code. - @param source A nul-terminated UTF-8 encoded string of source code. + @param source A null-terminated UTF-8 encoded string of source code. The implementation will make a copy of the source code data. An application may free the buffer immediately after this call returns. @@ -881,7 +885,7 @@ extern "C" /** Add a source string to the given translation unit. - @param request The comile request that owns the translation unit. + @param request The compile request that owns the translation unit. @param translationUnitIndex The index of the translation unit to add source to. @param path The file-system path that should be assumed for the source code. @param sourceBegin A pointer to a buffer of UTF-8 encoded source code. @@ -903,7 +907,7 @@ extern "C" /** Add a blob of source code to the given translation unit. - @param request The comile request that owns the translation unit. + @param request The compile request that owns the translation unit. @param translationUnitIndex The index of the translation unit to add source to. @param path The file-system path that should be assumed for the source code. @param sourceBlob A blob containing UTF-8 encoded source code. @@ -951,18 +955,18 @@ extern "C" /** Execute the compilation request. - Returns zero on success, non-zero on failure. + @returns SlangResult, SLANG_OK on success. Use SLANG_SUCCEEDED() and SLANG_FAILED() to test SlangResult. */ - SLANG_API int spCompile( + SLANG_API SlangResult spCompile( SlangCompileRequest* request); /** Get any diagnostic messages reported by the compiler. - @returns A nul-terminated UTF-8 encoded string of diagnostic messages. + @returns A null-terminated UTF-8 encoded string of diagnostic messages. The returned pointer is only guaranteed to be valid - until `reqeust` is destroyed. Applications that wish to + until `request` is destroyed. Applications that wish to hold on to the diagnostic output for longer should use `spGetDiagnosticOutputBlob`. */ @@ -990,14 +994,14 @@ extern "C" spGetDependencyFileCount( SlangCompileRequest* request); - /** Get the path to a file this compilation dependend on. + /** Get the path to a file this compilation depended on. */ SLANG_API char const* spGetDependencyFilePath( SlangCompileRequest* request, int index); - /** Get the number of tranlsation units associated with the compilation request + /** Get the number of translation units associated with the compilation request */ SLANG_API int spGetTranslationUnitCount( diff --git a/source/slang/compiler.h b/source/slang/compiler.h index 398c7ac62..c6a114d7d 100644 --- a/source/slang/compiler.h +++ b/source/slang/compiler.h @@ -416,8 +416,8 @@ namespace Slang void generateIR(); - int executeActionsInner(); - int executeActions(); + SlangResult executeActionsInner(); + SlangResult executeActions(); int addTranslationUnit(SourceLanguage language, String const& name); diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h index 8dd2f3b0b..12f9d2169 100644 --- a/source/slang/diagnostic-defs.h +++ b/source/slang/diagnostic-defs.h @@ -52,24 +52,27 @@ DIAGNOSTIC( 2, Error, cannotFindFile, "cannot find file '$0'.") DIAGNOSTIC( 2, Error, unsupportedCompilerMode, "unsupported compiler mode.") DIAGNOSTIC( 4, Error, cannotWriteOutputFile, "cannot write output file '$0'.") DIAGNOSTIC( 5, Error, failedToLoadDynamicLibrary, "failed to load dynamic library '$0'") +DIAGNOSTIC( 6, Error, tooManyOutputPathsSpecified, "$0 output paths specified, but only $1 entry points given") -DIAGNOSTIC( 6, Error, tooManyOutputPathsSpecified, - "$0 output paths specified, but only $1 entry points given") - -DIAGNOSTIC( 6, Error, noOutputPathSpecifiedForEntryPoint, +DIAGNOSTIC( 7, Error, noOutputPathSpecifiedForEntryPoint, "no output path specified for entry point '$0' (the '-o' option for an entry point must precede the corresponding '-entry')") -DIAGNOSTIC( 6, Error, outputPathsImplyDifferentFormats, +DIAGNOSTIC( 8, Error, outputPathsImplyDifferentFormats, "the output paths '$0' and '$1' require different code-generation targets") -DIAGNOSTIC( 6, Error, cannotDeduceOutputFormatFromPath, - "cannot deduce an output format from the output path '$0'") - -DIAGNOSTIC( 6, Error, explicitOutputPathsAndMultipleTargets, - "canot use both explicit output paths ('-o') and multiple targets ('-target')") - -DIAGNOSTIC( 7, Error, glslIsNotSupported, - "the Slang compiler does not support GLSL as a source language"); +DIAGNOSTIC( 9, Error, cannotDeduceOutputFormatFromPath, "cannot deduce an output format from the output path '$0'") +DIAGNOSTIC( 10, Error, explicitOutputPathsAndMultipleTargets, "canot use both explicit output paths ('-o') and multiple targets ('-target')") +DIAGNOSTIC( 11, Error, glslIsNotSupported, "the Slang compiler does not support GLSL as a source language"); +DIAGNOSTIC( 12, Error, cannotDeduceSourceLanguage, "can't deduce language for input file '$0'"); +DIAGNOSTIC( 13, Error, unknownCodeGenerationTarget, "unknown code generation target '$0'"); +DIAGNOSTIC( 14, Error, unknownProfile, "unknown profile '$0'"); +DIAGNOSTIC( 15, Error, unknownStage, "unknown stage '$0'"); +DIAGNOSTIC( 16, Error, unknownPassThroughTarget, "unknown pass-through target '$0'"); +DIAGNOSTIC( 17, Error, unknownCommandLineOption, "unknown command-line option '$0'"); +DIAGNOSTIC( 18, Error, noProfileSpecified, "no profile specified; use the '-profile <profile name>' option"); +DIAGNOSTIC( 19, Error, multipleEntryPointsNeedMulitpleProfiles, "when multiple entry points are specified, each must have a profile given (with '-profile') before the '-entry' option"); +DIAGNOSTIC( 20, Error, multipleTranslationUnitsNeedEntryPoints, "when using multiple translation units, entry points must be specified after their translation unit file(s)"); +DIAGNOSTIC( 21, Error, expectedArgumentForOption, "expected an argument for command-line option '$0'"); // // 1xxxx - Lexical anaylsis diff --git a/source/slang/options.cpp b/source/slang/options.cpp index dbddc0bdd..a067ddf0c 100644 --- a/source/slang/options.cpp +++ b/source/slang/options.cpp @@ -12,29 +12,30 @@ namespace Slang { -char const* tryReadCommandLineArgumentRaw(char const* option, char const* const**ioCursor, char const* const*end) +SlangResult tryReadCommandLineArgumentRaw(DiagnosticSink* sink, char const* option, char const* const**ioCursor, char const* const*end, char const** argOut) { + *argOut = nullptr; char const* const*& cursor = *ioCursor; if (cursor == end) { - fprintf(stderr, "expected an argument for command-line option '%s'", option); - exit(1); + sink->diagnose(SourceLoc(), Diagnostics::expectedArgumentForOption, option); + return SLANG_FAIL; } else { - return *cursor++; + *argOut = *cursor++; + return SLANG_OK; } } -String tryReadCommandLineArgument(char const* option, char const* const**ioCursor, char const* const*end) +SlangResult tryReadCommandLineArgument(DiagnosticSink* sink, char const* option, char const* const**ioCursor, char const* const*end, String& argOut) { - return String(tryReadCommandLineArgumentRaw(option, ioCursor, end)); + const char* arg; + SLANG_RETURN_ON_FAIL(tryReadCommandLineArgumentRaw(sink, option, ioCursor, end, &arg)); + argOut = arg; + return SLANG_OK; } - - - - struct OptionsParser { SlangSession* session = nullptr; @@ -144,7 +145,58 @@ struct OptionsParser path.begin()); } - void addInputPath( + static Profile::RawVal findGlslProfileFromPath(const String& path) + { + struct Entry + { + const char* ext; + Profile::RawVal profileId; + }; + + static const Entry entries[] = + { + { ".frag", Profile::GLSL_Fragment }, + { ".geom", Profile::GLSL_Geometry }, + { ".tesc", Profile::GLSL_TessControl }, + { ".tese", Profile::GLSL_TessEval }, + { ".comp", Profile::GLSL_Compute } + }; + + for (int i = 0; i < SLANG_COUNT_OF(entries); ++i) + { + const Entry& entry = entries[i]; + if (path.EndsWith(entry.ext)) + { + return entry.profileId; + } + } + return Profile::Unknown; + } + + static SlangSourceLanguage findSourceLanguageFromPath(const String& path, SlangProfileID* profileOut) + { + *profileOut = SLANG_PROFILE_UNKNOWN; + + if (path.EndsWith(".hlsl") || + path.EndsWith(".fx")) + { + return SLANG_SOURCE_LANGUAGE_HLSL; + } + if (path.EndsWith(".glsl")) + { + return SLANG_SOURCE_LANGUAGE_GLSL; + } + + Profile::RawVal profile = findGlslProfileFromPath(path); + if (profile != Profile::Unknown) + { + *profileOut = SlangProfileID(profile); + return SLANG_SOURCE_LANGUAGE_GLSL; + } + return SLANG_SOURCE_LANGUAGE_UNKNOWN; + } + + SlangResult addInputPath( char const* inPath) { inputPathCount++; @@ -157,33 +209,21 @@ struct OptionsParser { // Plain old slang code addInputSlangPath(path); + return SLANG_OK; } -#define CASE(EXT, LANG) \ - else if(path.EndsWith(EXT)) do { addInputForeignShaderPath(path, SLANG_SOURCE_LANGUAGE_##LANG); } while(0) - - CASE(".hlsl", HLSL); - CASE(".fx", HLSL); - - CASE(".glsl", GLSL); -#undef CASE - -#define CASE(EXT, LANG, PROFILE) \ - else if(path.EndsWith(EXT)) do { addInputForeignShaderPath(path, SLANG_SOURCE_LANGUAGE_##LANG, SlangProfileID(Slang::Profile::PROFILE)); } while(0) - // TODO: need a way to pass along stage/profile and entry-point info for these cases... - CASE(".vert", GLSL, GLSL_Vertex); - CASE(".frag", GLSL, GLSL_Fragment); - CASE(".geom", GLSL, GLSL_Geometry); - CASE(".tesc", GLSL, GLSL_TessControl); - CASE(".tese", GLSL, GLSL_TessEval); - CASE(".comp", GLSL, GLSL_Compute); - -#undef CASE - - else + + SlangProfileID profileID; + SlangSourceLanguage sourceLanguage = findSourceLanguageFromPath(path, &profileID); + + if (sourceLanguage == SLANG_SOURCE_LANGUAGE_UNKNOWN) { - fprintf(stderr, "error: can't deduce language for input file '%s'\n", inPath); - exit(1); + requestImpl->mSink.diagnose(SourceLoc(), Diagnostics::cannotDeduceSourceLanguage, inPath); + return SLANG_FAIL; } + + addInputForeignShaderPath(path, sourceLanguage, profileID); + + return SLANG_OK; } void addOutputPath( @@ -237,7 +277,7 @@ struct OptionsParser } } - int parse( + SlangResult parse( int argc, char const* const* argv) { @@ -245,7 +285,7 @@ struct OptionsParser // after some other initialization has been performed. flags = requestImpl->compileFlags; - // + DiagnosticSink* sink = &requestImpl->mSink; SlangMatrixLayoutMode defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_MODE_UNKNOWN; @@ -292,7 +332,9 @@ struct OptionsParser } else if (argStr == "-backend" || argStr == "-target") { - String name = tryReadCommandLineArgument(arg, &argCursor, argEnd); + String name; + SLANG_RETURN_ON_FAIL(tryReadCommandLineArgument(sink, arg, &argCursor, argEnd, name)); + SlangCompileTarget target = SLANG_TARGET_UNKNOWN; if (name == "glsl") @@ -336,8 +378,8 @@ struct OptionsParser else { - fprintf(stderr, "unknown code generation target '%S'\n", name.ToWString().begin()); - exit(1); + sink->diagnose(SourceLoc(), Diagnostics::unknownCodeGenerationTarget, name); + return SLANG_FAIL; } this->chosenTarget = target; @@ -347,12 +389,14 @@ struct OptionsParser // of capability required by the program. else if (argStr == "-profile") { - String name = tryReadCommandLineArgument(arg, &argCursor, argEnd); + String name; + SLANG_RETURN_ON_FAIL(tryReadCommandLineArgument(sink, arg, &argCursor, argEnd, name)); SlangProfileID profileID = spFindProfile(session, name.begin()); if( profileID == SLANG_PROFILE_UNKNOWN ) { - fprintf(stderr, "unknown profile '%s'\n", name.begin()); + sink->diagnose(SourceLoc(), Diagnostics::unknownProfile, name); + return SLANG_FAIL; } else { @@ -362,7 +406,8 @@ struct OptionsParser } else if (argStr == "-entry") { - String name = tryReadCommandLineArgument(arg, &argCursor, argEnd); + String name; + SLANG_RETURN_ON_FAIL(tryReadCommandLineArgument(sink, arg, &argCursor, argEnd, name)); RawEntryPoint entry; entry.name = name; @@ -384,7 +429,9 @@ struct OptionsParser #if 0 else if (argStr == "-stage") { - String name = tryReadCommandLineArgument(arg, &argCursor, argEnd); + String name; + SLANG_RETURN_ON_FAIL(tryReadCommandLineArgument(sink, arg, &argCursor, argEnd, name)); + StageTarget stage = StageTarget::Unknown; if (name == "vertex") { stage = StageTarget::VertexShader; } else if (name == "fragment") { stage = StageTarget::FragmentShader; } @@ -393,22 +440,25 @@ struct OptionsParser else if (name == "compute") { stage = StageTarget::ComputeShader; } else { - fprintf(stderr, "unknown stage '%S'\n", name.ToWString()); + sink->diagnose(SourceLoc(), Diagnostics::unknownStage, name); + return SLANG_FAIL; } options.stage = stage; } #endif else if (argStr == "-pass-through") { - String name = tryReadCommandLineArgument(arg, &argCursor, argEnd); + String name; + SLANG_RETURN_ON_FAIL(tryReadCommandLineArgument(sink, arg, &argCursor, argEnd, name)); + SlangPassThrough passThrough = SLANG_PASS_THROUGH_NONE; if (name == "fxc") { passThrough = SLANG_PASS_THROUGH_FXC; } else if (name == "dxc") { passThrough = SLANG_PASS_THROUGH_DXC; } else if (name == "glslang") { passThrough = SLANG_PASS_THROUGH_GLSLANG; } else { - fprintf(stderr, "unknown pass-through target '%S'\n", name.ToWString().begin()); - exit(1); + sink->diagnose(SourceLoc(), Diagnostics::unknownPassThroughTarget, name); + return SLANG_FAIL; } spSetPassThrough( @@ -427,7 +477,7 @@ struct OptionsParser if (defineStr[0] == 0) { // Need to read another argument from the command line - defineStr = tryReadCommandLineArgumentRaw(arg, &argCursor, argEnd); + SLANG_RETURN_ON_FAIL(tryReadCommandLineArgumentRaw(sink, arg, &argCursor, argEnd, &defineStr)); } // The string that sets up the define can have an `=` between // the name to be defined and its value, so we search for one. @@ -473,7 +523,7 @@ struct OptionsParser if (includeDirStr[0] == 0) { // Need to read another argument from the command line - includeDirStr = tryReadCommandLineArgumentRaw(arg, &argCursor, argEnd); + SLANG_RETURN_ON_FAIL(tryReadCommandLineArgumentRaw(sink, arg, &argCursor, argEnd, &includeDirStr)); } spAddSearchPath( @@ -484,8 +534,8 @@ struct OptionsParser // A `-o` option is used to specify a desired output file. else if (argStr == "-o") { - char const* outputPath = tryReadCommandLineArgumentRaw( - arg, &argCursor, argEnd); + char const* outputPath = nullptr; + SLANG_RETURN_ON_FAIL(tryReadCommandLineArgumentRaw(sink, arg, &argCursor, argEnd, &outputPath)); if (!outputPath) continue; addOutputPath(outputPath); @@ -504,20 +554,20 @@ struct OptionsParser // and treat the rest of the command line as input file names: while (argCursor != argEnd) { - addInputPath(*argCursor++); + SLANG_RETURN_ON_FAIL(addInputPath(*argCursor++)); } break; } else { - fprintf(stderr, "unknown command-line option '%S'\n", argStr.ToWString().begin()); + sink->diagnose(SourceLoc(), Diagnostics::unknownCommandLineOption, argStr); // TODO: print a usage message - exit(1); + return SLANG_FAIL; } } else { - addInputPath(arg); + SLANG_RETURN_ON_FAIL(addInputPath(arg)); } } @@ -529,14 +579,14 @@ struct OptionsParser if (inputPathCount == 0) { fprintf(stderr, "error: no input file specified\n"); - exit(1); + return SLANG_E_INVALID_ARG; } // No point in moving forward if there is nothing to compile if( translationUnitCount == 0 ) { fprintf(stderr, "error: no compilation requested\n"); - exit(1); + return SLANG_FAIL; } #endif @@ -598,8 +648,8 @@ struct OptionsParser if( anyEntryPointWithoutProfile && currentProfileID == SLANG_PROFILE_UNKNOWN) { - fprintf(stderr, "error: no profile specified; use the '-profile <profile name>' option\n"); - exit(1); + sink->diagnose(SourceLoc(), Diagnostics::noProfileSpecified); + return SLANG_E_INVALID_ARG; } // Issue an error if we have mulitple `-profile` options *and* // there were entry points that didn't get a profile, *and* @@ -609,8 +659,8 @@ struct OptionsParser { if (rawEntryPoints.Count() > 1) { - fprintf(stderr, "error: when multiple entry points are specified, each must have a profile given (with '-profile') before the '-entry' option\n"); - exit(1); + sink->diagnose(SourceLoc(), Diagnostics::multipleEntryPointsNeedMulitpleProfiles); + return SLANG_E_INVALID_ARG; } } // TODO: need to issue an error on a `-profile` option that doesn't actually @@ -631,12 +681,9 @@ struct OptionsParser // for direct output files for entry points, that is an error. if (rawOutputPaths.Count() != 0 && requestImpl->targets.Count() > 1) { - requestImpl->mSink.diagnose( - SourceLoc(), - Diagnostics::explicitOutputPathsAndMultipleTargets); + sink->diagnose(SourceLoc(), Diagnostics::explicitOutputPathsAndMultipleTargets); } - // Did the user try to specify output path(s)? if (rawOutputPaths.Count() != 0) { @@ -648,11 +695,8 @@ struct OptionsParser } else if (rawOutputPaths.Count() > rawEntryPoints.Count()) { - requestImpl->mSink.diagnose( - SourceLoc(), - Diagnostics::tooManyOutputPathsSpecified, - rawOutputPaths.Count(), - rawEntryPoints.Count()); + sink->diagnose(SourceLoc(), Diagnostics::tooManyOutputPathsSpecified, + rawOutputPaths.Count(), rawEntryPoints.Count()); } else { @@ -663,10 +707,7 @@ struct OptionsParser { if (entryPoint.outputPathIndex < 0) { - requestImpl->mSink.diagnose( - SourceLoc(), - Diagnostics::noOutputPathSpecifiedForEntryPoint, - entryPoint.name); + sink->diagnose(SourceLoc(), Diagnostics::noOutputPathSpecifiedForEntryPoint, entryPoint.name); // Don't emit this same error for other entry // points, even if we have more @@ -691,10 +732,7 @@ struct OptionsParser { // This file didn't imply a target, and that // needs to be an error: - requestImpl->mSink.diagnose( - SourceLoc(), - Diagnostics::cannotDeduceOutputFormatFromPath, - rawOutputPath.path); + sink->diagnose(SourceLoc(), Diagnostics::cannotDeduceOutputFormatFromPath, rawOutputPath.path); // Don't keep looking for errors anyUnknownTargets = true; @@ -721,7 +759,7 @@ struct OptionsParser { // This file didn't imply a target, and that // needs to be an error: - requestImpl->mSink.diagnose( + sink->diagnose( SourceLoc(), Diagnostics::outputPathsImplyDifferentFormats, rawOutputPaths[0].path, @@ -748,7 +786,7 @@ struct OptionsParser } } - // If the user specifed and per-compilation-target flags, make sure + // If the user specified and per-compilation-target flags, make sure // to apply them here. if(targetFlags) { @@ -780,8 +818,8 @@ struct OptionsParser if( anyEntryPointWithoutTranslationUnit && translationUnitCount != 1 ) { - fprintf(stderr, "error: when using multiple translation units, entry points must be specified after their translation unit file(s)\n"); - exit(1); + sink->diagnose(SourceLoc(), Diagnostics::multipleTranslationUnitsNeedEntryPoints); + return SLANG_FAIL; } // Now place all those entry points where they belong @@ -815,15 +853,12 @@ struct OptionsParser } #endif - if (requestImpl->mSink.GetErrorCount() != 0) - return 1; - - return 0; + return (sink->GetErrorCount() == 0) ? SLANG_OK : SLANG_FAIL; } }; -int parseOptions( +SlangResult parseOptions( SlangCompileRequest* compileRequest, int argc, char const* const* argv) @@ -837,7 +872,7 @@ int parseOptions( } // namespace Slang -SLANG_API int spProcessCommandLineArguments( +SLANG_API SlangResult spProcessCommandLineArguments( SlangCompileRequest* request, char const* const* args, int argCount) diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index ced2beb14..2b1857e07 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -462,7 +462,7 @@ static SourceLanguage inferSourceLanguage(CompileRequest* request) return language; } -int CompileRequest::executeActionsInner() +SlangResult CompileRequest::executeActionsInner() { // Do some cleanup on settings specified by user. // In particular, we want to propagate flags from the overall request down to @@ -510,7 +510,7 @@ int CompileRequest::executeActionsInner() case SourceLanguage::GLSL: mSink.diagnose(SourceLoc(), Diagnostics::glslIsNotSupported); - return 1; + return SLANG_FAIL; } } @@ -521,12 +521,12 @@ int CompileRequest::executeActionsInner() parseTranslationUnit(translationUnit.Ptr()); } if (mSink.GetErrorCount() != 0) - return 1; + return SLANG_FAIL; // Perform semantic checking on the whole collection checkAllTranslationUnits(); if (mSink.GetErrorCount() != 0) - return 1; + return SLANG_FAIL; if ((compileFlags & SLANG_COMPILE_FLAG_NO_CODEGEN) == 0) { @@ -536,18 +536,18 @@ int CompileRequest::executeActionsInner() } if (mSink.GetErrorCount() != 0) - return 1; + return SLANG_FAIL; // For each code generation target generate // parameter binding information. - // This step is done globaly, because all translation + // This step is done globally, because all translation // units and entry points need to agree on where // parameters are allocated. for (auto targetReq : targets) { generateParameterBindings(targetReq); if (mSink.GetErrorCount() != 0) - return 1; + return SLANG_FAIL; } } @@ -555,24 +555,22 @@ int CompileRequest::executeActionsInner() // Note: this is a debugging option. if (shouldSkipCodegen || ((compileFlags & SLANG_COMPILE_FLAG_NO_CODEGEN) != 0)) - return 0; + return SLANG_OK; // Generate output code, in whatever format was requested generateOutput(this); if (mSink.GetErrorCount() != 0) - return 1; + return SLANG_FAIL; - return 0; + return SLANG_OK; } // Act as expected of the API-based compiler -int CompileRequest::executeActions() +SlangResult CompileRequest::executeActions() { - int err = executeActionsInner(); - + SlangResult res = executeActionsInner(); mDiagnosticOutput = mSink.outputBuffer.ProduceString(); - - return err; + return res; } int CompileRequest::addTranslationUnit(SourceLanguage language, String const&) @@ -903,8 +901,8 @@ void Session::addBuiltinSource( path, source); - int err = compileRequest->executeActions(); - if (err) + SlangResult res = compileRequest->executeActions(); + if (SLANG_FAILED(res)) { fprintf(stderr, "%s", compileRequest->mDiagnosticOutput.Buffer()); @@ -1063,7 +1061,7 @@ SLANG_API void spSetCommandLineCompilerMode( SLANG_API void spSetCodeGenTarget( SlangCompileRequest* request, - int target) + SlangCompileTarget target) { auto req = REQ(request); req->targets.Clear(); @@ -1330,7 +1328,7 @@ SLANG_API int spAddEntryPointEx( // Compile in a context that already has its translation units specified -SLANG_API int spCompile( +SLANG_API SlangResult spCompile( SlangCompileRequest* request) { auto req = REQ(request); @@ -1345,16 +1343,16 @@ SLANG_API int spCompile( // // TODO: Consider supporting Windows "Structured Exception Handling" // so that we can also recover from a wider class of crashes. - int anyErrors = 1; + SlangResult res = SLANG_FAIL; try { - anyErrors = req->executeActions(); + res = req->executeActions(); } catch (Slang::AbortCompilationException&) { - // This situation indicates a fatal (but not necesarily internal) error + // This situation indicates a fatal (but not necessarily internal) error // that forced compilation to terminate. There should already have been - // a diagnositc produced, so we don't need to add one here. + // a diagnostic produced, so we don't need to add one here. } catch (Slang::Exception& e) { @@ -1373,13 +1371,12 @@ SLANG_API int spCompile( req->mSink.diagnose(Slang::SourceLoc(), Slang::Diagnostics::compilationAborted); } req->mDiagnosticOutput = req->mSink.outputBuffer.ProduceString(); - return anyErrors; + return res; #else // When debugging, we probably don't want to filter out any errors, since // we are probably trying to root-cause and *fix* those errors. { - int anyErrors = req->executeActions(); - return anyErrors; + return req->executeActions(); } #endif } diff --git a/source/slangc/main.cpp b/source/slangc/main.cpp index 376b75212..ba83a9bdf 100644 --- a/source/slangc/main.cpp +++ b/source/slangc/main.cpp @@ -26,7 +26,10 @@ static void diagnosticCallback( #define MAIN main #endif -int MAIN(int argc, char** argv) +// Used to identify that compilation was the failure - with a unique 'internal' code +#define SLANG_E_INTERNAL_COMPILE_FAILED SLANG_MAKE_ERROR(SLANG_FACILITY_INTERNAL, 0x7fab) + +static SlangResult innerMain(int argc, char** argv) { // Parse any command-line options @@ -41,28 +44,28 @@ int MAIN(int argc, char** argv) spSetCommandLineCompilerMode(compileRequest); char const* appName = "slangc"; - if(argc > 0) appName = argv[0]; + if (argc > 0) appName = argv[0]; - int err = spProcessCommandLineArguments(compileRequest, &argv[1], argc - 1); - if( err ) { - // TODO: print usage message - exit(1); + const SlangResult res = spProcessCommandLineArguments(compileRequest, &argv[1], argc - 1); + if (SLANG_FAILED(res)) + { + // TODO: print usage message + return res; + } } - // Invoke the compiler - #ifndef _DEBUG try #endif { // Run the compiler (this will produce any diagnostics through // our callback above). - int result = spCompile(compileRequest); - if( result != 0 ) + if (SLANG_FAILED(spCompile(compileRequest))) { // If the compilation failed, then get out of here... - exit(-1); + // Turn into an internal Result -> such that return code can be used to vary result to match previous behavior + return SLANG_E_INTERNAL_COMPILE_FAILED; } // Now that we are done, clean up after ourselves @@ -74,11 +77,25 @@ int MAIN(int argc, char** argv) catch (Exception & e) { printf("internal compiler error: %S\n", e.Message.ToWString().begin()); - return 1; + return SLANG_FAIL; } #endif + return SLANG_OK; +} - return 0; +int MAIN(int argc, char** argv) +{ + SlangResult res = innerMain(argc, argv); + + if (SLANG_SUCCEEDED(res)) + { + return 0; + } + else if (res == SLANG_E_INTERNAL_COMPILE_FAILED) + { + return -1; + } + return 1; } #ifdef _WIN32 diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp index d69060449..a6c252843 100644 --- a/tools/render-test/slang-support.cpp +++ b/tools/render-test/slang-support.cpp @@ -47,9 +47,9 @@ ShaderProgram* ShaderCompiler::compileProgram( spSetPassThrough(slangRequest, passThrough); } - // Preocess any additional command-line options specified for Slang using + // Process any additional command-line options specified for Slang using // the `-xslang <arg>` option to `render-test`. - spProcessCommandLineArguments(slangRequest, &gOptions.slangArgs[0], gOptions.slangArgCount); + SLANG_RETURN_NULL_ON_FAIL(spProcessCommandLineArguments(slangRequest, &gOptions.slangArgs[0], gOptions.slangArgCount)); int computeTranslationUnit = 0; int vertexTranslationUnit = 0; @@ -92,7 +92,7 @@ ShaderProgram* ShaderCompiler::compileProgram( } - ShaderProgram * result = nullptr; + ShaderProgram * shaderProgram = nullptr; Slang::List<const char*> rawTypeNames; for (auto typeName : request.entryPointTypeArguments) rawTypeNames.Add(typeName.Buffer()); @@ -105,12 +105,12 @@ ShaderProgram* ShaderCompiler::compileProgram( rawTypeNames.Buffer()); spSetLineDirectiveMode(slangRequest, SLANG_LINE_DIRECTIVE_MODE_NONE); - int compileErr = spCompile(slangRequest); + const SlangResult res = spCompile(slangRequest); if (auto diagnostics = spGetDiagnosticOutput(slangRequest)) { fprintf(stderr, "%s", diagnostics); } - if (!compileErr) + if (SLANG_SUCCEEDED(res)) { size_t codeSize = 0; char const* code = (char const*) spGetEntryPointCode(slangRequest, computeEntryPoint, &codeSize); @@ -125,7 +125,7 @@ ShaderProgram* ShaderCompiler::compileProgram( desc.kernels = &kernelDesc; desc.kernelCount = 1; - result = renderer->createProgram(desc); + shaderProgram = renderer->createProgram(desc); } } else @@ -133,14 +133,14 @@ ShaderProgram* ShaderCompiler::compileProgram( int vertexEntryPoint = spAddEntryPointEx(slangRequest, vertexTranslationUnit, vertexEntryPointName, SLANG_STAGE_VERTEX, (int)rawTypeNames.Count(), rawTypeNames.Buffer()); int fragmentEntryPoint = spAddEntryPointEx(slangRequest, fragmentTranslationUnit, fragmentEntryPointName, SLANG_STAGE_FRAGMENT, (int)rawTypeNames.Count(), rawTypeNames.Buffer()); - int compileErr = spCompile(slangRequest); + const SlangResult res = spCompile(slangRequest); if (auto diagnostics = spGetDiagnosticOutput(slangRequest)) { // TODO(tfoley): re-enable when I get a logging solution in place // OutputDebugStringA(diagnostics); fprintf(stderr, "%s", diagnostics); } - if (!compileErr) + if (SLANG_SUCCEEDED(res)) { size_t vertexCodeSize = 0; char const* vertexCode = (char const*) spGetEntryPointCode(slangRequest, vertexEntryPoint, &vertexCodeSize); @@ -165,7 +165,7 @@ ShaderProgram* ShaderCompiler::compileProgram( desc.kernels = &kernelDescs[0]; desc.kernelCount = kDescCount; - result = renderer->createProgram(desc); + shaderProgram = renderer->createProgram(desc); } } // We clean up the Slang compilation context and result *after* @@ -175,7 +175,7 @@ ShaderProgram* ShaderCompiler::compileProgram( spDestroyCompileRequest(slangRequest); spDestroySession(slangSession); - return result; + return shaderProgram; } } // renderer_test diff --git a/tools/slang-eval-test/main.cpp b/tools/slang-eval-test/main.cpp index e01d4441b..ff2ebed34 100644 --- a/tools/slang-eval-test/main.cpp +++ b/tools/slang-eval-test/main.cpp @@ -6,9 +6,7 @@ #include "../../source/core/secure-crt.h" #include <slang.h> -int main( - int argc, - char** argv) +static SlangResult innerMain(int argc, char*const* argv) { // TODO: parse arguments @@ -24,7 +22,7 @@ int main( size_t inputSize = ftell(inputFile); fseek(inputFile, 0, SEEK_SET); - char* inputText = (char*) malloc(inputSize + 1); + char* inputText = (char*)malloc(inputSize + 1); fread(inputText, inputSize, 1, inputFile); inputText[inputSize] = 0; fclose(inputFile); @@ -59,11 +57,11 @@ int main( "main", spFindProfile(session, "cs_5_0")); - if( spCompile(request) != 0 ) + if (SLANG_FAILED(spCompile(request))) { char const* output = spGetDiagnosticOutput(request); fputs(output, stderr); - exit(1); + return SLANG_FAIL; } // Things compiled, so now we need to run them... @@ -129,5 +127,13 @@ int main( spDestroyCompileRequest(request); spDestroySession(session); - return 0; + return SLANG_OK; +} + +int main( + int argc, + char** argv) +{ + SlangResult res = innerMain(argc, argv); + return SLANG_FAILED(res) ? 1 : 0; } diff --git a/tools/slang-reflection-test/main.cpp b/tools/slang-reflection-test/main.cpp index b900f3f62..667a0ddf7 100644 --- a/tools/slang-reflection-test/main.cpp +++ b/tools/slang-reflection-test/main.cpp @@ -6,6 +6,7 @@ #include <string.h> #include <slang.h> +#include <slang-com-helper.h> struct PrettyWriter { @@ -854,10 +855,17 @@ void emitReflectionJSON( emitReflectionJSON(writer, programReflection); } +static SlangResult maybeDumpDiagnostic(SlangResult res, SlangCompileRequest* request) +{ + const char* diagnostic; + if (SLANG_FAILED(res) && (diagnostic = spGetDiagnosticOutput(request))) + { + fputs(diagnostic, stderr); + } + return res; +} -int main( - int argc, - char** argv) +static SlangResult innerMain(int argc, char*const*argv) { // Parse any command-line options @@ -865,22 +873,10 @@ int main( SlangCompileRequest* request = spCreateCompileRequest(session); char const* appName = "slang-reflection-test"; - if(argc > 0) appName = argv[0]; - - int err = spProcessCommandLineArguments(request, &argv[1], argc - 1); - if( err ) - { - char const* output = spGetDiagnosticOutput(request); - fputs(output, stderr); - exit(1); - } + if (argc > 0) appName = argv[0]; - if( spCompile(request) != 0 ) - { - char const* output = spGetDiagnosticOutput(request); - fputs(output, stderr); - exit(1); - } + SLANG_RETURN_ON_FAIL(maybeDumpDiagnostic(spProcessCommandLineArguments(request, &argv[1], argc - 1), request)); + SLANG_RETURN_ON_FAIL(maybeDumpDiagnostic(spCompile(request), request)); // Okay, let's go through and emit reflection info on whatever // we have. @@ -891,5 +887,13 @@ int main( spDestroyCompileRequest(request); spDestroySession(session); - return 0; + return SLANG_OK; +} + +int main( + int argc, + char** argv) +{ + SlangResult res = innerMain(argc, argv); + return SLANG_FAILED(res) ? 1 : 0; } |
