1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 19:48:20 +02:00
Beef/BeefBoot/BootApp.cpp

966 lines
25 KiB
C++
Raw Normal View History

2019-08-23 11:56:54 -07:00
#pragma warning(disable:4996)
//#define BFBUILD_MAIN_THREAD_COMPILE
#include "BootApp.h"
#include <iostream>
#include "BeefySysLib/util/String.h"
#include "BeefySysLib/util/FileEnumerator.h"
#include "BeefySysLib/util/WorkThread.h"
#include "BeefySysLib/platform/PlatformHelper.h"
#include "Compiler/BfSystem.h"
#ifdef BF_PLATFORM_WINDOWS
#include <direct.h>
#endif
BF_IMPORT void BF_CALLTYPE Targets_Create();
BF_IMPORT void BF_CALLTYPE Targets_Delete();
BF_IMPORT void BF_CALLTYPE BfSystem_ReportMemory(void* bfSystem);
BF_EXPORT void BF_CALLTYPE BfCompiler_ProgramDone();
BF_IMPORT void BF_CALLTYPE Debugger_FullReportMemory();
//////////////////////////////////////////////////////////////////////////
BF_IMPORT void BF_CALLTYPE BfCompiler_Delete(void* bfCompiler);
BF_EXPORT void BF_CALLTYPE BfCompiler_SetOptions(void* bfCompiler, void* hotProject, int hotIdx,
2022-01-25 07:12:47 -05:00
const char* targetTriple, const char* targetCPU, int toolsetType, int simdSetting, int allocStackCount, int maxWorkerThreads,
Beefy::BfCompilerOptionFlags optionFlags, const char* mallocLinkName, const char* freeLinkName);
2019-08-23 11:56:54 -07:00
BF_IMPORT void BF_CALLTYPE BfCompiler_ClearBuildCache(void* bfCompiler);
BF_IMPORT bool BF_CALLTYPE BfCompiler_Compile(void* bfCompiler, void* bfPassInstance, const char* outputPath);
BF_IMPORT float BF_CALLTYPE BfCompiler_GetCompletionPercentage(void* bfCompiler);
BF_IMPORT const char* BF_CALLTYPE BfCompiler_GetUsedOutputFileNames(void* bfCompiler, void* bfProject, bool flushQueuedHotFiles, bool* hadOutputChanges);
BF_IMPORT void* BF_CALLTYPE BfSystem_CreateParser(void* bfSystem, void* bfProject);
BF_IMPORT void BF_CALLTYPE BfParser_SetSource(void* bfParser, const char* data, int length, const char* fileName);
BF_IMPORT void BF_CALLTYPE BfParser_SetCharIdData(void* bfParser, uint8* data, int length);
BF_IMPORT bool BF_CALLTYPE BfParser_Parse(void* bfParser, void* bfPassInstance, bool compatMode);
BF_IMPORT bool BF_CALLTYPE BfParser_Reduce(void* bfParser, void* bfPassInstance);
BF_IMPORT bool BF_CALLTYPE BfParser_BuildDefs(void* bfParser, void* bfPassInstance, void* resolvePassData, bool fullRefresh);
//////////////////////////////////////////////////////////////////////////
BF_IMPORT void* BF_CALLTYPE BfSystem_Create();
2022-05-13 13:37:00 -07:00
BF_EXPORT void BF_CALLTYPE BfSystem_Lock(void* bfSystem, int priority);
BF_EXPORT void BF_CALLTYPE BfSystem_Unlock(void* bfSystem);
2019-08-23 11:56:54 -07:00
BF_IMPORT void BF_CALLTYPE BfSystem_ReportMemory(void* bfSystem);
BF_IMPORT void BF_CALLTYPE BfSystem_Delete(void* bfSystem);
BF_IMPORT void* BF_CALLTYPE BfSystem_CreatePassInstance(void* bfSystem);
BF_IMPORT void* BF_CALLTYPE BfSystem_CreateCompiler(void* bfSystem, bool isResolveOnly);
2021-12-20 09:57:44 -05:00
BF_IMPORT void* BF_CALLTYPE BfSystem_CreateProject(void* bfSystem, const char* projectName, const char* projectDir);
2019-08-23 11:56:54 -07:00
BF_IMPORT void BF_CALLTYPE BfParser_Delete(void* bfParser);
BF_IMPORT void BF_CALLTYPE BfSystem_AddTypeOptions(void* bfSystem, const char* filter, int32 simdSetting, int32 optimizationLevel, int32 emitDebugInfo, int32 arrayBoundsCheck,
int32 initLocalVariables, int32 emitDynamicCastCheck, int32 emitObjectAccessCheck, int32 allocStackTraceDepth);
//////////////////////////////////////////////////////////////////////////
BF_IMPORT void BF_CALLTYPE BfProject_SetDisabled(void* bfProject, bool disabled);
BF_IMPORT void BF_CALLTYPE BfProject_SetOptions(void* bfProject, int targetType, const char* startupObject, const char* preprocessorMacros,
int optLevel, int ltoType, int relocType, int picLevel, int32 flags);
2019-08-23 11:56:54 -07:00
BF_IMPORT void BF_CALLTYPE BfProject_ClearDependencies(void* bfProject);
BF_IMPORT void BF_CALLTYPE BfProject_AddDependency(void* bfProject, void* depProject);
//////////////////////////////////////////////////////////////////////////
BF_IMPORT const char* BF_CALLTYPE BfPassInstance_PopOutString(void* bfPassInstance);
BF_IMPORT void BF_CALLTYPE BfPassInstance_Delete(void* bfPassInstance);
//////////////////////////////////////////////////////////////////////////
BF_IMPORT const char* BF_CALLTYPE VSSupport_Find();
//////////////////////////////////////////////////////////////////////////
USING_NS_BF;
BootApp* Beefy::gApp = NULL;
uint32 gConsoleFGColor = 0;
uint32 gConsoleBGColor = 0;
static bool GetConsoleColor(uint32& fgColor, uint32& bgColor)
{
#ifdef _WIN32
static uint32 consoleColors[16] = { 0xff000000, 0xff000080, 0xff008000, 0xff008080, 0xff800000, 0xff800080, 0xff808000, 0xffc0c0c0,
0xff808080, 0xff0000ff, 0xff00ff00, 0xff00ffff, 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff };
CONSOLE_SCREEN_BUFFER_INFO screenBuffInfo = { 0 };
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &screenBuffInfo);
fgColor = consoleColors[screenBuffInfo.wAttributes & 0xF];
bgColor = consoleColors[(screenBuffInfo.wAttributes >> 4) & 0xF];
return true;
#else
fgColor = 0xFF808080;
bgColor = 0xFF000000;
return false;
#endif
}
static WORD GetColorCode(uint32 color)
{
WORD code = 0;
#ifdef _WIN32
if (((color >> 0) & 0xFF) > 0x40)
code |= FOREGROUND_BLUE;
if (((color >> 8) & 0xFF) > 0x40)
code |= FOREGROUND_GREEN;
if (((color >> 16) & 0xFF) > 0x40)
code |= FOREGROUND_RED;
if ((((color >> 0) & 0xFF) > 0xC0) ||
(((color >> 8) & 0xFF) > 0xC0) ||
(((color >> 16) & 0xFF) > 0xC0))
code |= FOREGROUND_INTENSITY;
#endif
return code;
}
static bool SetConsoleColor(uint32 fgColor, uint32 bgColor)
{
#ifdef _WIN32
WORD attr = GetColorCode(fgColor) | (GetColorCode(bgColor) << 4);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), attr);
SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), attr);
return true;
#else
return false;
#endif
}
BootApp::BootApp()
{
Targets_Create();
mVerbosity = Verbosity_Normal;
mTargetType = BfTargetType_BeefConsoleApplication;
//char str[MAX_PATH];
//GetModuleFileNameA(NULL, str, MAX_PATH);
//mInstallDir = GetFileDir(str) + "/";
//getcwd(str, MAX_PATH);
//mStartupDir = str;
//mStartupDir += "/";
//mDoClean = false;
mHadCmdLine = false;
mShowedHelp = false;
mHadErrors = false;
mSystem = NULL;
mCompiler = NULL;
mProject = NULL;
mCELibProject = NULL;
mIsCERun = false;
mAsmKind = BfAsmKind_None;
mStartupObject = "Program";
2019-08-23 11:56:54 -07:00
#ifdef BF_PLATFORM_WINDOWS
mOptLevel = BfOptLevel_OgPlus;
mToolset = BfToolsetType_Microsoft;
#else
mOptLevel = BfOptLevel_O0;
mToolset = BfToolsetType_GNU;
#endif
mEmitIR = false;
#ifdef BF_PLATFORM_WINDOWS
mTargetTriple = "x86_64-pc-windows-msvc";
2019-10-15 17:27:09 -07:00
#elif defined BF_PLATFORM_MACOS
2020-04-27 05:44:46 -07:00
mTargetTriple = "x86_64-apple-macosx10.8.0";
#else
mTargetTriple = "x86_64-unknown-linux-gnu";
#endif
2019-08-23 11:56:54 -07:00
GetConsoleColor(gConsoleFGColor, gConsoleBGColor);
}
BootApp::~BootApp()
{
Targets_Delete();
}
void BootApp::OutputLine(const String& text, OutputPri outputPri)
{
if (mLogFile.IsOpen())
{
mLogFile.WriteSNZ(text);
mLogFile.WriteSNZ("\n");
}
if (outputPri == OutputPri_Error)
mHadErrors = true;
switch (outputPri)
{
case OutputPri_Low:
if (mVerbosity < Verbosity_Detailed)
return;
break;
case OutputPri_Normal:
if (mVerbosity < Verbosity_Normal)
return;
break;
case OutputPri_High:
case OutputPri_Warning:
case OutputPri_Error:
if (mVerbosity < Verbosity_Minimal)
return;
break;
default: break;
2019-08-23 11:56:54 -07:00
}
if (outputPri == OutputPri_Warning)
{
SetConsoleColor(0xFFFFFF00, gConsoleBGColor);
std::cerr << text.c_str() << std::endl;
SetConsoleColor(gConsoleFGColor, gConsoleBGColor);
}
else if (outputPri == OutputPri_Error)
{
SetConsoleColor(0xFFFF0000, gConsoleBGColor);
std::cerr << text.c_str() << std::endl;
SetConsoleColor(gConsoleFGColor, gConsoleBGColor);
}
else
std::cout << text.c_str() << std::endl;
}
void BootApp::Fail(const String& error)
{
if (mLogFile.IsOpen())
mLogFile.WriteSNZ("FAIL: " + error + "\n");
std::cerr << "FAIL: " << error.c_str() << std::endl;
mHadErrors = true;
}
bool BootApp::HandleCmdLine(const String &cmd, const String& param)
{
mHadCmdLine = true;
bool wantedParam = false;
if ((!cmd.StartsWith("-")) && (mIsCERun) && (mCESrc.IsEmpty()))
{
mCESrc = cmd;
return true;
}
if ((cmd == "-help") || (cmd == "-h") || (cmd == "/?"))
2019-08-23 11:56:54 -07:00
{
mShowedHelp = true;
std::cout << "BeefBoot - Beef bootstrapping tool" << std::endl;
return false;
}
else if (cmd == "-src")
2019-08-23 11:56:54 -07:00
{
mRequestedSrc.Add(param);
wantedParam = true;
}
else if (cmd == "-verbosity")
2019-08-23 11:56:54 -07:00
{
if (param == "quiet")
mVerbosity = Verbosity_Quiet;
else if (param == "minimal")
mVerbosity = Verbosity_Minimal;
else if (param == "normal")
mVerbosity = Verbosity_Normal;
else if (param == "detailed")
mVerbosity = Verbosity_Detailed;
else if (param == "diagnostic")
mVerbosity = Verbosity_Diagnostic;
else
{
Fail(StrFormat("Invalid verbosity level: '%s'", param.c_str()));
return false;
}
wantedParam = true;
}
else if (cmd == "-version")
{
BfpSystemResult sysResult;
String exePath;
BFP_GETSTR_HELPER(exePath, sysResult, BfpSystem_GetExecutablePath(__STR, __STRLEN, &sysResult));
std::cout << "0.0.0" << std::endl;
mShowedHelp = true;
return true;
}
else if (cmd == "-define")
2019-08-23 11:56:54 -07:00
{
if (!mDefines.IsEmpty())
mDefines += "\n";
mDefines += param;
wantedParam = true;
}
else if (cmd == "-startup")
2019-08-23 11:56:54 -07:00
{
mStartupObject = param;
wantedParam = true;
}
else if (cmd == "-out")
2019-08-23 11:56:54 -07:00
{
mTargetPath = param;
wantedParam = true;
}
else if (cmd == "-linkparams")
2019-08-23 11:56:54 -07:00
{
mLinkParams = param;
wantedParam = true;
}
else if (cmd == "-Og+")
{
mOptLevel = BfOptLevel_OgPlus;
}
else if (cmd == "-O0")
{
mOptLevel = BfOptLevel_O0;
}
else if (cmd == "-O1")
{
mOptLevel = BfOptLevel_O1;
}
else if (cmd == "-O2")
{
mOptLevel = BfOptLevel_O2;
}
else if (cmd == "-O3")
{
mOptLevel = BfOptLevel_O3;
}
else if (cmd == "-gnu")
{
mToolset = BfToolsetType_GNU;
}
else if (cmd == "-emitir")
{
mEmitIR = true;
}
else if (cmd == "-cedest")
{
mIsCERun = true;
mCEDest = param;
wantedParam = true;
}
else if (cmd == "-cesrc")
{
mIsCERun = true;
}
else if (cmd == "-emitasm")
{
if (param.IsEmpty())
{
mAsmKind = BfAsmKind_Intel;
}
else
{
if (param == "att")
mAsmKind = BfAsmKind_ATT;
else
mAsmKind = BfAsmKind_Intel;
wantedParam = true;
}
2019-08-23 11:56:54 -07:00
}
else
{
Fail("Unknown option: " + cmd);
return false;
}
if ((wantedParam) && (param.empty()))
{
Fail(StrFormat("Parameter expected for '%s'", cmd.c_str()));
return false;
}
else if ((!wantedParam) && (!param.empty()))
{
Fail(StrFormat("No parameter expected for '%s'", cmd.c_str()));
return false;
}
return true;
}
bool BootApp::Init()
{
char* cwdPtr = getcwd(NULL, 0);
mWorkingDir = cwdPtr;
free(cwdPtr);
if ((mTargetPath.IsEmpty()) && (mCESrc.IsEmpty()))
2019-08-23 11:56:54 -07:00
{
Fail("'Out' path not specified");
}
if (mRequestedSrc.IsEmpty())
{
Fail("No source specified");
}
return !mHadErrors;
}
void BootApp::QueueFile(const StringImpl& path, void* project)
2019-08-23 11:56:54 -07:00
{
String ext;
ext = GetFileExtension(path);
if ((ext.Equals(".bf", StringImpl::CompareKind_OrdinalIgnoreCase)) ||
(ext.Equals(".cs", StringImpl::CompareKind_OrdinalIgnoreCase)))
{
int len;
const char* data = LoadTextData(path, &len);
if (data == NULL)
{
Fail(StrFormat("Unable to load file '%s'", path.c_str()));
return;
}
bool worked = true;
void* bfParser = BfSystem_CreateParser(mSystem, project);
2019-08-23 11:56:54 -07:00
BfParser_SetSource(bfParser, data, len, path.c_str());
//bfParser.SetCharIdData(charIdData);
worked &= BfParser_Parse(bfParser, mPassInstance, false);
worked &= BfParser_Reduce(bfParser, mPassInstance);
worked &= BfParser_BuildDefs(bfParser, mPassInstance, NULL, false);
delete data;
}
}
void BootApp::QueuePath(const StringImpl& path)
{
if (DirectoryExists(path))
{
for (auto& fileEntry : FileEnumerator(path, FileEnumerator::Flags_Files))
{
String filePath = fileEntry.GetFilePath();
String fileName;
fileName = GetFileName(filePath);
QueueFile(filePath, (mCELibProject != NULL) ? mCELibProject : mProject);
2019-08-23 11:56:54 -07:00
}
for (auto& fileEntry : FileEnumerator(path, FileEnumerator::Flags_Directories))
{
String childPath = fileEntry.GetFilePath();
String dirName;
dirName = GetFileName(childPath);
if (dirName == "build")
continue;
QueuePath(childPath);
2019-08-23 11:56:54 -07:00
}
}
else
{
QueueFile(path, mProject);
2019-08-23 11:56:54 -07:00
}
}
static void CompileThread(void* param)
{
BfpThread_SetName(NULL, "CompileThread", NULL);
BootApp* app = (BootApp*)param;
BfCompiler_ClearBuildCache(app->mCompiler);
if (!BfCompiler_Compile(app->mCompiler, app->mPassInstance, app->mBuildDir.c_str()))
app->mHadErrors = true;
}
void BootApp::DoCompile()
{
#ifdef BFBUILD_MAIN_THREAD_COMPILE
mOutputDirectory = outputDirectory;
CompileThread(this);
#else
WorkThreadFunc workThread;
workThread.Start(CompileThread, this);
int lastProgressTicks = 0;
bool showProgress = mVerbosity >= Verbosity_Normal;
int progressSize = 30;
if (showProgress)
{
std::cout << "[";
for (int i = 0; i < progressSize; i++)
std::cout << " ";
std::cout << "]";
for (int i = 0; i < progressSize + 1; i++)
std::cout << "\b";
std::cout.flush();
}
while (true)
{
bool isDone = workThread.WaitForFinish(100);
float pct = BfCompiler_GetCompletionPercentage(mCompiler);
if (isDone)
pct = 1.0;
int progressTicks = (int)(pct * progressSize + 0.5f);
while (progressTicks > lastProgressTicks)
{
if (showProgress)
{
std::cout << "*";
std::cout.flush();
}
lastProgressTicks++;
}
if (isDone)
break;
}
if (showProgress)
std::cout << std::endl;
#endif
}
struct OutputContext
{
bool mIsError;
BfpFile* mFile;
};
static void OutputThread(void* param)
{
OutputContext* context = (OutputContext*)param;
String queuedStr;
while (true)
{
char data[1024];
BfpFileResult result;
int bytesRead = (int)BfpFile_Read(context->mFile, data, 1023, -1, &result);
if ((result != BfpFileResult_Ok) && (result != BfpFileResult_PartialData))
return;
data[bytesRead] = 0;
if (context->mIsError)
{
std::cerr << data;
std::cerr.flush();
}
else
{
std::cout << data;
std::cout.flush();
}
if (gApp->mLogFile.IsOpen())
{
// This is to ensure that error and output lines are not merged together, though they may interleave
queuedStr.Append(data, bytesRead);
while (true)
{
int crPos = (int)queuedStr.IndexOf('\n');
if (crPos == -1)
break;
AutoCrit autoCrit(gApp->mLogCritSect);
if (context->mIsError)
gApp->mLogFile.WriteSNZ("err> ");
else
gApp->mLogFile.WriteSNZ("out> ");
int endPos = crPos;
if ((endPos > 0) && (queuedStr[endPos - 1] == '\r'))
endPos--;
gApp->mLogFile.Write((void*)queuedStr.c_str(), endPos);
gApp->mLogFile.WriteSNZ("\n");
queuedStr.Remove(0, crPos + 1);
}
}
}
}
bool BootApp::QueueRun(const String& fileName, const String& args, const String& workingDir, BfpSpawnFlags extraFlags)
{
OutputLine(StrFormat("EXECUTING: %s %s", fileName.c_str(), args.c_str()), OutputPri_Low);
BfpSpawnFlags spawnFlags = (BfpSpawnFlags)(BfpSpawnFlag_NoWindow | BfpSpawnFlag_RedirectStdOutput | BfpSpawnFlag_RedirectStdError | extraFlags);
BfpSpawn* spawn = BfpSpawn_Create(fileName.c_str(), args.c_str(), workingDir.c_str(), NULL, spawnFlags, NULL);
if (spawn == NULL)
{
Fail(StrFormat("Failed to execute '%s'", fileName.c_str()));
return false;
}
int exitCode = 0;
OutputContext outputContext;;
outputContext.mIsError = false;
OutputContext errorContext;
errorContext.mIsError = false;
BfpSpawn_GetStdHandles(spawn, NULL, &outputContext.mFile, &errorContext.mFile);
BfpThread* outputThread = BfpThread_Create(OutputThread, (void*)&outputContext);
BfpThread* errorThread = BfpThread_Create(OutputThread, (void*)&errorContext);
BfpSpawn_WaitFor(spawn, -1, &exitCode, NULL);
if (outputContext.mFile != NULL)
BfpFile_Close(outputContext.mFile, NULL);
if (errorContext.mFile != NULL)
BfpFile_Close(errorContext.mFile, NULL);
BfpThread_WaitFor(outputThread, -1);
BfpThread_WaitFor(errorThread, -1);
BfpThread_Release(outputThread);
BfpThread_Release(errorThread);
BfpSpawn_Release(spawn);
if (exitCode != 0)
{
Fail(StrFormat("Exit code returned: %d", exitCode));
return false;
}
return true;
}
bool BootApp::CopyFile(const StringImpl& srcPath, const StringImpl& destPath)
{
BfpFileResult result = BfpFileResult_Ok;
for (int i = 0; i < 20; i++)
{
BfpFile_Copy(srcPath.c_str(), destPath.c_str(), BfpFileCopyKind_Always, &result);
if (result == BfpFileResult_Ok)
return true;
BfpThread_Sleep(100);
}
Fail(StrFormat("Failed to copy '%s' to '%s'", srcPath.c_str(), destPath.c_str()));
return false;
}
2019-08-23 11:56:54 -07:00
#ifdef BF_PLATFORM_WINDOWS
void BootApp::DoLinkMS()
{
String vsStr = VSSupport_Find();
int toolIdx = (int)vsStr.IndexOf("TOOL64\t");
int toolCrIdx = (int)vsStr.IndexOf('\n', toolIdx + 1);
if ((toolIdx == -1) || (toolCrIdx == -1))
{
Fail("Failed to detect Visual Studio configuration. Is Visual Studio 2015 or later installed?");
return;
}
String linkerPath = vsStr.Substring(toolIdx + 7, toolCrIdx - toolIdx - 7);
linkerPath.Append("\\link.exe");
String linkLine;
String targetPath = mTargetPath;
bool hadOutputChanges;
2022-05-13 13:37:00 -07:00
BfSystem_Lock(mSystem, 0);
2019-08-23 11:56:54 -07:00
const char* result = BfCompiler_GetUsedOutputFileNames(mCompiler, mProject, true, &hadOutputChanges);
2022-05-13 13:37:00 -07:00
BfSystem_Unlock(mSystem);
2019-08-23 11:56:54 -07:00
if (result == NULL)
return;
std::string fileNamesStr;
fileNamesStr += result;
if (fileNamesStr.length() == 0)
return;
int curIdx = -1;
while (curIdx < (int)fileNamesStr.length())
{
int nextBr = (int)fileNamesStr.find('\n', curIdx + 1);
if (nextBr == -1)
nextBr = (int)fileNamesStr.length();
linkLine.Append(fileNamesStr.substr(curIdx + 1, nextBr - curIdx - 1));
linkLine.Append(" ");
curIdx = nextBr;
}
linkLine.Append("-out:");
IDEUtils::AppendWithOptionalQuotes(linkLine, targetPath);
linkLine.Append(" ");
if (mTargetType == BfTargetType_BeefConsoleApplication)
linkLine.Append("-subsystem:console ");
else
linkLine.Append("-subsystem:windows ");
linkLine.Append("-defaultlib:libcmtd ");
linkLine.Append("-nologo ");
linkLine.Append("-pdb:");
int lastDotPos = (int)targetPath.LastIndexOf('.');
if (lastDotPos == -1)
lastDotPos = (int)targetPath.length();
auto pdbName = String(targetPath, 0, lastDotPos);
pdbName.Append(".pdb");
IDEUtils::AppendWithOptionalQuotes(linkLine, pdbName);
linkLine.Append(" ");
linkLine.Append("-debug ");
int checkIdx = 0;
while (true)
{
int libIdx = (int)vsStr.IndexOf("LIB64\t", checkIdx);
if (libIdx == -1)
break;
int libCrIdx = (int)vsStr.IndexOf('\n', libIdx + 1);
if (libCrIdx == -1)
break;
String libPath = vsStr.Substring(libIdx + 6, libCrIdx - libIdx - 6);
linkLine.Append("-libpath:\"");
linkLine.Append(libPath);
linkLine.Append("\" ");
checkIdx = libCrIdx + 1;
}
linkLine.Append(mLinkParams);
BfpSpawnFlags flags = BfpSpawnFlag_None;
flags = (BfpSpawnFlags)(BfpSpawnFlag_UseArgsFile | BfpSpawnFlag_UseArgsFile_Native | BfpSpawnFlag_UseArgsFile_BOM);
2019-08-23 11:56:54 -07:00
auto runCmd = QueueRun(linkerPath, linkLine, mWorkingDir, flags);
}
#endif
void BootApp::DoLinkGNU()
{
2020-05-21 06:58:26 -07:00
String linkerPath;
if (FileExists("/usr/bin/clang++"))
linkerPath = "/usr/bin/clang++";
else
linkerPath = "/usr/bin/c++";
2019-08-23 11:56:54 -07:00
String linkLine;
String targetPath = mTargetPath;
bool hadOutputChanges;
const char* result = BfCompiler_GetUsedOutputFileNames(mCompiler, mProject, true, &hadOutputChanges);
if (result == NULL)
return;
std::string fileNamesStr;
fileNamesStr += result;
if (fileNamesStr.length() == 0)
return;
int curIdx = -1;
while (curIdx < (int)fileNamesStr.length())
{
int nextBr = (int)fileNamesStr.find('\n', curIdx + 1);
if (nextBr == -1)
nextBr = (int)fileNamesStr.length();
linkLine.Append(fileNamesStr.substr(curIdx + 1, nextBr - curIdx - 1));
linkLine.Append(" ");
curIdx = nextBr;
}
linkLine.Append("-o ");
IDEUtils::AppendWithOptionalQuotes(linkLine, targetPath);
linkLine.Append(" ");
linkLine.Append("-g ");
linkLine.Append("-debug ");
#ifdef BF_PLATFORM_LINUX
linkLine.Append("-no-pie ");
#endif
2019-08-23 11:56:54 -07:00
linkLine.Append(mLinkParams);
auto runCmd = QueueRun(linkerPath, linkLine, mWorkingDir, BfpSpawnFlag_UseArgsFile);
2019-08-23 11:56:54 -07:00
}
bool BootApp::Compile()
{
DWORD startTick = BFTickCount();
mSystem = BfSystem_Create();
mCompiler = BfSystem_CreateCompiler(mSystem, false);
String projectName = GetFileName(mTargetPath);
int dotPos = (int)projectName.IndexOf('.');
if (dotPos != -1)
projectName.RemoveToEnd(dotPos);
if (projectName.IsEmpty())
projectName.Append("BeefProject");
2021-12-20 09:57:44 -05:00
mProject = BfSystem_CreateProject(mSystem, projectName.c_str(), GetFileDir(mTargetPath).c_str());
2019-08-23 11:56:54 -07:00
if (mIsCERun)
{
2021-12-20 09:57:44 -05:00
mCELibProject = BfSystem_CreateProject(mSystem, "BeefLib", GetFileDir(mTargetPath).c_str());
BfProjectFlags flags = BfProjectFlags_None;
BfProject_SetOptions(mCELibProject, BfTargetType_BeefLib, "", mDefines.c_str(), mOptLevel, 0, 0, 0, flags);
}
if (!mDefines.IsEmpty())
mDefines.Append("\n");
mDefines.Append("BF_64_BIT");
mDefines.Append("\nBF_LITTLE_ENDIAN");
2019-10-01 12:46:38 -07:00
mDefines.Append("\n");
mDefines.Append(BF_PLATFORM_NAME);
2019-08-23 11:56:54 -07:00
int ltoType = 0;
BfProjectFlags flags = BfProjectFlags_None;
if (mIsCERun)
{
flags = (BfProjectFlags)(flags | BfProjectFlags_SingleModule | BfProjectFlags_AlwaysIncludeAll);
if (mAsmKind == BfAsmKind_ATT)
flags = (BfProjectFlags)(flags | BfProjectFlags_AsmOutput | BfProjectFlags_AsmOutput_ATT);
else if (mAsmKind == BfAsmKind_Intel)
flags = (BfProjectFlags)(flags | BfProjectFlags_AsmOutput);
}
BfProject_SetOptions(mProject, mTargetType, mStartupObject.c_str(), mDefines.c_str(), mOptLevel, ltoType, 0, 0, flags);
if (mCELibProject != NULL)
BfProject_AddDependency(mProject, mCELibProject);
2019-08-23 11:56:54 -07:00
mPassInstance = BfSystem_CreatePassInstance(mSystem);
2019-08-23 11:56:54 -07:00
Beefy::String exePath;
BfpGetStrHelper(exePath, [](char* outStr, int* inOutStrSize, BfpResult* result)
{
BfpSystem_GetExecutablePath(outStr, inOutStrSize, (BfpSystemResult*)result);
});
mBuildDir = GetFileDir(exePath) + "/build";
RecursiveCreateDirectory(mBuildDir + "/" + projectName);
if (mIsCERun)
RecursiveCreateDirectory(mBuildDir + "/BeefLib");
2019-08-23 11:56:54 -07:00
BfCompilerOptionFlags optionFlags = (BfCompilerOptionFlags)(BfCompilerOptionFlag_EmitDebugInfo | BfCompilerOptionFlag_EmitLineInfo | BfCompilerOptionFlag_GenerateOBJ | BfCompilerOptionFlag_OmitDebugHelpers);
2019-08-23 11:56:54 -07:00
if (mEmitIR)
optionFlags = (BfCompilerOptionFlags)(optionFlags | BfCompilerOptionFlag_WriteIR);
int maxWorkerThreads = BfpSystem_GetNumLogicalCPUs(NULL);
if (maxWorkerThreads <= 1)
maxWorkerThreads = 6;
2022-01-25 07:12:47 -05:00
BfCompiler_SetOptions(mCompiler, NULL, 0, mTargetTriple.c_str(), "", mToolset, BfSIMDSetting_SSE2, 1, maxWorkerThreads, optionFlags, "malloc", "free");
2019-08-23 11:56:54 -07:00
if (mIsCERun)
{
QueueFile(mCESrc, mProject);
}
2019-08-23 11:56:54 -07:00
for (auto& srcName : mRequestedSrc)
{
String absPath = GetAbsPath(srcName, mWorkingDir);
QueuePath(absPath);
}
if (!mHadErrors)
{
DoCompile();
OutputLine(StrFormat("TIMING: Beef compiling: %0.1fs", (BFTickCount() - startTick) / 1000.0), OutputPri_Normal);
if (!mCEDest.IsEmpty())
{
String ext;
String srcResult = mBuildDir + "/BeefProject/BeefProject";
if (mAsmKind == BfAsmKind_None)
srcResult += BF_OBJ_EXT;
else
srcResult += ".s";
CopyFile(srcResult, mCEDest);
}
if ((mIsCERun) && (mEmitIR))
{
String ext;
String srcResult = mBuildDir + "/BeefProject/BeefProject";
String irDestPath = mCEDest;
int dotPos = (int)irDestPath.LastIndexOf('.');
if (dotPos != -1)
irDestPath.RemoveToEnd(dotPos);
if (mOptLevel == BfOptLevel_OgPlus)
{
srcResult += ".beir";
irDestPath += ".ll";
}
else
{
srcResult += ".ll";
irDestPath += ".ll";
}
CopyFile(srcResult, irDestPath);
}
2019-08-23 11:56:54 -07:00
}
while (true)
{
const char* msg = BfPassInstance_PopOutString(mPassInstance);
if (msg == NULL)
break;
if ((strncmp(msg, ":warn ", 6) == 0))
{
OutputLine(msg + 6, OutputPri_Warning);
}
else if ((strncmp(msg, ":error ", 7) == 0))
{
OutputLine(msg + 7, OutputPri_Error);
}
else if ((strncmp(msg, ":med ", 5) == 0))
{
OutputLine(msg + 5, OutputPri_Normal);
}
else if ((strncmp(msg, ":low ", 5) == 0))
{
OutputLine(msg + 5, OutputPri_Low);
}
else if ((strncmp(msg, "ERROR(", 6) == 0) || (strncmp(msg, "ERROR:", 6) == 0))
{
OutputLine(msg, OutputPri_Error);
}
else if ((strncmp(msg, "WARNING(", 8) == 0) || (strncmp(msg, "WARNING:", 8) == 0))
{
OutputLine(msg, OutputPri_Warning);
}
else
OutputLine(msg);
}
if ((!mHadErrors) && (!mTargetPath.IsEmpty()))
2019-08-23 11:56:54 -07:00
{
if (mVerbosity == Verbosity_Normal)
{
std::cout << "Linking " << mTargetPath.c_str() << "...";
std::cout.flush();
}
#ifdef BF_PLATFORM_WINDOWS
DoLinkMS();
#else
DoLinkGNU();
#endif
if (mVerbosity == Verbosity_Normal)
std::cout << std::endl;
}
BfPassInstance_Delete(mPassInstance);
BfCompiler_Delete(mCompiler);
BfSystem_Delete(mSystem);
return !mHadErrors;
}