Browse Source

Compiling and linking working partially

* /Fo and /out: automatically added for cl.exe and link.exe (hack)
* Fix bootstrap script to actually read errorlevel properly
* Use proper extensions for object files and default executable
* Properly write command line (was missing spaces)

What still doesn't work: Re-using obj files, re-writing obj files
windows-support
Macoy Madson 6 months ago
parent
commit
bbef503463
4 changed files with 112 additions and 37 deletions
  1. +4
    -4
      Bootstrap_MSVC.cake
  2. +31
    -12
      Build.bat
  3. +42
    -6
      src/ModuleManager.cpp
  4. +35
    -15
      src/RunProcess.cpp

+ 4
- 4
Bootstrap_MSVC.cake View File

@ -40,18 +40,18 @@
(set-cakelisp-option build-time-compiler "cl.exe")
(set-cakelisp-option build-time-compile-arguments
"/c" 'source-input "/Fo" 'object-output
"/c" 'source-input 'object-output
'include-search-dirs 'additional-options)
(set-cakelisp-option compile-time-compiler "cl.exe")
(set-cakelisp-option compile-time-compile-arguments
"/c" 'source-input "/Fo" 'object-output
"/c" 'source-input 'object-output
'cakelisp-headers-include)
;; "-fPIC"
(set-cakelisp-option build-time-linker "cl.exe")
(set-cakelisp-option build-time-linker "link.exe")
(set-cakelisp-option build-time-link-arguments
"/Fo" 'executable-output 'object-input)
'executable-output 'object-input)
;; Use separate build configuration in case other things build files from src/
(add-build-config-label "Bootstrap_Windows")

+ 31
- 12
Build.bat View File

@ -1,3 +1,4 @@
echo off
rem Set environment variables. The user may need to adjust this path
rem See https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-160#developer_command_file_locations
if exist "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" (
@ -10,7 +11,7 @@ echo Select workloads for C++ projects. Ensure you install the C++ developer too
echo If you're still seeing this, you may need to edit Build.bat to your vcvars path
echo Please see the following link:
echo https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-160
goto :fail
goto fail
)
if not exist "bin" (
@ -18,6 +19,12 @@ mkdir bin
)
if not exist "bin\cakelisp_bootstrap.exe" (
goto manualBuild
) else (
goto bootstrapBuild
)
:manualBuild
CL.exe src/Tokenizer.cpp ^
src/Evaluator.cpp ^
src/Utilities.cpp ^
@ -33,25 +40,37 @@ CL.exe src/Tokenizer.cpp ^
src/Logging.cpp ^
src/Main.cpp ^
/EHsc /DWINDOWS /Fe"bin\cakelisp_bootstrap"
echo %ERRORLEVEL%
@if ERRORLEVEL == 0 (
rem Clean up working directory
del *.obj
rem TODO Go to bootstrap build
"bin\cakelisp_bootstrap.exe"
) else (
echo "Error while building"
goto :fail
)
@if %ERRORLEVEL% == 0 (
echo Success building
rem Clean up working directory
del *.obj
goto bootstrapBuild
) else (
"bin\cakelisp_bootstrap.exe" --verbose-processes Bootstrap_MSVC.cake
echo Error while building
goto fail
)
:bootstrapBuild
"bin\cakelisp_bootstrap.exe" --verbose-processes Bootstrap_MSVC.cake
rem Left off: Remove space between /Fo and output, -Isrc isn't going to work either
rem Figure out why CL isn't being found by CreateProcess
rem Can I list all the variables/paths being set in Cakelisp, to see if vcvars is applying, or if CreateProcess isn't passing them?
rem CL /c src/Tokenizer.cpp /Fo"cakelisp_cache/Bootstrap_Windows/Tokenizer.cpp.o" -Isrc /DWINDOWS /EHsc
@if %ERRORLEVEL% == 0 (
echo Success! Use bin\cakelisp.exe to build your programs
goto success
) else (
echo Error while bootstrapping cakelisp
goto fail
)
:fail
pause
goto end
:success
goto end
:end
pause

