summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2020-09-17 12:13:50 -0700
committerGitHub <noreply@github.com>2020-09-17 12:13:50 -0700
commitbbf492a0b78ce8b96372a736b7d591cdc71d5b65 (patch)
treebc8e65906efacc0930df522ddd68e074bcf51614
parent0124bf25c53ba76bf0d0e624d9a0d1b2b03760a6 (diff)
Embed default prelude for CUDA (#1546)
* Embed default prelude for CUDA Slang supports the notion of a "prelude" that gets prepended to the source code we generate in language. For some targets, a prelude is not necessary (e.g., we compile to HLSL/GLSL and then on to DXBC/DXIL/SPIR-V just fine without a prelude), but some targets have been implemented in a way that makes a prelude necessary (notably CPU and CUDA). For the targets that require a prelude, the Slang codebase includes usable preludes under the `prelude/` directory. Prior to this change, if a user was compiling for such a target (whether via command-line or API), there had to take responsibility for specifying the prelude to use (usually by passing in the contents of the prelude file(s) already included in the Slang distribution). It is reasonable for a user to expect an out-of-the-box experience where compilation to CUDA PTX or native CPU code should Just Work, similarly to how compilation to SPIR-V Just Works. This change is a step in the direction of providing a user experiene that Just Works for common cases. The main addition here is a tool called `slang-embed` that we run during our build to turn the `prelude/*.h` files into `prelude/*.h.cpp` files that embed the contents of the original `.h` file as a `const` variable. By compiling and linking in the generated `.h.cpp` file for the CUDA prelude, we are then able to set the default prelude to use for CUDA at the time a session/linkage is created. That default prelude will be used unless the user manually specifies their own prelude (which current users of the CUDA back-end must be doing). This change only sets up a default prelude for CUDA because of the way that the CPU prelude is split across multiple files. A strategy that provides a good default prelude for CPU may take more work, but that work might also be unnecessary if we switch to a strategy of using LLVM to generate native code. The implementation of the `slang-embed` tool is intentionally simple, and it will likely run into issues if/when we need to embed binary files or larger text files. The assumption being made here is that we can address those issues when they arise, and there is no reason to over-engineer the tool right now. The way that `slang-embed` is integrated into our build process is likely to require some iteration to make sure that it works across all platforms. I expect that this change will have multiple follow-up fixes related to trying to get the build to work as expected across all targets on CI. * fixup: trying to ensure that embedded prelude gets compiled into slang * fixup: properly clean up allocations in slang-embed * fixup: fix double free introduced by previous change * fixup: off-by-one allocation error
-rw-r--r--premake5.lua20
-rw-r--r--slang.sln12
-rw-r--r--source/core/core.vcxproj2
-rw-r--r--source/slang/run-generators.vcxproj52
-rw-r--r--source/slang/run-generators.vcxproj.filters12
-rw-r--r--source/slang/slang.cpp5
-rw-r--r--source/slang/slang.vcxproj4
-rw-r--r--source/slang/slang.vcxproj.filters12
-rw-r--r--tools/slang-embed/slang-embed.cpp228
-rw-r--r--tools/slang-embed/slang-embed.vcxproj171
-rw-r--r--tools/slang-embed/slang-embed.vcxproj.filters13
11 files changed, 529 insertions, 2 deletions
diff --git a/premake5.lua b/premake5.lua
index 17313b825..f6bfe6d77 100644
--- a/premake5.lua
+++ b/premake5.lua
@@ -616,6 +616,9 @@ tool "slang-generate"
uuid "66174227-8541-41FC-A6DF-4764FC66F78E"
links { "core" }
+tool "slang-embed"
+ links { "core" }
+
--
-- The `slang-test` test driver also uses the `core` library, and it
-- currently relies on include paths being set up so that it can find
@@ -791,6 +794,7 @@ generatorProject("run-generators", "source/slang/")
{
"source/slang/*.meta.slang", -- The stdlib files
"source/slang/slang-ast-reflect.h", -- The C++ reflection
+ "prelude/*.h", -- The prelude files
--
-- To build we need to have some source! It has to be a source file that
@@ -805,7 +809,7 @@ generatorProject("run-generators", "source/slang/")
-- gets built before `slang`, so we declare a non-linking dependency between
-- the projects here:
--
- dependson { "slang-cpp-extractor", "slang-generate" }
+ dependson { "slang-cpp-extractor", "slang-generate", "slang-embed" }
local executableSuffix = "";
if(os.target() == "windows") then
@@ -895,6 +899,14 @@ generatorProject("run-generators", "source/slang/")
--
buildinputs { "%{cfg.targetdir}/slang-generate" .. executableSuffix }
end
+
+ if executeBinary then
+ filter "files:prelude/*.h"
+ buildmessage "slang-embed %{file.relpath}"
+ buildcommands { '"%{cfg.targetdir}/slang-embed" %{file.relpath}' }
+ buildoutputs { "%{file.abspath}.cpp" }
+ buildinputs { "%{cfg.targetdir}/slang-embed" .. executableSuffix }
+ end
--
@@ -938,6 +950,12 @@ standardProject "slang"
files { "source/core/core.natvis" }
+ -- We explicitly name the prelude file(s) that we need to
+ -- compile for their embedded code, since they will not
+ -- exist at the time projects/makefiles are generated,
+ -- and thus a glob would not match anything.
+ files { "prelude/slang-cuda-prelude.h.cpp" }
+
--
-- The most challenging part of building `slang` is that we need
-- to invoke generators such as slang-cpp-extractor and slang-generate
diff --git a/slang.sln b/slang.sln
index c2481ca33..6c486c89a 100644
--- a/slang.sln
+++ b/slang.sln
@@ -21,6 +21,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "run-generators", "source\sl
ProjectSection(ProjectDependencies) = postProject
{CA8A30D1-8FA9-4330-B7F7-84709246D8DC} = {CA8A30D1-8FA9-4330-B7F7-84709246D8DC}
{66174227-8541-41FC-A6DF-4764FC66F78E} = {66174227-8541-41FC-A6DF-4764FC66F78E}
+ {7F773DD9-EB8F-2403-B43C-B49C2014B99C} = {7F773DD9-EB8F-2403-B43C-B49C2014B99C}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slang", "source\slang\slang.vcxproj", "{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}"
@@ -42,6 +43,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gfx", "tools\gfx\gfx.vcxpro
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slang-cpp-extractor", "tools\slang-cpp-extractor\slang-cpp-extractor.vcxproj", "{CA8A30D1-8FA9-4330-B7F7-84709246D8DC}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slang-embed", "tools\slang-embed\slang-embed.vcxproj", "{7F773DD9-EB8F-2403-B43C-B49C2014B99C}"
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slang-generate", "tools\slang-generate\slang-generate.vcxproj", "{66174227-8541-41FC-A6DF-4764FC66F78E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slang-test", "tools\slang-test\slang-test.vcxproj", "{0C768A18-1D25-4000-9F37-DA5FE99E3B64}"
@@ -158,6 +161,14 @@ Global
{CA8A30D1-8FA9-4330-B7F7-84709246D8DC}.Release|Win32.Build.0 = Release|Win32
{CA8A30D1-8FA9-4330-B7F7-84709246D8DC}.Release|x64.ActiveCfg = Release|x64
{CA8A30D1-8FA9-4330-B7F7-84709246D8DC}.Release|x64.Build.0 = Release|x64
+ {7F773DD9-EB8F-2403-B43C-B49C2014B99C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7F773DD9-EB8F-2403-B43C-B49C2014B99C}.Debug|Win32.Build.0 = Debug|Win32
+ {7F773DD9-EB8F-2403-B43C-B49C2014B99C}.Debug|x64.ActiveCfg = Debug|x64
+ {7F773DD9-EB8F-2403-B43C-B49C2014B99C}.Debug|x64.Build.0 = Debug|x64
+ {7F773DD9-EB8F-2403-B43C-B49C2014B99C}.Release|Win32.ActiveCfg = Release|Win32
+ {7F773DD9-EB8F-2403-B43C-B49C2014B99C}.Release|Win32.Build.0 = Release|Win32
+ {7F773DD9-EB8F-2403-B43C-B49C2014B99C}.Release|x64.ActiveCfg = Release|x64
+ {7F773DD9-EB8F-2403-B43C-B49C2014B99C}.Release|x64.Build.0 = Release|x64
{66174227-8541-41FC-A6DF-4764FC66F78E}.Debug|Win32.ActiveCfg = Debug|Win32
{66174227-8541-41FC-A6DF-4764FC66F78E}.Debug|Win32.Build.0 = Debug|Win32
{66174227-8541-41FC-A6DF-4764FC66F78E}.Debug|x64.ActiveCfg = Debug|x64
@@ -189,6 +200,7 @@ Global
{C5ACCA6E-C04D-4B36-8516-3752B3C13C2F} = {57B5AA5E-C340-1823-CC51-9B17385C7423}
{222F7498-B40C-4F3F-A704-DDEB91A4484A} = {FD47AE19-69FD-260F-F2F1-20E65EA61D13}
{CA8A30D1-8FA9-4330-B7F7-84709246D8DC} = {FD47AE19-69FD-260F-F2F1-20E65EA61D13}
+ {7F773DD9-EB8F-2403-B43C-B49C2014B99C} = {FD47AE19-69FD-260F-F2F1-20E65EA61D13}
{66174227-8541-41FC-A6DF-4764FC66F78E} = {FD47AE19-69FD-260F-F2F1-20E65EA61D13}
{0C768A18-1D25-4000-9F37-DA5FE99E3B64} = {FD47AE19-69FD-260F-F2F1-20E65EA61D13}
EndGlobalSection
diff --git a/source/core/core.vcxproj b/source/core/core.vcxproj
index 521adc790..38f06b407 100644
--- a/source/core/core.vcxproj
+++ b/source/core/core.vcxproj
@@ -254,4 +254,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project> \ No newline at end of file
+</Project> \ No newline at end of file
diff --git a/source/slang/run-generators.vcxproj b/source/slang/run-generators.vcxproj
index 620d43039..c03b67ce1 100644
--- a/source/slang/run-generators.vcxproj
+++ b/source/slang/run-generators.vcxproj
@@ -157,6 +157,58 @@
<ClCompile Include="..\core\slang-string.cpp" />
</ItemGroup>
<ItemGroup>
+ <CustomBuild Include="..\..\prelude\slang-cpp-prelude.h">
+ <FileType>Document</FileType>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"../../bin/windows-x86/debug/slang-embed" %(Identity)</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"../../bin/windows-x64/debug/slang-embed" %(Identity)</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"../../bin/windows-x86/release/slang-embed" %(Identity)</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"../../bin/windows-x64/release/slang-embed" %(Identity)</Command>
+ <Outputs>../../prelude/slang-cpp-prelude.h.cpp</Outputs>
+ <Message>slang-embed %(Identity)</Message>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../bin/windows-x86/debug/slang-embed.exe</AdditionalInputs>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../bin/windows-x64/debug/slang-embed.exe</AdditionalInputs>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../bin/windows-x86/release/slang-embed.exe</AdditionalInputs>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../bin/windows-x64/release/slang-embed.exe</AdditionalInputs>
+ </CustomBuild>
+ <CustomBuild Include="..\..\prelude\slang-cpp-scalar-intrinsics.h">
+ <FileType>Document</FileType>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"../../bin/windows-x86/debug/slang-embed" %(Identity)</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"../../bin/windows-x64/debug/slang-embed" %(Identity)</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"../../bin/windows-x86/release/slang-embed" %(Identity)</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"../../bin/windows-x64/release/slang-embed" %(Identity)</Command>
+ <Outputs>../../prelude/slang-cpp-scalar-intrinsics.h.cpp</Outputs>
+ <Message>slang-embed %(Identity)</Message>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../bin/windows-x86/debug/slang-embed.exe</AdditionalInputs>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../bin/windows-x64/debug/slang-embed.exe</AdditionalInputs>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../bin/windows-x86/release/slang-embed.exe</AdditionalInputs>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../bin/windows-x64/release/slang-embed.exe</AdditionalInputs>
+ </CustomBuild>
+ <CustomBuild Include="..\..\prelude\slang-cpp-types.h">
+ <FileType>Document</FileType>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"../../bin/windows-x86/debug/slang-embed" %(Identity)</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"../../bin/windows-x64/debug/slang-embed" %(Identity)</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"../../bin/windows-x86/release/slang-embed" %(Identity)</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"../../bin/windows-x64/release/slang-embed" %(Identity)</Command>
+ <Outputs>../../prelude/slang-cpp-types.h.cpp</Outputs>
+ <Message>slang-embed %(Identity)</Message>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../bin/windows-x86/debug/slang-embed.exe</AdditionalInputs>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../bin/windows-x64/debug/slang-embed.exe</AdditionalInputs>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../bin/windows-x86/release/slang-embed.exe</AdditionalInputs>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../bin/windows-x64/release/slang-embed.exe</AdditionalInputs>
+ </CustomBuild>
+ <CustomBuild Include="..\..\prelude\slang-cuda-prelude.h">
+ <FileType>Document</FileType>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"../../bin/windows-x86/debug/slang-embed" %(Identity)</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"../../bin/windows-x64/debug/slang-embed" %(Identity)</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"../../bin/windows-x86/release/slang-embed" %(Identity)</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"../../bin/windows-x64/release/slang-embed" %(Identity)</Command>
+ <Outputs>../../prelude/slang-cuda-prelude.h.cpp</Outputs>
+ <Message>slang-embed %(Identity)</Message>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../bin/windows-x86/debug/slang-embed.exe</AdditionalInputs>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../bin/windows-x64/debug/slang-embed.exe</AdditionalInputs>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../bin/windows-x86/release/slang-embed.exe</AdditionalInputs>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../bin/windows-x64/release/slang-embed.exe</AdditionalInputs>
+ </CustomBuild>
<CustomBuild Include="core.meta.slang">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"../../bin/windows-x86/debug/slang-generate" %(Identity)</Command>
diff --git a/source/slang/run-generators.vcxproj.filters b/source/slang/run-generators.vcxproj.filters
index 45b6e00b1..2f0200bd1 100644
--- a/source/slang/run-generators.vcxproj.filters
+++ b/source/slang/run-generators.vcxproj.filters
@@ -14,6 +14,18 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
+ <CustomBuild Include="..\..\prelude\slang-cpp-prelude.h">
+ <Filter>Header Files</Filter>
+ </CustomBuild>
+ <CustomBuild Include="..\..\prelude\slang-cpp-scalar-intrinsics.h">
+ <Filter>Header Files</Filter>
+ </CustomBuild>
+ <CustomBuild Include="..\..\prelude\slang-cpp-types.h">
+ <Filter>Header Files</Filter>
+ </CustomBuild>
+ <CustomBuild Include="..\..\prelude\slang-cuda-prelude.h">
+ <Filter>Header Files</Filter>
+ </CustomBuild>
<CustomBuild Include="core.meta.slang">
<Filter>Source Files</Filter>
</CustomBuild>
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index c97da7125..4c83095c2 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -40,6 +40,8 @@
#undef NOMINMAX
#endif
+extern char const* slang_cuda_prelude;
+
namespace Slang {
/* static */const BaseTypeInfo BaseTypeInfo::s_info[Index(BaseType::CountOf)] =
@@ -183,6 +185,9 @@ void Session::init()
m_defaultDownstreamCompilers[Index(SourceLanguage::CPP)] = PassThroughMode::GenericCCpp;
m_defaultDownstreamCompilers[Index(SourceLanguage::CUDA)] = PassThroughMode::NVRTC;
}
+
+ // Set up default prelude code for target languages that need a prelude
+ m_languagePreludes[Index(SourceLanguage::CUDA)] = slang_cuda_prelude;
}
ISlangUnknown* Session::getInterface(const Guid& guid)
diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj
index dcbc3865e..696873756 100644
--- a/source/slang/slang.vcxproj
+++ b/source/slang/slang.vcxproj
@@ -295,6 +295,10 @@
<ClInclude Include="slang-visitor.h" />
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="..\..\prelude\slang-cpp-prelude.h.cpp" />
+ <ClCompile Include="..\..\prelude\slang-cpp-scalar-intrinsics.h.cpp" />
+ <ClCompile Include="..\..\prelude\slang-cpp-types.h.cpp" />
+ <ClCompile Include="..\..\prelude\slang-cuda-prelude.h.cpp" />
<ClCompile Include="slang-ast-builder.cpp" />
<ClCompile Include="slang-ast-decl.cpp" />
<ClCompile Include="slang-ast-dump.cpp" />
diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters
index 1fff5d01f..3fd006f77 100644
--- a/source/slang/slang.vcxproj.filters
+++ b/source/slang/slang.vcxproj.filters
@@ -332,6 +332,18 @@
</ClInclude>
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="..\..\prelude\slang-cpp-prelude.h.cpp">
+ <Filter>Header Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\prelude\slang-cpp-scalar-intrinsics.h.cpp">
+ <Filter>Header Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\prelude\slang-cpp-types.h.cpp">
+ <Filter>Header Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\prelude\slang-cuda-prelude.h.cpp">
+ <Filter>Header Files</Filter>
+ </ClCompile>
<ClCompile Include="slang-ast-builder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/tools/slang-embed/slang-embed.cpp b/tools/slang-embed/slang-embed.cpp
new file mode 100644
index 000000000..5dee2a609
--- /dev/null
+++ b/tools/slang-embed/slang-embed.cpp
@@ -0,0 +1,228 @@
+// slang-embed.cpp
+
+// This file implements a simple utility for taking an input file
+// and embedding into a C++ source file as a `static const` array.
+
+// For now this utility uses plain C stdlib functionality rather
+// than depending on any of the utiltiies from the Slang project
+// libraries.
+//
+#ifdef _MSC_VER
+#pragma warning(disable: 4996)
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Utility to free pointers on scope exit
+struct ScopedMemory
+{
+ ScopedMemory(void* ptr)
+ : ptr(ptr)
+ {}
+
+ ~ScopedMemory()
+ {
+ if(ptr) free(ptr);
+ }
+
+ void* ptr;
+};
+
+// Utility to close file on scope exit
+struct ScopedFile
+{
+ ScopedFile(FILE* file)
+ : file(file)
+ {}
+
+ ~ScopedFile()
+ {
+ if(file) fclose(file);
+ }
+
+ FILE* file;
+};
+
+// The utility is implemented as a single `struct` type
+// that provides a context for the code. We do this as
+// an alternative to using global variables for passing
+// around options easily.
+//
+struct App
+{
+ char const* appName = "slang-embed";
+ char const* inputPath = nullptr;
+
+ void parseOptions(int argc, char** argv)
+ {
+ // Options are currently all specified by position,
+ // so the parsing logic is simplistic.
+
+ if( argc > 0 )
+ {
+ appName = *argv++;
+ argc--;
+ }
+
+ if( argc > 0 )
+ {
+ inputPath = *argv++;
+ argc--;
+ }
+
+ if( !inputPath || (argc != 0) )
+ {
+ fprintf(stderr, "usage: %s <inputPath>\n", appName);
+ exit(1);
+ }
+ }
+
+ void processInputFile()
+ {
+ // Note: Eventually we might support multiple input files in a
+ // single invocation of the tool, but for now we only have
+ // a single file to process.
+
+ // We open the input file in text mode because we are currently
+ // embedding textual source files. If/when this utility gets
+ // used for binary files another mode could be called for.
+ //
+ // (Alternatively, we might always use binary mode, but this
+ // could lead to a difference in the embedded bytes based on
+ // the line ending convention of the host platform)
+ //
+ FILE* inputFile = fopen(inputPath, "r");
+ ScopedFile inputFileCleanup(inputFile);
+ if( !inputFile )
+ {
+ fprintf(stderr, "%s: error: failed to open '%s' for reading\n", appName, inputPath);
+ exit(1);
+ }
+
+ // We derive an output path simply by appending `.cpp` to the input path.
+ //
+ // TODO: If we start adding more complicated options, a `-o` option
+ // to specify a desired output path would be an obvious choice.
+ //
+ char* outputPath = (char*) malloc(strlen(inputPath) + strlen(".cpp") + 1);
+ ScopedMemory outputPathCleanup(outputPath);
+ strcpy(outputPath, inputPath);
+ strcat(outputPath, ".cpp");
+
+ FILE* outputFile = fopen(outputPath, "w");
+ ScopedFile outputFileCleanup(outputFile);
+ if( !outputPath )
+ {
+ fprintf(stderr, "%s: error: failed to open '%s' for reading\n", appName, outputPath);
+ exit(1);
+ }
+
+ // We want to derive a variable name based on the name of
+ // the input file we are mbedded. Toward this end, we
+ // start by trying to strip off any leading directories
+ // in the path. This logic is ad hoc but should suffice,
+ // given that we don't plan to give the files we embed
+ // unconventional names.
+ //
+ char const* fileName = inputPath;
+ if(auto pos = strrchr(fileName, '\\'))
+ fileName = pos+1;
+ if(auto pos = strrchr(fileName, '/'))
+ fileName = pos+1;
+
+ // The variable name will start as a copy of the file
+ // name, although we will immediately drop any extension
+ // that comes after a `.` to trim the name further.
+ //
+ char* variableName = (char*) malloc(strlen(fileName)+1);
+ ScopedMemory variableNameCleanup(variableName);
+ strcpy(variableName, fileName);
+ if(auto pos = strchr(variableName, '.'))
+ *pos = 0;
+
+ // We will also replace any `-` in the file name with
+ // a `_` in the generate variable name, so that the
+ // tool will be compatible with our current naming
+ // convention of using `-` as the separator in file names.
+ //
+ for( auto cursor = variableName; *cursor; ++cursor)
+ {
+ switch( *cursor )
+ {
+ default:
+ break;
+ case '-': *cursor = '_';
+ }
+ }
+
+ // With all the preliminaries out of the way, the actual
+ // task of outputting the generated source file is simple.
+ //
+ fprintf(outputFile, "// generated code; do not edit\n");
+ fprintf(outputFile, "const char* %s =\n", variableName);
+
+ // Note: For now we are embedding the file as a string
+ // literal, with full knowledge that this strategy
+ // will run into limitations in certain compilers
+ // (e.g., some versions of the Visual C++ compiler
+ // don't handle string literals larger than 64KB).
+ //
+ // TODO: Eventually we should replace this logic with
+ // code to emit a plain array of `unsigned char` with
+ // an array initializer list `{ ... }`. While some
+ // compilers have limitations or performance issues
+ // with large array literals, the practical limits
+ // appear to be higher than they are for string literals.
+
+ fprintf(outputFile, "\"");
+ for( ;;)
+ {
+ int c = fgetc(inputFile);
+ if( c == EOF )
+ break;
+
+ // Based on the byte that we are trying to emit,
+ // we may need to emit an escape sequence.
+ //
+ switch( c )
+ {
+ // The common C escape sequencs are handled directly.
+ //
+ case '"': fprintf(outputFile, "\\\""); break;
+ case '\n': fprintf(outputFile, "\\n\"\n\""); break;
+ case '\t': fprintf(outputFile, "\\t"); break;
+
+ default:
+ // For all other cases, we detect if the byte
+ // is in the printable ASCII range, and emit
+ // it directly if sco.
+ //
+ if( c >= 32 && c <= 126 )
+ {
+ fputc(c, outputFile);
+ }
+ else
+ {
+ // Otherwise, we emit the byte as an octal
+ // escape sequence, being sure to emit a
+ // full three digits to avoid errorneous
+ // encoding if the following byte might
+ // represent a digit.
+ //
+ fprintf(outputFile, "\\%03o", c);
+ }
+ break;
+ }
+ }
+ fprintf(outputFile, "\";\n");
+ }
+};
+
+int main(int argc, char** argv)
+{
+ App app;
+ app.parseOptions(argc, argv);
+ app.processInputFile();
+ return 0;
+}
diff --git a/tools/slang-embed/slang-embed.vcxproj b/tools/slang-embed/slang-embed.vcxproj
new file mode 100644
index 000000000..67ddcd6e8
--- /dev/null
+++ b/tools/slang-embed/slang-embed.vcxproj
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{7F773DD9-EB8F-2403-B43C-B49C2014B99C}</ProjectGuid>
+ <IgnoreWarnCompileDuplicatedFilename>true</IgnoreWarnCompileDuplicatedFilename>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>slang-embed</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v140</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v140</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v140</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v140</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>..\..\bin\windows-x86\debug\</OutDir>
+ <IntDir>..\..\intermediate\windows-x86\debug\slang-embed\</IntDir>
+ <TargetName>slang-embed</TargetName>
+ <TargetExt>.exe</TargetExt>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>..\..\bin\windows-x64\debug\</OutDir>
+ <IntDir>..\..\intermediate\windows-x64\debug\slang-embed\</IntDir>
+ <TargetName>slang-embed</TargetName>
+ <TargetExt>.exe</TargetExt>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>..\..\bin\windows-x86\release\</OutDir>
+ <IntDir>..\..\intermediate\windows-x86\release\slang-embed\</IntDir>
+ <TargetName>slang-embed</TargetName>
+ <TargetExt>.exe</TargetExt>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>..\..\bin\windows-x64\release\</OutDir>
+ <IntDir>..\..\intermediate\windows-x64\release\slang-embed\</IntDir>
+ <TargetName>slang-embed</TargetName>
+ <TargetExt>.exe</TargetExt>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <Optimization>Disabled</Optimization>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <Optimization>Disabled</Optimization>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Optimization>Full</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Optimization>Full</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="slang-embed.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\source\core\core.vcxproj">
+ <Project>{F9BE7957-8399-899E-0C49-E714FDDD4B65}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/tools/slang-embed/slang-embed.vcxproj.filters b/tools/slang-embed/slang-embed.vcxproj.filters
new file mode 100644
index 000000000..56c2872ac
--- /dev/null
+++ b/tools/slang-embed/slang-embed.vcxproj.filters
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{E9C7FDCE-D52A-8D73-7EB0-C5296AF258F6}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="slang-embed.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file