Browse Source

Clean up, move executable resolution

* Rename SafeSnprinf -> SafeSnprintf
* Enable all build tests
* Moved MSVC resolution code into resolveExecutablePath() instead of
corrupting RunProcess with its presense. This also gives us a nice
place to add Linux binary search paths and such
* Use Log macros in DynamicLoader, since it's no longer used in
runtime
* Move changeExtension to FileUtilities
* Changed %ul to %lu to silence warning
build-system-unification
Macoy Madson 6 months ago
parent
commit
bffff9be23
11 changed files with 227 additions and 180 deletions
  1. +19
    -11
      BuildAndRunTests.sh
  2. +83
    -7
      src/Build.cpp
  3. +6
    -0
      src/Build.hpp
  4. +8
    -8
      src/DynamicLoader.cpp
  5. +28
    -16
      src/Evaluator.cpp
  6. +39
    -13
      src/FileUtilities.cpp
  7. +4
    -0
      src/FileUtilities.hpp
  8. +26
    -34
      src/ModuleManager.cpp
  9. +6
    -87
      src/RunProcess.cpp
  10. +5
    -1
      src/RunProcess.hpp
  11. +3
    -3
      src/Utilities.hpp

+ 19
- 11
BuildAndRunTests.sh View File

@ -7,20 +7,28 @@
# See https://clang.llvm.org/docs/UsersManual.html#precompiled-headers
# clang -g -fPIC -x c++-header src/Evaluator.hpp -o src/Evaluator.hpp.pch
# ./bin/cakelisp --ignore-cache --verbose-compile-time-build-objects \
# test/CodeModification.cake
./bin/cakelisp --execute \
test/CodeModification.cake
# ./bin/cakelisp --ignore-cache --verbose-compile-time-build-objects \
# test/BuildOptions.cake
./bin/cakelisp \
test/BuildOptions.cake
# ./bin/cakelisp --verbose-processes --execute \
# test/Execute.cake
./bin/cakelisp --execute \
test/Execute.cake
# ./bin/cakelisp --verbose-build-process \
# runtime/HotReloadingCodeModifier.cake runtime/TextAdventure.cake || exit $?
./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 --verbose-processes --verbose-include-scanning \
# runtime/HotLoader.cake || exit $?
./bin/cakelisp \
runtime/Config_Windows.cake runtime/HotLoader.cake || exit $?
./bin/cakelisp CrossCompile_Windows.cake
./bin/cakelisp \
runtime/Config_Linux.cake runtime/HotLoader.cake || exit $?
./bin/cakelisp --execute \
test/Defines.cake
# ./bin/cakelisp CrossCompile_Windows.cake
./bin/cakelisp --execute test/MultiLineStrings.cake || exit $?

+ 83
- 7
src/Build.cpp View File

