summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-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
3 files changed, 412 insertions, 0 deletions
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