+ 42
- 6
src/ModuleManager.cpp View File

@ -18,7 +18,13 @@
#include "Utilities.hpp"
#include "Writer.hpp"
#ifdef WINDOWS
const char* compilerObjectExtension = "obj";
const char* defaultExecutableName = "output.exe";
#else
const char* compilerObjectExtension = "o";
const char* defaultExecutableName = "a.out";
#endif
// The ' symbols tell the signature validator that the actual contents of those symbols can be
// user-defined (just like C letting you specify arguments without names)
@ -651,7 +657,7 @@ void getExecutableOutputName(ModuleManager& manager, std::string& finalOutputNam
if (!manager.environment.executableOutput.empty())
finalOutputNameOut = manager.environment.executableOutput;
else
finalOutputNameOut = "a.out";
finalOutputNameOut = defaultExecutableName;
}
// Copy cachedOutputExecutable to finalOutputNameOut, adding executable permissions
@ -847,9 +853,20 @@ bool moduleManagerBuild(ModuleManager& manager, std::vector<std::string>& builtO
*object->buildCommandOverride :
manager.environment.buildTimeBuildCommand;
// Annoying exception for MSVC not having spaces between some arguments
std::string* objectOutput = &object->filename;
std::string objectOutputOverride;
if (_stricmp(buildCommand.fileToExecute.c_str(), "CL.exe") == 0)
{
char msvcObjectOutput[MAX_PATH_LENGTH] = {0};
PrintfBuffer(msvcObjectOutput, "/Fo\"%s\"", object->filename.c_str());
objectOutputOverride = msvcObjectOutput;
objectOutput = &objectOutputOverride;
}
ProcessCommandInput buildTimeInputs[] = {
{ProcessCommandArgumentType_SourceInput, {object->sourceFilename.c_str()}},
{ProcessCommandArgumentType_ObjectOutput, {object->filename.c_str()}},
{ProcessCommandArgumentType_ObjectOutput, {objectOutput->c_str()}},
{ProcessCommandArgumentType_IncludeSearchDirs, std::move(searchDirArgs)},
{ProcessCommandArgumentType_AdditionalOptions, std::move(additionalOptions)}};
const char** buildArguments = MakeProcessArgumentsFromCommand(buildCommand, buildTimeInputs,
@ -961,7 +978,7 @@ bool moduleManagerBuild(ModuleManager& manager, std::vector<std::string>& builtO
outputExecutableName = outputExecutableFilename;
}
if (outputExecutableName.empty())
outputExecutableName = "a.out";
outputExecutableName = defaultExecutableName;
char outputExecutableCachePath[MAX_PATH_LENGTH] = {0};
if (!outputFilenameFromSourceFilename(
@ -980,7 +997,7 @@ bool moduleManagerBuild(ModuleManager& manager, std::vector<std::string>& builtO
{
// Module* module = manager.modules[moduleIndex];
int buildResult = object->buildStatus;
if (buildResult != 0)
if (buildResult != 0 || !fileExists(object->filename.c_str()))
{
Logf("error: failed to make target %s\n", object->filename.c_str());
succeededBuild = false;
@ -1016,10 +1033,29 @@ bool moduleManagerBuild(ModuleManager& manager, std::vector<std::string>& builtO
objectsToLink[i] = object->filename.c_str();
}
// Copy it so hooks can modify it
ProcessCommand linkCommand = manager.environment.buildTimeLinkCommand;
// Annoying exception for MSVC not having spaces between some arguments
std::string* executableOutput = &outputExecutableName;
std::string executableOutputOverride;
if (_stricmp(linkCommand.fileToExecute.c_str(), "cl.exe") == 0)
{
char msvcExecutableOutput[MAX_PATH_LENGTH] = {0};
PrintfBuffer(msvcExecutableOutput, "/Fe\"%s\"", outputExecutableName.c_str());
executableOutputOverride = msvcExecutableOutput;
executableOutput = &executableOutputOverride;
}
else if (_stricmp(linkCommand.fileToExecute.c_str(), "link.exe") == 0)
{
char msvcExecutableOutput[MAX_PATH_LENGTH] = {0};
PrintfBuffer(msvcExecutableOutput, "/out:\"%s\"", outputExecutableName.c_str());
executableOutputOverride = msvcExecutableOutput;
executableOutput = &executableOutputOverride;
}
// Copy it so hooks can modify it
ProcessCommandInput linkTimeInputs[] = {
{ProcessCommandArgumentType_ExecutableOutput, {outputExecutableName.c_str()}},
{ProcessCommandArgumentType_ExecutableOutput, {executableOutput->c_str()}},
{ProcessCommandArgumentType_ObjectInput, objectsToLink}};
// Hooks should cooperate with eachother, i.e. try to only add things


+ 35
- 15
src/RunProcess.cpp View File

@ -235,7 +235,7 @@ int runProcess(const RunProcessArguments& arguments, int* statusOut)
{
*msvcVariables[i].outputString = (LPTSTR)malloc(bufferSize * sizeof(TCHAR));
if (!GetEnvironmentVariable(msvcVariables[i].variableName,
*msvcVariables[i].outputString, bufferSize) || true)
*msvcVariables[i].outputString, bufferSize))
{
Logf(
"error: could not find environment variable '%s'.\n Please read the "
@ -277,13 +277,6 @@ int runProcess(const RunProcessArguments& arguments, int* statusOut)
else
Log("Not doing override\n");
STARTUPINFO startupInfo;
PROCESS_INFORMATION* processInfo = new PROCESS_INFORMATION;
ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
ZeroMemory(processInfo, sizeof(PROCESS_INFORMATION));
const char* fileToExecute =
fileToExecuteOverride[0] ? fileToExecuteOverride : arguments.fileToExecute;
@ -310,18 +303,37 @@ int runProcess(const RunProcessArguments& arguments, int* statusOut)
free(commandLineString);
return 1;
}
if (*(arg + 1) != nullptr)
{
if (!writeCharToBuffer(' ', &writeHead, commandLineString, commandLineLength))
{
Log("error: ran out of space to write command\n");
free(commandLineString);
return 1;
}
}
}
}
STARTUPINFO startupInfo;
PROCESS_INFORMATION* processInfo = new PROCESS_INFORMATION;
ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
ZeroMemory(processInfo, sizeof(PROCESS_INFORMATION));
Logf("Final command string: %s\n", commandLineString);
// Start the child process.
if (!CreateProcess(fileToExecute, // No module name (use command line)
commandLineString, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
nullptr, // No security attributes
nullptr, // Thread handle not inheritable
true, // Set handle inheritance to true
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
nullptr, // Use parent's environment block
nullptr, // Use parent's starting directory
&startupInfo, // Pointer to STARTUPINFO structure
processInfo)) // Pointer to PROCESS_INFORMATION structure
{
@ -388,9 +400,17 @@ void waitForAllProcessesClosed(SubprocessOnOutputFunc onOutput)
// Wait until child process exits.
WaitForSingleObject(process.processInfo->hProcess, INFINITE);
DWORD exit_code;
if (!GetExitCodeProcess(process.processInfo->hProcess, &exit_code) || exit_code != 0)
// TODO: Why isn't this working? I always get 0
DWORD exit_code = 0;
if (!GetExitCodeProcess(process.processInfo->hProcess, &exit_code))
{
Log("error: failed to get exit code for process\n");
exit_code = 1;
}
else if (exit_code != 0)
{
Logf("%s\n", process.command.c_str());
}
*process.statusOut = exit_code;


Loading…
Cancel
Save