Browse Source

WIP precompiled headers

I may take this another direction. Mostly committing in its current
state to make sure I don't lose it.
precompiled-headers
Macoy Madson 4 months ago
parent
commit
8154950bda
10 changed files with 176 additions and 21 deletions
  1. +3
    -4
      BuildAndRunTests.sh
  2. +20
    -0
      src/Build.cpp
  3. +104
    -9
      src/Evaluator.cpp
  4. +1
    -0
      src/Generators.cpp
  5. +8
    -8
      src/OutputPreambles.cpp
  6. +2
    -0
      src/OutputPreambles.hpp
  7. +2
    -0
      src/RunProcess.cpp
  8. +2
    -0
      src/RunProcessEnums.hpp
  9. +30
    -0
      src/Writer.cpp
  10. +4
    -0
      src/Writer.hpp

+ 3
- 4
BuildAndRunTests.sh View File

@ -27,15 +27,14 @@ echo "\nHot reloadable library\n"
./bin/cakelisp \
runtime/Config_Linux.cake runtime/HotReloadingCodeModifier.cake runtime/TextAdventure.cake || exit $?
# TestMain is the loader. It doesn't care at all about fancy hot reloading macros, it just loads libs
# ./bin/cakelisp \
# runtime/Config_Windows.cake runtime/HotLoader.cake || exit $?
echo "\nHot loader\n"
./bin/cakelisp \
runtime/Config_Linux.cake runtime/HotLoader.cake || exit $?
# ./bin/cakelisp \
# runtime/Config_Windows.cake runtime/HotLoader.cake || exit $?
echo "\nCompile-time defines\n"
./bin/cakelisp --execute \


+ 20
- 0
src/Build.cpp View File