@ -18,9 +18,9 @@ void makeIncludeArgument(char* buffer, int bufferSize, const char* searchDir)
{
// TODO: Make this a setting rather than a define
#ifdef WINDOWS
SafeSnprinf(buffer, bufferSize, "/I \"%s\"", searchDir);
SafeSnprintf(buffer, bufferSize, "/I \"%s\"", searchDir);
#else
SafeSnprinf(buffer, bufferSize, "-I%s", searchDir);
SafeSnprintf(buffer, bufferSize, "-I%s", searchDir);
#endif
}
@ -28,9 +28,9 @@ void makeObjectOutputArgument(char* buffer, int bufferSize, const char* objectNa
{
// TODO: Make this a setting rather than a define
#ifdef WINDOWS
SafeSnprinf(buffer, bufferSize, "/Fo\"%s\"", objectName);
SafeSnprintf(buffer, bufferSize, "/Fo\"%s\"", objectName);
#else
SafeSnprinf(buffer, bufferSize, "%s", objectName);
SafeSnprintf(buffer, bufferSize, "%s", objectName);
#endif
}
@ -41,14 +41,90 @@ void makeDynamicLibraryOutputArgument(char* buffer, int bufferSize, const char*
{
Log("error: attempting to build dynamic library using cl.exe. You must use link.exe "
"instead\n");
SafeSnprinf(buffer, bufferSize, "%s", libraryName);
SafeSnprintf(buffer, bufferSize, "%s", libraryName);
}
else if (StrCompareIgnoreCase(buildExecutable, "link.exe") == 0)
{
SafeSnprinf(buffer, bufferSize, "/OUT:\"%s\"", libraryName);
SafeSnprintf(buffer, bufferSize, "/OUT:\"%s\"", libraryName);
}
else
{
SafeSnprinf(buffer, bufferSize, "%s", libraryName);
SafeSnprintf(buffer, bufferSize, "%s", libraryName);
}
}
bool resolveExecutablePath(const char* fileToExecute, char* resolvedPathOut,
int resolvedPathOutSize)
{
#ifdef WINDOWS
// We need to do some extra legwork to find which compiler they actually want to use, based on
// the current environment variables set by vcvars*.bat
// See https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-160
if (_stricmp(fileToExecute, "cl.exe") == 0 || _stricmp(fileToExecute, "link.exe") == 0)
{
LPTSTR vcInstallDir = nullptr;
LPTSTR vcHostArchitecture = nullptr;
LPTSTR vcTargetArchitecture = nullptr;
const int bufferSize = 4096;
struct
{
const char* variableName;
LPTSTR* outputString;
} msvcVariables[] = {{"VCToolsInstallDir", &vcInstallDir},
{"VSCMD_ARG_HOST_ARCH", &vcHostArchitecture},
{"VSCMD_ARG_TGT_ARCH", &vcTargetArchitecture}};
bool variablesFound = true;
for (int i = 0; i < ArraySize(msvcVariables); ++i)
{
*msvcVariables[i].outputString = (LPTSTR)malloc(bufferSize * sizeof(TCHAR));
if (!GetEnvironmentVariable(msvcVariables[i].variableName,
*msvcVariables[i].outputString, bufferSize))
{
Logf(
"error: could not find environment variable '%s'.\n Please read the "
"following "
"URL:\nhttps://docs.microsoft.com/en-us/cpp/build/"
"building-on-the-command-line?view=msvc-160\nYou must run Cakelisp in a "
"command prompt which has already run vcvars* scripts.\nSee "
"cakelisp/Build.bat for an example.\nYou can define variables when running "
"Cakelisp from Visual Studio via Project -> Properties -> Configuration "
"Properties -> Debugging -> Environment\n",
msvcVariables[i].variableName);
Log("The following vars need to be defined in the environment to be read from "
"Cakelisp directly:\n");
for (int n = 0; n < ArraySize(msvcVariables); ++n)
Logf("\t%s\n", msvcVariables[n].variableName);
Log("Note that MSVC relies on more variables which vcvars*.bat define, so you need "
"to define those as well (if you do not use vcvars script).\n");
variablesFound = false;
break;
}
}
if (variablesFound)
{
// SafeSnprintf(resolvedPathOut, resolvedPathOutSize, "%sHost%s/%s/%s", vcInstallDir,
// vcHostArchitecture,
SafeSnprintf(resolvedPathOut, resolvedPathOutSize, "%sbin\\Host%s\\%s\\%s",
vcInstallDir, vcHostArchitecture, vcTargetArchitecture, fileToExecute);
if (logging.processes)
Logf("\nOverriding command to:\n%s\n\n", resolvedPathOut);
}
for (int n = 0; n < ArraySize(msvcVariables); ++n)
if (*msvcVariables[n].outputString)
free(*msvcVariables[n].outputString);
return variablesFound;
}
#endif
// Default is to just keep it as-is. This may make sense to bolster in the future via using
// search paths, e.g. remove the need to specify /usr/bin
SafeSnprintf(resolvedPathOut, resolvedPathOutSize, "%s", fileToExecute);
return true;
}

+ 6
- 0
src/Build.hpp View File

@ -11,3 +11,9 @@ void makeIncludeArgument(char* buffer, int bufferSize, const char* searchDir);
void makeObjectOutputArgument(char* buffer, int bufferSize, const char* objectName);
void makeDynamicLibraryOutputArgument(char* buffer, int bufferSize, const char* libraryName,
const char* buildExecutable);
// On Windows, extra work is done to find the compiler and linker executables. This function handles
// looking up those environment variables to determine which executable to use. On Linux, this
// function might be a good place for executable search paths, e.g. check /usr/bin for g++
bool resolveExecutablePath(const char* fileToExecute, char* resolvedPathOut,
int resolvedPathOutSize);

+ 8
- 8
src/DynamicLoader.cpp View File

@ -42,7 +42,7 @@ DynamicLibHandle loadDynamicLibrary(const char* libraryPath)
const char* error = dlerror();
if (!libHandle || error)
{
fprintf(stderr, "DynamicLoader Error:\n%s\n", error);
Logf("DynamicLoader Error:\n%s\n", error);
return nullptr;
}
@ -78,8 +78,8 @@ DynamicLibHandle loadDynamicLibrary(const char* libraryPath)
LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
if (!libHandle)
{
fprintf(stderr, "DynamicLoader Error: Failed to load %s with code %d\n", convertedPath,
GetLastError());
Logf("DynamicLoader Error: Failed to load %s with code %d\n", convertedPath,
GetLastError());
free((void*)absoluteLibPath);
return nullptr;
}
@ -94,7 +94,7 @@ void* getSymbolFromDynamicLibrary(DynamicLibHandle library, const char* symbolNa
{
if (!library)
{
fprintf(stderr, "DynamicLoader Error: Received empty library handle\n");
Log("DynamicLoader Error: Received empty library handle\n");
return nullptr;
}
@ -103,7 +103,7 @@ void* getSymbolFromDynamicLibrary(DynamicLibHandle library, const char* symbolNa
char* error = dlerror();
if (error != nullptr)
{
fprintf(stderr, "DynamicLoader Error:\n%s\n", error);
Logf("DynamicLoader Error:\n%s\n", error);
return nullptr;
}
@ -112,7 +112,7 @@ void* getSymbolFromDynamicLibrary(DynamicLibHandle library, const char* symbolNa
error = dlerror();
if (error != nullptr)
{
fprintf(stderr, "DynamicLoader Error:\n%s\n", error);
Logf("DynamicLoader Error:\n%s\n", error);
return nullptr;
}
@ -121,7 +121,7 @@ void* getSymbolFromDynamicLibrary(DynamicLibHandle library, const char* symbolNa
void* procedure = (void*)GetProcAddress((HINSTANCE)library, symbolName);
if (!procedure)
{
fprintf(stderr, "DynamicLoader Error:\n%d\n", GetLastError());
Logf("DynamicLoader Error:\n%d\n", GetLastError());
return nullptr;
}
return procedure;
@ -160,7 +160,7 @@ void closeDynamicLibrary(DynamicLibHandle handleToClose)
if (!libHandle)
{
fprintf(stderr, "warning: closing library which wasn't in the list of loaded libraries\n");
Log("warning: closing library which wasn't in the list of loaded libraries\n");
libHandle = handleToClose;
}


+ 28
- 16
src/Evaluator.cpp View File

@ -1,5 +1,8 @@
#include "Evaluator.hpp"
#include <stdio.h>
#include <string.h>
#include "Build.hpp"
#include "Converters.hpp"
#include "DynamicLoader.hpp"
@ -13,9 +16,6 @@
#include "Utilities.hpp"
#include "Writer.hpp"
#include <stdio.h>
#include <string.h>
//
// Environment
//
@ -869,15 +869,20 @@ int BuildExecuteCompileTimeFunctions(EvaluatorEnvironment& environment,
environment.cakelispSrcDir.c_str());
char buildObjectArgument[MAX_PATH_LENGTH] = {0};
makeObjectOutputArgument(buildObjectArgument, sizeof(buildObjectArgument),
buildObjectName);
makeObjectOutputArgument(buildObjectArgument, sizeof(buildObjectArgument), buildObjectName);
char compileTimeBuildExecutable[MAX_PATH_LENGTH] = {0};
if (!resolveExecutablePath(environment.compileTimeBuildCommand.fileToExecute.c_str(),
compileTimeBuildExecutable, sizeof(compileTimeBuildExecutable)))
continue;
ProcessCommandInput compileTimeInputs[] = {
{ProcessCommandArgumentType_SourceInput, {sourceOutputName}},
{ProcessCommandArgumentType_ObjectOutput, {buildObjectArgument}},
{ProcessCommandArgumentType_CakelispHeadersInclude, {headerInclude}}};
const char** buildArguments = MakeProcessArgumentsFromCommand(
environment.compileTimeBuildCommand, compileTimeInputs, ArraySize(compileTimeInputs));
compileTimeBuildExecutable, environment.compileTimeBuildCommand.arguments,
compileTimeInputs, ArraySize(compileTimeInputs));
if (!buildArguments)
{
// TODO: Abort building if cannot invoke compiler
@ -885,7 +890,7 @@ int BuildExecuteCompileTimeFunctions(EvaluatorEnvironment& environment,
}
RunProcessArguments compileArguments = {};
compileArguments.fileToExecute = environment.compileTimeBuildCommand.fileToExecute.c_str();
compileArguments.fileToExecute = compileTimeBuildExecutable;
compileArguments.arguments = buildArguments;
if (runProcess(compileArguments, &buildObject.status) != 0)
{
@ -941,23 +946,29 @@ int BuildExecuteCompileTimeFunctions(EvaluatorEnvironment& environment,
Logf("Compiled %s successfully\n", buildObject.definition->name.c_str());
char dynamicLibraryOutArgument[MAX_PATH_LENGTH] = {0};
makeDynamicLibraryOutputArgument(
dynamicLibraryOutArgument, sizeof(dynamicLibraryOutArgument),
buildObject.dynamicLibraryPath.c_str(), environment.compileTimeLinkCommand.fileToExecute.c_str());
makeDynamicLibraryOutputArgument(dynamicLibraryOutArgument,
sizeof(dynamicLibraryOutArgument),
buildObject.dynamicLibraryPath.c_str(),
environment.compileTimeLinkCommand.fileToExecute.c_str());
char compileTimeLinkExecutable[MAX_PATH_LENGTH] = {0};
if (!resolveExecutablePath(environment.compileTimeLinkCommand.fileToExecute.c_str(),
compileTimeLinkExecutable, sizeof(compileTimeLinkExecutable)))
continue;
ProcessCommandInput linkTimeInputs[] = {
{ProcessCommandArgumentType_DynamicLibraryOutput,
{dynamicLibraryOutArgument}},
{ProcessCommandArgumentType_DynamicLibraryOutput, {dynamicLibraryOutArgument}},
{ProcessCommandArgumentType_ObjectInput, {buildObject.buildObjectName.c_str()}}};
const char** linkArgumentList = MakeProcessArgumentsFromCommand(
environment.compileTimeLinkCommand, linkTimeInputs, ArraySize(linkTimeInputs));
compileTimeLinkExecutable, environment.compileTimeLinkCommand.arguments, linkTimeInputs,
ArraySize(linkTimeInputs));
if (!linkArgumentList)
{
// TODO: Abort building if cannot invoke compiler
continue;
}
RunProcessArguments linkArguments = {};
linkArguments.fileToExecute = environment.compileTimeLinkCommand.fileToExecute.c_str();
linkArguments.fileToExecute = compileTimeLinkExecutable;
linkArguments.arguments = linkArgumentList;
if (runProcess(linkArguments, &buildObject.status) != 0)
{
@ -1641,7 +1652,8 @@ bool searchForFileInPaths(const char* shortPath, const char* encounteredInFile,
{
char relativePathBuffer[MAX_PATH_LENGTH] = {0};
getDirectoryFromPath(encounteredInFile, relativePathBuffer, sizeof(relativePathBuffer));
SafeSnprinf(foundFilePathOut, foundFilePathOutSize, "%s/%s", relativePathBuffer, shortPath);
SafeSnprintf(foundFilePathOut, foundFilePathOutSize, "%s/%s", relativePathBuffer,
shortPath);
if (logging.fileSearch)
Logf("File exists? %s (", foundFilePathOut);
@ -1658,7 +1670,7 @@ bool searchForFileInPaths(const char* shortPath, const char* encounteredInFile,
for (const std::string& path : searchPaths)
{
SafeSnprinf(foundFilePathOut, foundFilePathOutSize, "%s/%s", path.c_str(), shortPath);
SafeSnprintf(foundFilePathOut, foundFilePathOutSize, "%s/%s", path.c_str(), shortPath);
if (logging.fileSearch)
Logf("File exists? %s (", foundFilePathOut);


+ 39
- 13
src/FileUtilities.cpp View File

@ -163,7 +163,7 @@ void getDirectoryFromPath(const char* path, char* bufferOut, int bufferSize)
#ifdef UNIX
char* pathCopy = StrDuplicate(path);
const char* dirName = dirname(pathCopy);
SafeSnprinf(bufferOut, bufferSize, "%s", dirName);
SafeSnprintf(bufferOut, bufferSize, "%s", dirName);
free(pathCopy);
#elif WINDOWS
char drive[_MAX_DRIVE];
@ -185,7 +185,7 @@ void getFilenameFromPath(const char* path, char* bufferOut, int bufferSize)
#ifdef UNIX
char* pathCopy = StrDuplicate(path);
const char* fileName = basename(pathCopy);
SafeSnprinf(bufferOut, bufferSize, "%s", fileName);
SafeSnprintf(bufferOut, bufferSize, "%s", fileName);
free(pathCopy);
#elif WINDOWS
// char drive[_MAX_DRIVE];
@ -204,7 +204,6 @@ void makePathRelativeToFile(const char* filePath, const char* referencedFilePath
int bufferSize)
{
getDirectoryFromPath(filePath, bufferOut, bufferSize);
// TODO: Need to make this safe!
StrCatSafe(bufferOut, bufferSize, "/");
StrCatSafe(bufferOut, bufferSize, referencedFilePath);
}
@ -258,14 +257,14 @@ void makeAbsoluteOrRelativeToWorkingDir(const char* filePath, char* bufferOut, i
if (filePath[0] == '/' || (filePath[0] == '.' && filePath[1] == '\0') ||
(filePath[0] == '.' && filePath[1] == '/' && filePath[2] == '\0'))
{
SafeSnprinf(bufferOut, bufferSize, "%s", filePath);
SafeSnprintf(bufferOut, bufferSize, "%s", filePath);
return;
}
const char* workingDirAbsolute = realpath(".", nullptr);
if (!workingDirAbsolute)
{
SafeSnprinf(bufferOut, bufferSize, "%s", filePath);
SafeSnprintf(bufferOut, bufferSize, "%s", filePath);
return;
}
@ -273,7 +272,7 @@ void makeAbsoluteOrRelativeToWorkingDir(const char* filePath, char* bufferOut, i
if (!filePathAbsolute)
{
free((void*)workingDirAbsolute);
SafeSnprinf(bufferOut, bufferSize, "%s", filePath);
SafeSnprintf(bufferOut, bufferSize, "%s", filePath);
return;
}
@ -285,13 +284,13 @@ void makeAbsoluteOrRelativeToWorkingDir(const char* filePath, char* bufferOut, i
// The resolved path is within working dir
int trimTrailingSlash = filePathAbsolute[workingDirPathLength] == '/' ? 1 : 0;
const char* startRelativePath = &filePathAbsolute[workingDirPathLength + trimTrailingSlash];
SafeSnprinf(bufferOut, bufferSize, "%s", startRelativePath);
SafeSnprintf(bufferOut, bufferSize, "%s", startRelativePath);
}
else
{
// Resolved path is above working dir
// Could still make this relative with ../ up to differing directory, if I find it's desired
SafeSnprinf(bufferOut, bufferSize, "%s", filePathAbsolute);
SafeSnprintf(bufferOut, bufferSize, "%s", filePathAbsolute);
}
free((void*)workingDirAbsolute);
@ -315,7 +314,7 @@ void makeAbsoluteOrRelativeToWorkingDir(const char* filePath, char* bufferOut, i
const char* filePathAbsolute = makeAbsolutePath_Allocated(nullptr, filePath);
if (!filePathAbsolute)
{
SafeSnprinf(bufferOut, bufferSize, "%s", filePath);
SafeSnprintf(bufferOut, bufferSize, "%s", filePath);
return;
}
@ -330,13 +329,13 @@ void makeAbsoluteOrRelativeToWorkingDir(const char* filePath, char* bufferOut, i
0;
const char* startRelativePath =
&filePathAbsolute[workingDirPathLength + trimTrailingSlash];
SafeSnprinf(bufferOut, bufferSize, "%s", startRelativePath);
SafeSnprintf(bufferOut, bufferSize, "%s", startRelativePath);
}
else
{
// Resolved path is above working dir. Could still make this relative with ../ up to
// differing directory, if I find it's desired
SafeSnprinf(bufferOut, bufferSize, "%s", filePathAbsolute);
SafeSnprintf(bufferOut, bufferSize, "%s", filePathAbsolute);
}
free((void*)filePathAbsolute);
}
@ -374,11 +373,11 @@ bool outputFilenameFromSourceFilename(const char* outputDir, const char* sourceF
// TODO: Trim .cake.cpp (etc.)
if (!addExtension)
{
SafeSnprinf(bufferOut, bufferSize, "%s/%s", outputDir, buildFilename);
SafeSnprintf(bufferOut, bufferSize, "%s/%s", outputDir, buildFilename);
}
else
{
SafeSnprinf(bufferOut, bufferSize, "%s/%s.%s", outputDir, buildFilename, addExtension);
SafeSnprintf(bufferOut, bufferSize, "%s/%s.%s", outputDir, buildFilename, addExtension);
}
return true;
}
@ -497,3 +496,30 @@ void makeBackslashFilename(char* buffer, int bufferSize, const char* filename)
}
}
}
// TODO: Safer version
bool changeExtension(char* buffer, const char* newExtension)
{
int bufferLength = strlen(buffer);
char* expectExtensionStart = nullptr;
for (char* currentChar = buffer + (bufferLength - 1); *currentChar && currentChar > buffer;
--currentChar)
{
if (*currentChar == '.')
{
expectExtensionStart = currentChar;
break;
}
}
if (!expectExtensionStart)
return false;
char* extensionWrite = expectExtensionStart + 1;
for (const char* extensionChar = newExtension; *extensionChar; ++extensionChar)
{
*extensionWrite = *extensionChar;
++extensionWrite;
}
*extensionWrite = '\0';
return true;
}

+ 4
- 0
src/FileUtilities.hpp View File

@ -42,3 +42,7 @@ void addExecutablePermission(const char* filename);
// Some Windows APIs require backslashes
void makeBackslashFilename(char* buffer, int bufferSize, const char* filename);
// Does NOT validate whether your buffer can fit the new extension + null terminator
// TODO: Safer version
bool changeExtension(char* buffer, const char* newExtension);

+ 26
- 34
src/ModuleManager.cpp View File

@ -728,32 +728,6 @@ void getExecutableOutputName(ModuleManager& manager, std::string& finalOutputNam
finalOutputNameOut = defaultExecutableName;
}
// TODO: Safer version
bool changeExtension(char* buffer, const char* newExtension)
{
int bufferLength = strlen(buffer);
char* expectExtensionStart = nullptr;
for (char* currentChar = buffer + (bufferLength - 1); *currentChar && currentChar > buffer;
--currentChar)
{
if (*currentChar == '.')
{
expectExtensionStart = currentChar;
break;
}
}
if (!expectExtensionStart)
return false;
char* extensionWrite = expectExtensionStart + 1;
for (const char* extensionChar = newExtension; *extensionChar; ++extensionChar)
{
*extensionWrite = *extensionChar;
++extensionWrite;
}
return true;
}
// Copy cachedOutputExecutable to finalOutputNameOut, adding executable permissions
// TODO: There's no easy way to know whether this exe is the current build configuration's
// output exe, so copy it every time
@ -772,14 +746,14 @@ bool copyExecutableToFinalOutput(ModuleManager& manager, const std::string& cach
// TODO: Consider a better place for this
#ifdef WINDOWS
char executableLib[MAX_PATH_LENGTH] = {0};
SafeSnprinf(executableLib, sizeof(executableLib), "%s", cachedOutputExecutable.c_str());
SafeSnprintf(executableLib, sizeof(executableLib), "%s", cachedOutputExecutable.c_str());
bool modifiedExtension = changeExtension(executableLib, "lib");
if (modifiedExtension && fileExists(executableLib))
{
char finalOutputLib[MAX_PATH_LENGTH] = {0};
SafeSnprinf(finalOutputLib, sizeof(finalOutputLib), "%s", finalOutputName.c_str());
SafeSnprintf(finalOutputLib, sizeof(finalOutputLib), "%s", finalOutputName.c_str());
modifiedExtension = changeExtension(finalOutputLib, "lib");
if (modifiedExtension && !copyBinaryFileTo(executableLib, finalOutputLib))
@ -987,13 +961,22 @@ bool moduleManagerBuild(ModuleManager& manager, std::vector<std::string>& builtO
objectOutput = &objectOutputOverride;
}
char buildTimeBuildExecutable[MAX_PATH_LENGTH] = {0};
if (!resolveExecutablePath(buildCommand.fileToExecute.c_str(), buildTimeBuildExecutable,
sizeof(buildTimeBuildExecutable)))
{
builtObjectsFree(builtObjects);
return false;
}
ProcessCommandInput buildTimeInputs[] = {
{ProcessCommandArgumentType_SourceInput, {object->sourceFilename.c_str()}},
{ProcessCommandArgumentType_ObjectOutput, {objectOutput->c_str()}},
{ProcessCommandArgumentType_IncludeSearchDirs, std::move(searchDirArgs)},
{ProcessCommandArgumentType_AdditionalOptions, std::move(additionalOptions)}};
const char** buildArguments = MakeProcessArgumentsFromCommand(buildCommand, buildTimeInputs,
ArraySize(buildTimeInputs));
const char** buildArguments =
MakeProcessArgumentsFromCommand(buildTimeBuildExecutable, buildCommand.arguments,
buildTimeInputs, ArraySize(buildTimeInputs));
if (!buildArguments)
{
Log("error: failed to construct build arguments\n");
@ -1044,7 +1027,7 @@ bool moduleManagerBuild(ModuleManager& manager, std::vector<std::string>& builtO
{
Logf("--- Must rebuild %s (header files modified)\n",
object->sourceFilename.c_str());
Logf("Artifact: %ul Most recent header: %ul\n", artifactModTime,
Logf("Artifact: %lu Most recent header: %lu\n", artifactModTime,
mostRecentHeaderModTime);
}
}
@ -1066,7 +1049,7 @@ bool moduleManagerBuild(ModuleManager& manager, std::vector<std::string>& builtO
// Go through with the build
RunProcessArguments compileArguments = {};
compileArguments.fileToExecute = buildCommand.fileToExecute.c_str();
compileArguments.fileToExecute = buildTimeBuildExecutable;
compileArguments.arguments = buildArguments;
// PrintProcessArguments(buildArguments);
@ -1197,8 +1180,17 @@ bool moduleManagerBuild(ModuleManager& manager, std::vector<std::string>& builtO
}
}
char buildTimeLinkExecutable[MAX_PATH_LENGTH] = {0};
if (!resolveExecutablePath(linkCommand.fileToExecute.c_str(), buildTimeLinkExecutable,
sizeof(buildTimeLinkExecutable)))
{
builtObjectsFree(builtObjects);
return false;
}
const char** linkArgumentList =
MakeProcessArgumentsFromCommand(linkCommand, linkTimeInputs, ArraySize(linkTimeInputs));
MakeProcessArgumentsFromCommand(buildTimeLinkExecutable, linkCommand.arguments,
linkTimeInputs, ArraySize(linkTimeInputs));
if (!linkArgumentList)
{
builtObjectsFree(builtObjects);
@ -1247,7 +1239,7 @@ bool moduleManagerBuild(ModuleManager& manager, std::vector<std::string>& builtO
manager.newCommandCrcs[finalOutputName] = commandCrc;
RunProcessArguments linkArguments = {};
linkArguments.fileToExecute = linkCommand.fileToExecute.c_str();
linkArguments.fileToExecute = buildTimeLinkExecutable;
linkArguments.arguments = linkArgumentList;
int linkStatus = 0;
if (runProcess(linkArguments, &linkStatus) != 0)


+ 6
- 87
src/RunProcess.cpp View File

@ -62,20 +62,6 @@ void subprocessReceiveStdOut(const char* processOutputBuffer)
Logf("%s", processOutputBuffer);
}
// Does not work
#ifdef WINDOWS
void LogLastError()
{
LPTSTR lpMsgBuf = nullptr;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpMsgBuf, 0, NULL);
printf("%s\n", lpMsgBuf);
}
#endif
int runProcess(const RunProcessArguments& arguments, int* statusOut)
{
if (logging.processes)
@ -180,75 +166,7 @@ int runProcess(const RunProcessArguments& arguments, int* statusOut)
return 0;
#elif WINDOWS
// We need to do some extra legwork to find which compiler they actually want to use, based on
// the current environment variables set by vcvars*.bat
// See https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-160
char fileToExecuteOverride[MAX_PATH_LENGTH] = {0};
if (_stricmp(arguments.fileToExecute, "cl.exe") == 0 ||
_stricmp(arguments.fileToExecute, "link.exe") == 0)
{
LPTSTR vcInstallDir = nullptr;
LPTSTR vcHostArchitecture = nullptr;
LPTSTR vcTargetArchitecture = nullptr;
const int bufferSize = 4096;
struct
{
const char* variableName;
LPTSTR* outputString;
} msvcVariables[] = {{"VCToolsInstallDir", &vcInstallDir},
{"VSCMD_ARG_HOST_ARCH", &vcHostArchitecture},
{"VSCMD_ARG_TGT_ARCH", &vcTargetArchitecture}};
bool variablesFound = true;
for (int i = 0; i < ArraySize(msvcVariables); ++i)
{
*msvcVariables[i].outputString = (LPTSTR)malloc(bufferSize * sizeof(TCHAR));
if (!GetEnvironmentVariable(msvcVariables[i].variableName,
*msvcVariables[i].outputString, bufferSize))
{
Logf(
"error: could not find environment variable '%s'.\n Please read the "
"following "
"URL:\nhttps://docs.microsoft.com/en-us/cpp/build/"
"building-on-the-command-line?view=msvc-160\nYou must run Cakelisp in a "
"command prompt which has already run vcvars* scripts.\nSee "
"cakelisp/Build.bat for an example.\nYou can define variables when running "
"Cakelisp from Visual Studio via Project -> Properties -> Configuration "
"Properties -> Debugging -> Environment\n",
msvcVariables[i].variableName);
Log("The following vars need to be defined in the environment to be read from "
"Cakelisp directly:\n");
for (int n = 0; n < ArraySize(msvcVariables); ++n)
Logf("\t%s\n", msvcVariables[n].variableName);
Log("Note that MSVC relies on more variables which vcvars*.bat define, so you need "
"to define those as well (if you do not use vcvars script).\n");
variablesFound = false;
break;
}
}
if (variablesFound)
{
// PrintfBuffer(fileToExecuteOverride, "%sHost%s/%s/%s", vcInstallDir, vcHostArchitecture,
PrintfBuffer(fileToExecuteOverride, "%sbin\\Host%s\\%s\\%s", vcInstallDir, vcHostArchitecture,
vcTargetArchitecture, arguments.fileToExecute);
if (logging.processes)
Logf("\nOverriding command to:\n%s\n\n", fileToExecuteOverride);
}
for (int n = 0; n < ArraySize(msvcVariables); ++n)
if (*msvcVariables[n].outputString)
free(*msvcVariables[n].outputString);
if (!variablesFound)
return 1;
}
const char* fileToExecute =
fileToExecuteOverride[0] ? fileToExecuteOverride : arguments.fileToExecute;
const char* fileToExecute = arguments.fileToExecute;
// Build a single string with all arguments
char* commandLineString = nullptr;
@ -555,14 +473,15 @@ void PrintProcessArguments(const char** processArguments)
}
// The array will need to be deleted, but the array members will not
const char** MakeProcessArgumentsFromCommand(ProcessCommand& command,
const char** MakeProcessArgumentsFromCommand(const char* fileToExecute,
std::vector<ProcessCommandArgument>& arguments,
const ProcessCommandInput* inputs, int numInputs)
{
std::vector<const char*> argumentsAccumulate;
for (unsigned int i = 0; i < command.arguments.size(); ++i)
for (unsigned int i = 0; i < arguments.size(); ++i)
{
ProcessCommandArgument& argument = command.arguments[i];
ProcessCommandArgument& argument = arguments[i];
if (argument.type == ProcessCommandArgumentType_String)
argumentsAccumulate.push_back(argument.contents.c_str());
@ -593,7 +512,7 @@ const char** MakeProcessArgumentsFromCommand(ProcessCommand& command,
// +1 again for the null terminator
const char** newArguments = (const char**)calloc(sizeof(const char*), numFinalArguments + 1);
newArguments[0] = command.fileToExecute.c_str();
newArguments[0] = fileToExecute;
for (int i = 1; i < numFinalArguments; ++i)
newArguments[i] = argumentsAccumulate[i - 1];
newArguments[numFinalArguments] = nullptr;


+ 5
- 1
src/RunProcess.hpp View File

@ -42,7 +42,11 @@ struct ProcessCommandInput
};
void PrintProcessArguments(const char** processArguments);
const char** MakeProcessArgumentsFromCommand(ProcessCommand& command,
// The array will need to be deleted, but the array members will not
// All strings need to exist and not be moved until after you call runProcess
const char** MakeProcessArgumentsFromCommand(const char* fileToExecute,
std::vector<ProcessCommandArgument>& arguments,
const ProcessCommandInput* inputs, int numInputs);
extern const int maxProcessesRecommendedSpawned;

+ 3
- 3
src/Utilities.hpp View File

@ -22,16 +22,16 @@ void printIndentToDepth(int depth);
#define Log(format) fprintf(stderr, format)
// TODO: de-macroize
#define SafeSnprinf(buffer, size, format, ...) \
#define SafeSnprintf(buffer, size, format, ...) \
{ \
int _numPrinted = snprintf(buffer, size, format, __VA_ARGS__); \
buffer[_numPrinted] = '\0'; \
}
#define PrintfBuffer(buffer, format, ...) SafeSnprinf(buffer, sizeof(buffer), format, __VA_ARGS__)
#define PrintfBuffer(buffer, format, ...) SafeSnprintf(buffer, sizeof(buffer), format, __VA_ARGS__)
// TODO Replace with strcat()?
#define PrintBuffer(buffer, output) SafeSnprinf(buffer, sizeof(buffer), "%s", output)
#define PrintBuffer(buffer, output) SafeSnprintf(buffer, sizeof(buffer), "%s", output)
bool writeCharToBuffer(char c, char** at, char* bufferStart, int bufferSize);
bool writeStringToBuffer(const char* str, char** at, char* bufferStart, int bufferSize);


Loading…
Cancel
Save