diff --git a/StandAlone/DirStackFileIncluder.h b/StandAlone/DirStackFileIncluder.h index 18734130..5a33c78f 100644 --- a/StandAlone/DirStackFileIncluder.h +++ b/StandAlone/DirStackFileIncluder.h @@ -40,6 +40,7 @@ #include #include #include +#include #include "./../glslang/Public/ShaderLang.h" @@ -84,12 +85,18 @@ public: } } + virtual std::set getIncludedFiles() + { + return includedFiles; + } + virtual ~DirStackFileIncluder() override { } protected: typedef char tUserDataElement; std::vector directoryStack; int externalLocalDirectoryCount; + std::set includedFiles; // Search for a valid "local" path based on combining the stack of include // directories and the nominal name of the header. @@ -108,6 +115,7 @@ protected: std::ifstream file(path, std::ios_base::binary | std::ios_base::ate); if (file) { directoryStack.push_back(getDirectory(path)); + includedFiles.insert(path); return newIncludeResult(path, file, (int)file.tellg()); } } diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp index 923ded30..f76fc05d 100644 --- a/StandAlone/StandAlone.cpp +++ b/StandAlone/StandAlone.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include "../glslang/OSDependent/osinclude.h" @@ -165,6 +166,7 @@ int ReflectOptions = EShReflectionDefault; int Options = 0; const char* ExecutableName = nullptr; const char* binaryFileName = nullptr; +const char* depencyFileName = nullptr; const char* entryPointName = nullptr; const char* sourceEntryPointName = nullptr; const char* shaderStageName = nullptr; @@ -798,6 +800,11 @@ void ProcessArguments(std::vector>& workItem break; } else if (lowerword == "quiet") { beQuiet = true; + } else if (lowerword == "depfile") { + if (argc <= 1) + Error("no provided", lowerword.c_str()); + depencyFileName = argv[1]; + bumpArg(); } else if (lowerword == "version") { Options |= EOptionDumpVersions; } else if (lowerword == "help") { @@ -1135,6 +1142,23 @@ struct ShaderCompUnit { } }; +// Writes a depfile similar to gcc -MMD foo.c +bool writeDepFile(std::string depfile, std::vector& binaryFiles, const std::vector& sources) +{ + std::ofstream file(depfile); + if (file.fail()) + return false; + + for (auto it = binaryFiles.begin(); it != binaryFiles.end(); it++) { + file << *it << ":"; + for (auto it = sources.begin(); it != sources.end(); it++) { + file << " " << *it; + } + file << std::endl; + } + return true; +} + // // For linking mode: Will independently parse each compilation unit, but then put them // in the same program and link them together, making at most one linked module per @@ -1151,6 +1175,12 @@ void CompileAndLinkShaderUnits(std::vector compUnits) EShMessages messages = EShMsgDefault; SetMessageOptions(messages); + DirStackFileIncluder includer; + std::for_each(IncludeDirectoryList.rbegin(), IncludeDirectoryList.rend(), [&includer](const std::string& dir) { + includer.pushExternalLocalDirectory(dir); }); + + std::vector sources; + // // Per-shader processing... // @@ -1158,6 +1188,9 @@ void CompileAndLinkShaderUnits(std::vector compUnits) glslang::TProgram& program = *new glslang::TProgram; for (auto it = compUnits.cbegin(); it != compUnits.cend(); ++it) { const auto &compUnit = *it; + for (int i = 0; i < compUnit.count; i++) { + sources.push_back(compUnit.fileNameList[i]); + } glslang::TShader* shader = new glslang::TShader(compUnit.stage); shader->setStringsWithLengthsAndNames(compUnit.text, NULL, compUnit.fileNameList, compUnit.count); if (entryPointName) @@ -1252,9 +1285,6 @@ void CompileAndLinkShaderUnits(std::vector compUnits) const int defaultVersion = Options & EOptionDefaultDesktop ? 110 : 100; - DirStackFileIncluder includer; - std::for_each(IncludeDirectoryList.rbegin(), IncludeDirectoryList.rend(), [&includer](const std::string& dir) { - includer.pushExternalLocalDirectory(dir); }); #ifndef GLSLANG_WEB if (Options & EOptionOutputPreprocessed) { std::string str; @@ -1314,6 +1344,8 @@ void CompileAndLinkShaderUnits(std::vector compUnits) } #endif + std::vector outputFiles; + // Dump SPIR-V if (Options & EOptionSpv) { if (CompileFailed || LinkFailed) @@ -1343,6 +1375,8 @@ void CompileAndLinkShaderUnits(std::vector compUnits) } else { glslang::OutputSpvBin(spirv, GetBinaryName((EShLanguage)stage)); } + + outputFiles.push_back(GetBinaryName((EShLanguage)stage)); #ifndef GLSLANG_WEB if (!SpvToolsDisassembler && (Options & EOptionHumanReadableSpv)) spv::Disassemble(std::cout, spirv); @@ -1353,6 +1387,13 @@ void CompileAndLinkShaderUnits(std::vector compUnits) } } + if (depencyFileName && !(CompileFailed || LinkFailed)) { + std::set includedFiles = includer.getIncludedFiles(); + sources.insert(sources.end(), includedFiles.begin(), includedFiles.end()); + + writeDepFile(depencyFileName, outputFiles, sources); + } + // Free everything up, program has to go before the shaders // because it might have merged stuff from the shaders, and // the stuff from the shaders has to have its destructors called @@ -1773,6 +1814,7 @@ void usage() " --auto-map-locations | --aml automatically locate input/output lacking\n" " 'location' (fragile, not cross stage)\n" " --client {vulkan|opengl} see -V and -G\n" + " --depfile writes depfile for build systems\n" " --dump-builtin-symbols prints builtin symbol table prior each compile\n" " -dumpfullversion | -dumpversion print bare major.minor.patchlevel\n" " --flatten-uniform-arrays | --fua flatten uniform texture/sampler arrays to\n"