@ -26,6 +26,8 @@ const char* linkerDynamicLibraryExtension = "so";
const char* defaultExecutableName = "a.out";
#endif
const char* precompiledHeaderExtension = "pch";
void makeIncludeArgument(char* buffer, int bufferSize, const char* searchDir)
{
// TODO: Make this a setting rather than a define
@ -83,6 +85,24 @@ void makeExecutableOutputArgument(char* buffer, int bufferSize, const char* exec
}
}
void makePrecompiledHeaderOutputArgument(char* buffer, int bufferSize, const char* executableName,
const char* linkExecutable)
{
// Annoying exception for MSVC not having spaces between some arguments
if (StrCompareIgnoreCase(linkExecutable, "cl.exe") == 0)
{
SafeSnprintf(buffer, bufferSize, "/Fe\"%s\"", executableName);
}
else if (StrCompareIgnoreCase(linkExecutable, "link.exe") == 0)
{
SafeSnprintf(buffer, bufferSize, "/out:\"%s\"", executableName);
}
else
{
SafeSnprintf(buffer, bufferSize, "%s", executableName);
}
}
void makeLinkLibraryArgument(char* buffer, int bufferSize, const char* libraryName,
const char* linkExecutable)
{


+ 104
- 9
src/Evaluator.cpp View File

@ -835,12 +835,103 @@ static int ReevaluateResolveReferences(EvaluatorEnvironment& environment,
return numReferencesResolved;
}
bool ComptimePrepareHeaders(EvaluatorEnvironment& environment)
{
const char* outputDir = cakelispWorkingDir;
const char* combinedHeaderName = "CakelispComptime.hpp";
std::vector<std::string> headerSearchDirectories;
{
// Need working dir to find cached file itself
headerSearchDirectories.push_back(".");
// Need Cakelisp src dir to find cakelisp headers. If these aren't checked for
// modification, comptime code can end up calling stale functions/initializing
// incorrect types
headerSearchDirectories.push_back(
environment.cakelispSrcDir.empty() ? "src" : environment.cakelispSrcDir);
}
char combinedHeaderFilename[MAX_PATH_LENGTH] = {0};
PrintfBuffer(combinedHeaderFileName, "%s/%s", outputDir, combinedHeaderName);
std::vector<const char*> headersToCombine(ArraySize(g_comptimeDefaultHeaders));
for (int i = 0; i < ArraySize(g_comptimeDefaultHeaders); ++i)
headersToCombine[i] = g_comptimeDefaultHeaders[i];
if (!writeCombinedHeader(combinedHeaderFilename, headersToCombine))
return false;
char precompiledHeaderFilename[MAX_PATH_LENGTH] = {0};
if (!outputFilenameFromSourceFilename(outputDir, combinedHeaderFilename,
precompiledHeaderExtension))
{
Logf("error: failed to prepare precompiled header output filename");
return false;
}
char precompiledHeaderOutputArgument[MAX_PATH_LENGTH + 5] = {0};
makePrecompiledHeaderOutputArgument(precompiledHeaderOutputArgument,
sizeof(precompiledHeaderOutputArgument),
precompiledHeaderFilename, buildExecutable);
const char* buildExecutable = environment.comptimePrecompileHeaderBuildCommand.fileToExecute.c_str();
char headerInclude[MAX_PATH_LENGTH] = {0};
if (environment.cakelispSrcDir.empty())
makeIncludeArgument(headerInclude, sizeof(headerInclude), "src/");
else
makeIncludeArgument(headerInclude, sizeof(headerInclude),
environment.cakelispSrcDir.c_str());
char precompileHeaderExecutable[MAX_PATH_LENGTH] = {0};
if (!resolveExecutablePath(buildExecutable, precompileHeaderExecutable,
sizeof(precompileHeaderExecutable)))
// TODO: Add error message?
continue;
ProcessCommandInput precompileHeaderInputs[] = {
{ProcessCommandArgumentType_SourceInput, {combinedHeaderFilename}},
{ProcessCommandArgumentType_PrecompiledHeaderOutput, {precompiledHeaderOutputArgument}},
{ProcessCommandArgumentType_CakelispHeadersInclude, {headerInclude}}};
const char** buildArguments = MakeProcessArgumentsFromCommand(
precompileHeaderExecutable, environment.comptimePrecompileHeaderBuildCommand.arguments,
precompileHeaderInputs, ArraySize(precompileHeaderInputs));
if (!buildArguments)
{
// TODO: Abort building if cannot invoke compiler
continue;
}
// Can we use the cached version?
if (!cppFileNeedsBuild(environment, combinedHeaderFilename, precompiledHeaderFilename,
buildArguments, environment.comptimeCachedCommandCrcs,
environment.comptimeNewCommandCrcs,
environment.comptimeHeaderModifiedCache, headerSearchDirectories))
{
if (logging.buildProcess)
Logf("Skipping precompiling %s (using cached header)\n", sourceOutputName);
return true;
}
environment.comptimeHeadersPrepared = true;
return true;
}
int BuildExecuteCompileTimeFunctions(EvaluatorEnvironment& environment,
std::vector<ComptimeBuildObject>& definitionsToBuild,
int& numErrorsOut)
{
int numReferencesResolved = 0;
if (environment.comptimeUsePrecompiledHeaders && !environment.comptimeHeadersPrepared)
{
if (!ComptimePrepareHeaders(environment))
{
++numErrorsOut;
return 0;
}
}
// Spin up as many compile processes as necessary
// TODO: Combine sure-thing builds into batches (ones where we know all references)
// TODO: Make pipeline able to start e.g. linker while other objects are still compiling
@ -1395,19 +1486,23 @@ bool BuildEvaluateReferences(EvaluatorEnvironment& environment, int& numErrorsOu
}
}
if (logging.compileTimeBuildObjects && !definitionsToBuild.empty())
int numReferencesResolved = 0;
if (!definitionsToBuild.empty())
{
int numToBuild = (int)definitionsToBuild.size();
Logf("Building %d compile-time object%c\n", numToBuild, numToBuild > 1 ? 's' : ' ');
for (ComptimeBuildObject& buildObject : definitionsToBuild)
if (logging.compileTimeBuildObjects)
{
Logf("\t%s\n", buildObject.definition->name.c_str());
int numToBuild = (int)definitionsToBuild.size();
Logf("Building %d compile-time object%c\n", numToBuild, numToBuild > 1 ? 's' : ' ');
for (ComptimeBuildObject& buildObject : definitionsToBuild)
{
Logf("\t%s\n", buildObject.definition->name.c_str());
}
}
}
int numReferencesResolved =
BuildExecuteCompileTimeFunctions(environment, definitionsToBuild, numErrorsOut);
numReferencesResolved =
BuildExecuteCompileTimeFunctions(environment, definitionsToBuild, numErrorsOut);
}
return numReferencesResolved > 0 || requireDependencyPropagation;
}


+ 1
- 0
src/Generators.cpp View File

