diff --git a/StandAlone/DirStackFileIncluder.h b/StandAlone/DirStackFileIncluder.h index 8f06f9ea..8d6543ab 100644 --- a/StandAlone/DirStackFileIncluder.h +++ b/StandAlone/DirStackFileIncluder.h @@ -48,6 +48,8 @@ // Can be overridden to customize. class DirStackFileIncluder : public glslang::TShader::Includer { public: + DirStackFileIncluder() : externalLocalDirectoryCount(0) { } + virtual IncludeResult* includeLocal(const char* headerName, const char* includerName, size_t inclusionDepth) override @@ -62,6 +64,18 @@ public: return readSystemPath(headerName); } + // Externally set directories. E.g., from a command-line -I. + // - Most-recently pushed are checked first. + // - All these are checked after the parse-time stack of local directories + // is checked. + // - This only applies to the "local" form of #include. + // - Makes its own copy of the path. + virtual void pushExternalLocalDirectory(const std::string& dir) + { + directoryStack.push_back(dir); + externalLocalDirectoryCount = directoryStack.size(); + } + virtual void releaseInclude(IncludeResult* result) override { if (result != nullptr) { @@ -75,17 +89,19 @@ public: protected: typedef char tUserDataElement; std::vector directoryStack; + int externalLocalDirectoryCount; // Search for a valid "local" path based on combining the stack of include // directories and the nominal name of the header. virtual IncludeResult* readLocalPath(const char* headerName, const char* includerName, int depth) { - // Discard popped include directories, and if first level, initialize. - directoryStack.resize(depth); + // Discard popped include directories, and + // initialize when at parse-time first level. + directoryStack.resize(depth + externalLocalDirectoryCount); if (depth == 1) - directoryStack.front() = getDirectory(includerName); + directoryStack.back() = getDirectory(includerName); - // find a directory that works, reverse search of include stack + // Find a directory that works, using a reverse search of the include stack. for (auto it = directoryStack.rbegin(); it != directoryStack.rend(); ++it) { std::string path = *it + '/' + headerName; std::replace(path.begin(), path.end(), '\\', '/'); diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp index 40110e35..0b8b8f4d 100644 --- a/StandAlone/StandAlone.cpp +++ b/StandAlone/StandAlone.cpp @@ -167,6 +167,7 @@ const char* entryPointName = nullptr; const char* sourceEntryPointName = nullptr; const char* shaderStageName = nullptr; const char* variableName = nullptr; +std::vector IncludeDirectoryList; std::array baseSamplerBinding; std::array baseTextureBinding; @@ -407,6 +408,13 @@ void ProcessArguments(std::vector>& workItem Options |= EOptionLinkProgram; } break; + case 'I': + if (argv[0][2] == 0) { + printf("include path must immediately follow (no spaces) -I\n"); + exit(EFailUsage); + } + IncludeDirectoryList.push_back(argv[0]+2); + break; case 'V': Options |= EOptionSpv; Options |= EOptionVulkanRules; @@ -668,6 +676,8 @@ 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); }); if (Options & EOptionOutputPreprocessed) { std::string str; if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false, @@ -1031,6 +1041,8 @@ void usage() " -G create SPIR-V binary, under OpenGL semantics; turns on -l;\n" " default file name is .spv (-o overrides this)\n" " -H print human readable form of SPIR-V; turns on -V\n" + " -I add dir to the include search path; includer's directory\n" + " is searched first, followed by left-to-right order of -I\n" " -E print pre-processed GLSL; cannot be used with -l;\n" " errors will appear on stderr.\n" " -S uses specified stage rather than parsing the file extension\n" diff --git a/Test/baseResults/hlsl.dashI.vert.out b/Test/baseResults/hlsl.dashI.vert.out new file mode 100644 index 00000000..27e9129c --- /dev/null +++ b/Test/baseResults/hlsl.dashI.vert.out @@ -0,0 +1,69 @@ +hlsl.dashI.vert +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 40 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Vertex 4 "main" 38 + Source HLSL 500 + Name 4 "main" + Name 9 "@main(" + Name 11 "$Global" + MemberName 11($Global) 0 "i1" + MemberName 11($Global) 1 "p1" + MemberName 11($Global) 2 "p2" + MemberName 11($Global) 3 "p3" + MemberName 11($Global) 4 "i4" + Name 13 "" + Name 38 "@entryPointOutput" + MemberDecorate 11($Global) 0 Offset 0 + MemberDecorate 11($Global) 1 Offset 16 + MemberDecorate 11($Global) 2 Offset 32 + MemberDecorate 11($Global) 3 Offset 48 + MemberDecorate 11($Global) 4 Offset 64 + Decorate 11($Global) Block + Decorate 13 DescriptorSet 0 + Decorate 38(@entryPointOutput) BuiltIn Position + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 4 + 8: TypeFunction 7(fvec4) + 11($Global): TypeStruct 7(fvec4) 7(fvec4) 7(fvec4) 7(fvec4) 7(fvec4) + 12: TypePointer Uniform 11($Global) + 13: 12(ptr) Variable Uniform + 14: TypeInt 32 1 + 15: 14(int) Constant 0 + 16: TypePointer Uniform 7(fvec4) + 19: 14(int) Constant 4 + 23: 14(int) Constant 1 + 27: 14(int) Constant 2 + 31: 14(int) Constant 3 + 37: TypePointer Output 7(fvec4) +38(@entryPointOutput): 37(ptr) Variable Output + 4(main): 2 Function None 3 + 5: Label + 39: 7(fvec4) FunctionCall 9(@main() + Store 38(@entryPointOutput) 39 + Return + FunctionEnd + 9(@main(): 7(fvec4) Function None 8 + 10: Label + 17: 16(ptr) AccessChain 13 15 + 18: 7(fvec4) Load 17 + 20: 16(ptr) AccessChain 13 19 + 21: 7(fvec4) Load 20 + 22: 7(fvec4) FAdd 18 21 + 24: 16(ptr) AccessChain 13 23 + 25: 7(fvec4) Load 24 + 26: 7(fvec4) FAdd 22 25 + 28: 16(ptr) AccessChain 13 27 + 29: 7(fvec4) Load 28 + 30: 7(fvec4) FAdd 26 29 + 32: 16(ptr) AccessChain 13 31 + 33: 7(fvec4) Load 32 + 34: 7(fvec4) FAdd 30 33 + ReturnValue 34 + FunctionEnd diff --git a/Test/hlsl.dashI.vert b/Test/hlsl.dashI.vert new file mode 100644 index 00000000..a432be51 --- /dev/null +++ b/Test/hlsl.dashI.vert @@ -0,0 +1,13 @@ +// For -Iinc1/path1 -Iinc1/path2 +// bar.h from local directory will define i1, while the ones from inc1/path1 and inc1/path2 will not. +// notHere.h is only in inc1/path1 and inc2/path2, and only inc1/path1 defines p1, p2, and p3 +// parent.h is local again, and defines i4 + +#include "bar.h" +#include "notHere.h" +#include "parent.h" + +float4 main() : SV_Position +{ + return i1 + i4 + p1 + p2 + p3; +} diff --git a/Test/inc1/path1/bar.h b/Test/inc1/path1/bar.h new file mode 100644 index 00000000..46141dd1 --- /dev/null +++ b/Test/inc1/path1/bar.h @@ -0,0 +1 @@ +float4 i9991; diff --git a/Test/inc1/path1/local.h b/Test/inc1/path1/local.h new file mode 100644 index 00000000..b3aac8e3 --- /dev/null +++ b/Test/inc1/path1/local.h @@ -0,0 +1 @@ +float4 p2; diff --git a/Test/inc1/path1/notHere.h b/Test/inc1/path1/notHere.h new file mode 100644 index 00000000..2e7d56a6 --- /dev/null +++ b/Test/inc1/path1/notHere.h @@ -0,0 +1,4 @@ +float4 p1; + +#include "local.h" +#include "remote.h" diff --git a/Test/inc1/path2/bar.h b/Test/inc1/path2/bar.h new file mode 100644 index 00000000..46141dd1 --- /dev/null +++ b/Test/inc1/path2/bar.h @@ -0,0 +1 @@ +float4 i9991; diff --git a/Test/inc1/path2/notHere.h b/Test/inc1/path2/notHere.h new file mode 100644 index 00000000..63f4ca47 --- /dev/null +++ b/Test/inc1/path2/notHere.h @@ -0,0 +1 @@ +float4 paoeu1; diff --git a/Test/inc1/path2/remote.h b/Test/inc1/path2/remote.h new file mode 100644 index 00000000..c925d27a --- /dev/null +++ b/Test/inc1/path2/remote.h @@ -0,0 +1 @@ +float4 p3; diff --git a/Test/runtests b/Test/runtests index c3a049b1..945a0f34 100755 --- a/Test/runtests +++ b/Test/runtests @@ -116,6 +116,8 @@ $EXE -D -e main -H hlsl.includeNegative.vert > $TARGETDIR/hlsl.includeNegative.v diff -b $BASEDIR/hlsl.includeNegative.vert.out $TARGETDIR/hlsl.includeNegative.vert.out || HASERROR=1 $EXE -l -i include.vert > $TARGETDIR/include.vert.out diff -b $BASEDIR/include.vert.out $TARGETDIR/include.vert.out || HASERROR=1 +$EXE -D -e main -H -Iinc1/path1 -Iinc1/path2 hlsl.dashI.vert > $TARGETDIR/hlsl.dashI.vert.out +diff -b $BASEDIR/hlsl.dashI.vert.out $TARGETDIR/hlsl.dashI.vert.out || HASERROR=1 # # Final checking