@ -68,6 +68,7 @@ bool SetProcessCommandArguments(EvaluatorEnvironment& environment, const std::ve
{"'cakelisp-headers-include", ProcessCommandArgumentType_CakelispHeadersInclude},
{"'include-search-dirs", ProcessCommandArgumentType_IncludeSearchDirs},
{"'additional-options", ProcessCommandArgumentType_AdditionalOptions},
{"'precompiled-header-output", ProcessCommandArgumentType_PrecompiledHeaderOutput},
{"'object-input", ProcessCommandArgumentType_ObjectInput},
{"'library-output", ProcessCommandArgumentType_DynamicLibraryOutput},
{"'executable-output", ProcessCommandArgumentType_ExecutableOutput},


+ 8
- 8
src/OutputPreambles.cpp View File

@ -4,19 +4,19 @@
#include "GeneratorHelpers.hpp"
#include "Utilities.hpp"
const char* g_comptimeDefaultHeaders[10] = {
"Evaluator.hpp", "EvaluatorEnums.hpp", "Tokenizer.hpp", "GeneratorHelpers.hpp",
"Utilities.hpp", "ModuleManager.hpp", "Converters.hpp", "RunProcess.hpp",
"Build.hpp", "FileUtilities.hpp"};
void makeCompileTimeHeaderFooter(GeneratorOutput& headerOut, GeneratorOutput& footerOut,
GeneratorOutput* spliceAfterHeaders, const Token* blameToken)
{
const char* defaultIncludes[] = {
"Evaluator.hpp", "EvaluatorEnums.hpp", "Tokenizer.hpp", "GeneratorHelpers.hpp",
"Utilities.hpp", "ModuleManager.hpp", "Converters.hpp", "RunProcess.hpp",
"Build.hpp", "FileUtilities.hpp"};
for (unsigned int i = 0; i < ArraySize(defaultIncludes); ++i)
for (unsigned int i = 0; i < ArraySize(g_comptimeDefaultHeaders); ++i)
{
addStringOutput(headerOut.source, "#include", StringOutMod_SpaceAfter, blameToken);
addStringOutput(headerOut.source, defaultIncludes[i], StringOutMod_SurroundWithQuotes,
blameToken);
addStringOutput(headerOut.source, g_comptimeDefaultHeaders[i],
StringOutMod_SurroundWithQuotes, blameToken);
addLangTokenOutput(headerOut.source, StringOutMod_NewlineAfter, blameToken);
}


+ 2
- 0
src/OutputPreambles.hpp View File

@ -7,3 +7,5 @@ void makeCompileTimeHeaderFooter(GeneratorOutput& headerOut, GeneratorOutput& fo
GeneratorOutput* spliceAfterHeaders, const Token* blameToken);
void makeRunTimeHeaderFooter(GeneratorOutput& headerOut, GeneratorOutput& footerOut,
const Token* blameToken);
extern const char* g_comptimeDefaultHeaders[10];

+ 2
- 0
src/RunProcess.cpp View File

@ -500,6 +500,8 @@ static const char* ProcessCommandArgumentTypeToString(ProcessCommandArgumentType
return "IncludeSearchDirs";
case ProcessCommandArgumentType_AdditionalOptions:
return "AdditionalOptions";
case ProcessCommandArgumentType_PrecompiledHeaderOutput:
return "PrecompiledHeaderOutput";
case ProcessCommandArgumentType_ObjectInput:
return "ObjectInput";
case ProcessCommandArgumentType_DynamicLibraryOutput:


+ 2
- 0
src/RunProcessEnums.hpp View File

@ -13,6 +13,8 @@ enum ProcessCommandArgumentType
ProcessCommandArgumentType_IncludeSearchDirs,
ProcessCommandArgumentType_AdditionalOptions,
ProcessCommandArgumentType_PrecompiledHeaderOutput,
ProcessCommandArgumentType_ObjectInput,
ProcessCommandArgumentType_DynamicLibraryOutput,
ProcessCommandArgumentType_LibrarySearchDirs,


+ 30
- 0
src/Writer.cpp View File

@ -11,6 +11,7 @@
#include <stdio.h>
#include <string.h>
// This will delete the file at tempFilename
bool writeIfContentsNewer(const char* tempFilename, const char* outputFilename)
{
// Read temporary file and destination file and compare
@ -486,3 +487,32 @@ bool writeGeneratorOutput(const GeneratorOutput& generatedOutput,
return true;
}
bool writeCombinedHeader(const char* combinedHeaderFilename,
std::vector<const char*>& headersToInclude)
{
char tempFilename[MAX_PATH_LENGTH] = {0};
PrintfBuffer(tempFilename, "%s.temp", combinedHeaderFilename);
FILE* combinedHeaderFile = fopen(tempFilename, "w");
if (!combinedHeaderFile)
{
perror("fopen: ");
Logf("error: failed open %s", tempFilename);
return false;
}
fprint(combinedHeaderFile, "#pragma once\n");
for (const char* sourceHeader : headersToInclude)
{
fprintf(combinedHeaderFile, "#include \"%s\"\n", sourceHeader);
}
fclose(combinedHeaderFile);
if (!writeIfContentsNewer(tempFilename, combinedHeaderFilename))
return false;
return true;
}

+ 4
- 0
src/Writer.hpp View File

@ -37,3 +37,7 @@ bool writeGeneratorOutput(const GeneratorOutput& generatedOutput,
const NameStyleSettings& nameSettings,
const WriterFormatSettings& formatSettings,
const WriterOutputSettings& outputSettings);
// Create combinedHeaderFilename which is a header that includes headersToInclude
bool writeCombinedHeader(const char* combinedHeaderFilename,
std::vector<const char*>& headersToInclude);

Loading…
Cancel
Save