BootApp.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965
  1. #pragma warning(disable:4996)
  2. //#define BFBUILD_MAIN_THREAD_COMPILE
  3. #include "BootApp.h"
  4. #include <iostream>
  5. #include "BeefySysLib/util/String.h"
  6. #include "BeefySysLib/util/FileEnumerator.h"
  7. #include "BeefySysLib/util/WorkThread.h"
  8. #include "BeefySysLib/platform/PlatformHelper.h"
  9. #include "Compiler/BfSystem.h"
  10. #ifdef BF_PLATFORM_WINDOWS
  11. #include <direct.h>
  12. #endif
  13. BF_IMPORT void BF_CALLTYPE Targets_Create();
  14. BF_IMPORT void BF_CALLTYPE Targets_Delete();
  15. BF_IMPORT void BF_CALLTYPE BfSystem_ReportMemory(void* bfSystem);
  16. BF_EXPORT void BF_CALLTYPE BfCompiler_ProgramDone();
  17. BF_IMPORT void BF_CALLTYPE Debugger_FullReportMemory();
  18. //////////////////////////////////////////////////////////////////////////
  19. BF_IMPORT void BF_CALLTYPE BfCompiler_Delete(void* bfCompiler);
  20. BF_EXPORT void BF_CALLTYPE BfCompiler_SetOptions(void* bfCompiler, void* hotProject, int hotIdx,
  21. const char* targetTriple, const char* targetCPU, int toolsetType, int simdSetting, int allocStackCount, int maxWorkerThreads,
  22. Beefy::BfCompilerOptionFlags optionFlags, const char* mallocLinkName, const char* freeLinkName);
  23. BF_IMPORT void BF_CALLTYPE BfCompiler_ClearBuildCache(void* bfCompiler);
  24. BF_IMPORT bool BF_CALLTYPE BfCompiler_Compile(void* bfCompiler, void* bfPassInstance, const char* outputPath);
  25. BF_IMPORT float BF_CALLTYPE BfCompiler_GetCompletionPercentage(void* bfCompiler);
  26. BF_IMPORT const char* BF_CALLTYPE BfCompiler_GetUsedOutputFileNames(void* bfCompiler, void* bfProject, bool flushQueuedHotFiles, bool* hadOutputChanges);
  27. BF_IMPORT void* BF_CALLTYPE BfSystem_CreateParser(void* bfSystem, void* bfProject);
  28. BF_IMPORT void BF_CALLTYPE BfParser_SetSource(void* bfParser, const char* data, int length, const char* fileName);
  29. BF_IMPORT void BF_CALLTYPE BfParser_SetCharIdData(void* bfParser, uint8* data, int length);
  30. BF_IMPORT bool BF_CALLTYPE BfParser_Parse(void* bfParser, void* bfPassInstance, bool compatMode);
  31. BF_IMPORT bool BF_CALLTYPE BfParser_Reduce(void* bfParser, void* bfPassInstance);
  32. BF_IMPORT bool BF_CALLTYPE BfParser_BuildDefs(void* bfParser, void* bfPassInstance, void* resolvePassData, bool fullRefresh);
  33. //////////////////////////////////////////////////////////////////////////
  34. BF_IMPORT void* BF_CALLTYPE BfSystem_Create();
  35. BF_EXPORT void BF_CALLTYPE BfSystem_Lock(void* bfSystem, int priority);
  36. BF_EXPORT void BF_CALLTYPE BfSystem_Unlock(void* bfSystem);
  37. BF_IMPORT void BF_CALLTYPE BfSystem_ReportMemory(void* bfSystem);
  38. BF_IMPORT void BF_CALLTYPE BfSystem_Delete(void* bfSystem);
  39. BF_IMPORT void* BF_CALLTYPE BfSystem_CreatePassInstance(void* bfSystem);
  40. BF_IMPORT void* BF_CALLTYPE BfSystem_CreateCompiler(void* bfSystem, bool isResolveOnly);
  41. BF_IMPORT void* BF_CALLTYPE BfSystem_CreateProject(void* bfSystem, const char* projectName, const char* projectDir);
  42. BF_IMPORT void BF_CALLTYPE BfParser_Delete(void* bfParser);
  43. BF_IMPORT void BF_CALLTYPE BfSystem_AddTypeOptions(void* bfSystem, const char* filter, int32 simdSetting, int32 optimizationLevel, int32 emitDebugInfo, int32 arrayBoundsCheck,
  44. int32 initLocalVariables, int32 emitDynamicCastCheck, int32 emitObjectAccessCheck, int32 allocStackTraceDepth);
  45. //////////////////////////////////////////////////////////////////////////
  46. BF_IMPORT void BF_CALLTYPE BfProject_SetDisabled(void* bfProject, bool disabled);
  47. BF_IMPORT void BF_CALLTYPE BfProject_SetOptions(void* bfProject, int targetType, const char* startupObject, const char* preprocessorMacros,
  48. int optLevel, int ltoType, int relocType, int picLevel, int32 flags);
  49. BF_IMPORT void BF_CALLTYPE BfProject_ClearDependencies(void* bfProject);
  50. BF_IMPORT void BF_CALLTYPE BfProject_AddDependency(void* bfProject, void* depProject);
  51. //////////////////////////////////////////////////////////////////////////
  52. BF_IMPORT const char* BF_CALLTYPE BfPassInstance_PopOutString(void* bfPassInstance);
  53. BF_IMPORT void BF_CALLTYPE BfPassInstance_Delete(void* bfPassInstance);
  54. //////////////////////////////////////////////////////////////////////////
  55. BF_IMPORT const char* BF_CALLTYPE VSSupport_Find();
  56. //////////////////////////////////////////////////////////////////////////
  57. USING_NS_BF;
  58. BootApp* Beefy::gApp = NULL;
  59. uint32 gConsoleFGColor = 0;
  60. uint32 gConsoleBGColor = 0;
  61. static bool GetConsoleColor(uint32& fgColor, uint32& bgColor)
  62. {
  63. #ifdef _WIN32
  64. static uint32 consoleColors[16] = { 0xff000000, 0xff000080, 0xff008000, 0xff008080, 0xff800000, 0xff800080, 0xff808000, 0xffc0c0c0,
  65. 0xff808080, 0xff0000ff, 0xff00ff00, 0xff00ffff, 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff };
  66. CONSOLE_SCREEN_BUFFER_INFO screenBuffInfo = { 0 };
  67. GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &screenBuffInfo);
  68. fgColor = consoleColors[screenBuffInfo.wAttributes & 0xF];
  69. bgColor = consoleColors[(screenBuffInfo.wAttributes >> 4) & 0xF];
  70. return true;
  71. #else
  72. fgColor = 0xFF808080;
  73. bgColor = 0xFF000000;
  74. return false;
  75. #endif
  76. }
  77. static WORD GetColorCode(uint32 color)
  78. {
  79. WORD code = 0;
  80. #ifdef _WIN32
  81. if (((color >> 0) & 0xFF) > 0x40)
  82. code |= FOREGROUND_BLUE;
  83. if (((color >> 8) & 0xFF) > 0x40)
  84. code |= FOREGROUND_GREEN;
  85. if (((color >> 16) & 0xFF) > 0x40)
  86. code |= FOREGROUND_RED;
  87. if ((((color >> 0) & 0xFF) > 0xC0) ||
  88. (((color >> 8) & 0xFF) > 0xC0) ||
  89. (((color >> 16) & 0xFF) > 0xC0))
  90. code |= FOREGROUND_INTENSITY;
  91. #endif
  92. return code;
  93. }
  94. static bool SetConsoleColor(uint32 fgColor, uint32 bgColor)
  95. {
  96. #ifdef _WIN32
  97. WORD attr = GetColorCode(fgColor) | (GetColorCode(bgColor) << 4);
  98. SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), attr);
  99. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), attr);
  100. return true;
  101. #else
  102. return false;
  103. #endif
  104. }
  105. BootApp::BootApp()
  106. {
  107. Targets_Create();
  108. mVerbosity = Verbosity_Normal;
  109. mTargetType = BfTargetType_BeefConsoleApplication;
  110. //char str[MAX_PATH];
  111. //GetModuleFileNameA(NULL, str, MAX_PATH);
  112. //mInstallDir = GetFileDir(str) + "/";
  113. //getcwd(str, MAX_PATH);
  114. //mStartupDir = str;
  115. //mStartupDir += "/";
  116. //mDoClean = false;
  117. mHadCmdLine = false;
  118. mShowedHelp = false;
  119. mHadErrors = false;
  120. mSystem = NULL;
  121. mCompiler = NULL;
  122. mProject = NULL;
  123. mCELibProject = NULL;
  124. mIsCERun = false;
  125. mAsmKind = BfAsmKind_None;
  126. mStartupObject = "Program";
  127. #ifdef BF_PLATFORM_WINDOWS
  128. mOptLevel = BfOptLevel_OgPlus;
  129. mToolset = BfToolsetType_Microsoft;
  130. #else
  131. mOptLevel = BfOptLevel_O0;
  132. mToolset = BfToolsetType_GNU;
  133. #endif
  134. mEmitIR = false;
  135. #ifdef BF_PLATFORM_WINDOWS
  136. mTargetTriple = "x86_64-pc-windows-msvc";
  137. #elif defined BF_PLATFORM_MACOS
  138. mTargetTriple = "x86_64-apple-macosx10.8.0";
  139. #else
  140. mTargetTriple = "x86_64-unknown-linux-gnu";
  141. #endif
  142. GetConsoleColor(gConsoleFGColor, gConsoleBGColor);
  143. }
  144. BootApp::~BootApp()
  145. {
  146. Targets_Delete();
  147. }
  148. void BootApp::OutputLine(const String& text, OutputPri outputPri)
  149. {
  150. if (mLogFile.IsOpen())
  151. {
  152. mLogFile.WriteSNZ(text);
  153. mLogFile.WriteSNZ("\n");
  154. }
  155. if (outputPri == OutputPri_Error)
  156. mHadErrors = true;
  157. switch (outputPri)
  158. {
  159. case OutputPri_Low:
  160. if (mVerbosity < Verbosity_Detailed)
  161. return;
  162. break;
  163. case OutputPri_Normal:
  164. if (mVerbosity < Verbosity_Normal)
  165. return;
  166. break;
  167. case OutputPri_High:
  168. case OutputPri_Warning:
  169. case OutputPri_Error:
  170. if (mVerbosity < Verbosity_Minimal)
  171. return;
  172. break;
  173. default: break;
  174. }
  175. if (outputPri == OutputPri_Warning)
  176. {
  177. SetConsoleColor(0xFFFFFF00, gConsoleBGColor);
  178. std::cerr << text.c_str() << std::endl;
  179. SetConsoleColor(gConsoleFGColor, gConsoleBGColor);
  180. }
  181. else if (outputPri == OutputPri_Error)
  182. {
  183. SetConsoleColor(0xFFFF0000, gConsoleBGColor);
  184. std::cerr << text.c_str() << std::endl;
  185. SetConsoleColor(gConsoleFGColor, gConsoleBGColor);
  186. }
  187. else
  188. std::cout << text.c_str() << std::endl;
  189. }
  190. void BootApp::Fail(const String& error)
  191. {
  192. if (mLogFile.IsOpen())
  193. mLogFile.WriteSNZ("FAIL: " + error + "\n");
  194. std::cerr << "FAIL: " << error.c_str() << std::endl;
  195. mHadErrors = true;
  196. }
  197. bool BootApp::HandleCmdLine(const String &cmd, const String& param)
  198. {
  199. mHadCmdLine = true;
  200. bool wantedParam = false;
  201. if ((!cmd.StartsWith("-")) && (mIsCERun) && (mCESrc.IsEmpty()))
  202. {
  203. mCESrc = cmd;
  204. return true;
  205. }
  206. if ((cmd == "-help") || (cmd == "-h") || (cmd == "/?"))
  207. {
  208. mShowedHelp = true;
  209. std::cout << "BeefBoot - Beef bootstrapping tool" << std::endl;
  210. return false;
  211. }
  212. else if (cmd == "-src")
  213. {
  214. mRequestedSrc.Add(param);
  215. wantedParam = true;
  216. }
  217. else if (cmd == "-verbosity")
  218. {
  219. if (param == "quiet")
  220. mVerbosity = Verbosity_Quiet;
  221. else if (param == "minimal")
  222. mVerbosity = Verbosity_Minimal;
  223. else if (param == "normal")
  224. mVerbosity = Verbosity_Normal;
  225. else if (param == "detailed")
  226. mVerbosity = Verbosity_Detailed;
  227. else if (param == "diagnostic")
  228. mVerbosity = Verbosity_Diagnostic;
  229. else
  230. {
  231. Fail(StrFormat("Invalid verbosity level: '%s'", param.c_str()));
  232. return false;
  233. }
  234. wantedParam = true;
  235. }
  236. else if (cmd == "-version")
  237. {
  238. BfpSystemResult sysResult;
  239. String exePath;
  240. BFP_GETSTR_HELPER(exePath, sysResult, BfpSystem_GetExecutablePath(__STR, __STRLEN, &sysResult));
  241. std::cout << "0.0.0" << std::endl;
  242. mShowedHelp = true;
  243. return true;
  244. }
  245. else if (cmd == "-define")
  246. {
  247. if (!mDefines.IsEmpty())
  248. mDefines += "\n";
  249. mDefines += param;
  250. wantedParam = true;
  251. }
  252. else if (cmd == "-startup")
  253. {
  254. mStartupObject = param;
  255. wantedParam = true;
  256. }
  257. else if (cmd == "-out")
  258. {
  259. mTargetPath = param;
  260. wantedParam = true;
  261. }
  262. else if (cmd == "-linkparams")
  263. {
  264. mLinkParams = param;
  265. wantedParam = true;
  266. }
  267. else if (cmd == "-Og+")
  268. {
  269. mOptLevel = BfOptLevel_OgPlus;
  270. }
  271. else if (cmd == "-O0")
  272. {
  273. mOptLevel = BfOptLevel_O0;
  274. }
  275. else if (cmd == "-O1")
  276. {
  277. mOptLevel = BfOptLevel_O1;
  278. }
  279. else if (cmd == "-O2")
  280. {
  281. mOptLevel = BfOptLevel_O2;
  282. }
  283. else if (cmd == "-O3")
  284. {
  285. mOptLevel = BfOptLevel_O3;
  286. }
  287. else if (cmd == "-gnu")
  288. {
  289. mToolset = BfToolsetType_GNU;
  290. }
  291. else if (cmd == "-emitir")
  292. {
  293. mEmitIR = true;
  294. }
  295. else if (cmd == "-cedest")
  296. {
  297. mIsCERun = true;
  298. mCEDest = param;
  299. wantedParam = true;
  300. }
  301. else if (cmd == "-cesrc")
  302. {
  303. mIsCERun = true;
  304. }
  305. else if (cmd == "-emitasm")
  306. {
  307. if (param.IsEmpty())
  308. {
  309. mAsmKind = BfAsmKind_Intel;
  310. }
  311. else
  312. {
  313. if (param == "att")
  314. mAsmKind = BfAsmKind_ATT;
  315. else
  316. mAsmKind = BfAsmKind_Intel;
  317. wantedParam = true;
  318. }
  319. }
  320. else
  321. {
  322. Fail("Unknown option: " + cmd);
  323. return false;
  324. }
  325. if ((wantedParam) && (param.empty()))
  326. {
  327. Fail(StrFormat("Parameter expected for '%s'", cmd.c_str()));
  328. return false;
  329. }
  330. else if ((!wantedParam) && (!param.empty()))
  331. {
  332. Fail(StrFormat("No parameter expected for '%s'", cmd.c_str()));
  333. return false;
  334. }
  335. return true;
  336. }
  337. bool BootApp::Init()
  338. {
  339. char* cwdPtr = getcwd(NULL, 0);
  340. mWorkingDir = cwdPtr;
  341. free(cwdPtr);
  342. if ((mTargetPath.IsEmpty()) && (mCESrc.IsEmpty()))
  343. {
  344. Fail("'Out' path not specified");
  345. }
  346. if (mRequestedSrc.IsEmpty())
  347. {
  348. Fail("No source specified");
  349. }
  350. return !mHadErrors;
  351. }
  352. void BootApp::QueueFile(const StringImpl& path, void* project)
  353. {
  354. String ext;
  355. ext = GetFileExtension(path);
  356. if ((ext.Equals(".bf", StringImpl::CompareKind_OrdinalIgnoreCase)) ||
  357. (ext.Equals(".cs", StringImpl::CompareKind_OrdinalIgnoreCase)))
  358. {
  359. int len;
  360. const char* data = LoadTextData(path, &len);
  361. if (data == NULL)
  362. {
  363. Fail(StrFormat("Unable to load file '%s'", path.c_str()));
  364. return;
  365. }
  366. bool worked = true;
  367. void* bfParser = BfSystem_CreateParser(mSystem, project);
  368. BfParser_SetSource(bfParser, data, len, path.c_str());
  369. //bfParser.SetCharIdData(charIdData);
  370. worked &= BfParser_Parse(bfParser, mPassInstance, false);
  371. worked &= BfParser_Reduce(bfParser, mPassInstance);
  372. worked &= BfParser_BuildDefs(bfParser, mPassInstance, NULL, false);
  373. delete data;
  374. }
  375. }
  376. void BootApp::QueuePath(const StringImpl& path)
  377. {
  378. if (DirectoryExists(path))
  379. {
  380. for (auto& fileEntry : FileEnumerator(path, FileEnumerator::Flags_Files))
  381. {
  382. String filePath = fileEntry.GetFilePath();
  383. String fileName;
  384. fileName = GetFileName(filePath);
  385. QueueFile(filePath, (mCELibProject != NULL) ? mCELibProject : mProject);
  386. }
  387. for (auto& fileEntry : FileEnumerator(path, FileEnumerator::Flags_Directories))
  388. {
  389. String childPath = fileEntry.GetFilePath();
  390. String dirName;
  391. dirName = GetFileName(childPath);
  392. if (dirName == "build")
  393. continue;
  394. QueuePath(childPath);
  395. }
  396. }
  397. else
  398. {
  399. QueueFile(path, mProject);
  400. }
  401. }
  402. static void CompileThread(void* param)
  403. {
  404. BfpThread_SetName(NULL, "CompileThread", NULL);
  405. BootApp* app = (BootApp*)param;
  406. BfCompiler_ClearBuildCache(app->mCompiler);
  407. if (!BfCompiler_Compile(app->mCompiler, app->mPassInstance, app->mBuildDir.c_str()))
  408. app->mHadErrors = true;
  409. }
  410. void BootApp::DoCompile()
  411. {
  412. #ifdef BFBUILD_MAIN_THREAD_COMPILE
  413. mOutputDirectory = outputDirectory;
  414. CompileThread(this);
  415. #else
  416. WorkThreadFunc workThread;
  417. workThread.Start(CompileThread, this);
  418. int lastProgressTicks = 0;
  419. bool showProgress = mVerbosity >= Verbosity_Normal;
  420. int progressSize = 30;
  421. if (showProgress)
  422. {
  423. std::cout << "[";
  424. for (int i = 0; i < progressSize; i++)
  425. std::cout << " ";
  426. std::cout << "]";
  427. for (int i = 0; i < progressSize + 1; i++)
  428. std::cout << "\b";
  429. std::cout.flush();
  430. }
  431. while (true)
  432. {
  433. bool isDone = workThread.WaitForFinish(100);
  434. float pct = BfCompiler_GetCompletionPercentage(mCompiler);
  435. if (isDone)
  436. pct = 1.0;
  437. int progressTicks = (int)(pct * progressSize + 0.5f);
  438. while (progressTicks > lastProgressTicks)
  439. {
  440. if (showProgress)
  441. {
  442. std::cout << "*";
  443. std::cout.flush();
  444. }
  445. lastProgressTicks++;
  446. }
  447. if (isDone)
  448. break;
  449. }
  450. if (showProgress)
  451. std::cout << std::endl;
  452. #endif
  453. }
  454. struct OutputContext
  455. {
  456. bool mIsError;
  457. BfpFile* mFile;
  458. };
  459. static void OutputThread(void* param)
  460. {
  461. OutputContext* context = (OutputContext*)param;
  462. String queuedStr;
  463. while (true)
  464. {
  465. char data[1024];
  466. BfpFileResult result;
  467. int bytesRead = (int)BfpFile_Read(context->mFile, data, 1023, -1, &result);
  468. if ((result != BfpFileResult_Ok) && (result != BfpFileResult_PartialData))
  469. return;
  470. data[bytesRead] = 0;
  471. if (context->mIsError)
  472. {
  473. std::cerr << data;
  474. std::cerr.flush();
  475. }
  476. else
  477. {
  478. std::cout << data;
  479. std::cout.flush();
  480. }
  481. if (gApp->mLogFile.IsOpen())
  482. {
  483. // This is to ensure that error and output lines are not merged together, though they may interleave
  484. queuedStr.Append(data, bytesRead);
  485. while (true)
  486. {
  487. int crPos = (int)queuedStr.IndexOf('\n');
  488. if (crPos == -1)
  489. break;
  490. AutoCrit autoCrit(gApp->mLogCritSect);
  491. if (context->mIsError)
  492. gApp->mLogFile.WriteSNZ("err> ");
  493. else
  494. gApp->mLogFile.WriteSNZ("out> ");
  495. int endPos = crPos;
  496. if ((endPos > 0) && (queuedStr[endPos - 1] == '\r'))
  497. endPos--;
  498. gApp->mLogFile.Write((void*)queuedStr.c_str(), endPos);
  499. gApp->mLogFile.WriteSNZ("\n");
  500. queuedStr.Remove(0, crPos + 1);
  501. }
  502. }
  503. }
  504. }
  505. bool BootApp::QueueRun(const String& fileName, const String& args, const String& workingDir, BfpSpawnFlags extraFlags)
  506. {
  507. OutputLine(StrFormat("EXECUTING: %s %s", fileName.c_str(), args.c_str()), OutputPri_Low);
  508. BfpSpawnFlags spawnFlags = (BfpSpawnFlags)(BfpSpawnFlag_NoWindow | BfpSpawnFlag_RedirectStdOutput | BfpSpawnFlag_RedirectStdError | extraFlags);
  509. BfpSpawn* spawn = BfpSpawn_Create(fileName.c_str(), args.c_str(), workingDir.c_str(), NULL, spawnFlags, NULL);
  510. if (spawn == NULL)
  511. {
  512. Fail(StrFormat("Failed to execute '%s'", fileName.c_str()));
  513. return false;
  514. }
  515. int exitCode = 0;
  516. OutputContext outputContext;;
  517. outputContext.mIsError = false;
  518. OutputContext errorContext;
  519. errorContext.mIsError = false;
  520. BfpSpawn_GetStdHandles(spawn, NULL, &outputContext.mFile, &errorContext.mFile);
  521. BfpThread* outputThread = BfpThread_Create(OutputThread, (void*)&outputContext);
  522. BfpThread* errorThread = BfpThread_Create(OutputThread, (void*)&errorContext);
  523. BfpSpawn_WaitFor(spawn, -1, &exitCode, NULL);
  524. if (outputContext.mFile != NULL)
  525. BfpFile_Close(outputContext.mFile, NULL);
  526. if (errorContext.mFile != NULL)
  527. BfpFile_Close(errorContext.mFile, NULL);
  528. BfpThread_WaitFor(outputThread, -1);
  529. BfpThread_WaitFor(errorThread, -1);
  530. BfpThread_Release(outputThread);
  531. BfpThread_Release(errorThread);
  532. BfpSpawn_Release(spawn);
  533. if (exitCode != 0)
  534. {
  535. Fail(StrFormat("Exit code returned: %d", exitCode));
  536. return false;
  537. }
  538. return true;
  539. }
  540. bool BootApp::CopyFile(const StringImpl& srcPath, const StringImpl& destPath)
  541. {
  542. BfpFileResult result = BfpFileResult_Ok;
  543. for (int i = 0; i < 20; i++)
  544. {
  545. BfpFile_Copy(srcPath.c_str(), destPath.c_str(), BfpFileCopyKind_Always, &result);
  546. if (result == BfpFileResult_Ok)
  547. return true;
  548. BfpThread_Sleep(100);
  549. }
  550. Fail(StrFormat("Failed to copy '%s' to '%s'", srcPath.c_str(), destPath.c_str()));
  551. return false;
  552. }
  553. #ifdef BF_PLATFORM_WINDOWS
  554. void BootApp::DoLinkMS()
  555. {
  556. String vsStr = VSSupport_Find();
  557. int toolIdx = (int)vsStr.IndexOf("TOOL64\t");
  558. int toolCrIdx = (int)vsStr.IndexOf('\n', toolIdx + 1);
  559. if ((toolIdx == -1) || (toolCrIdx == -1))
  560. {
  561. Fail("Failed to detect Visual Studio configuration. Is Visual Studio 2015 or later installed?");
  562. return;
  563. }
  564. String linkerPath = vsStr.Substring(toolIdx + 7, toolCrIdx - toolIdx - 7);
  565. linkerPath.Append("\\link.exe");
  566. String linkLine;
  567. String targetPath = mTargetPath;
  568. bool hadOutputChanges;
  569. BfSystem_Lock(mSystem, 0);
  570. const char* result = BfCompiler_GetUsedOutputFileNames(mCompiler, mProject, true, &hadOutputChanges);
  571. BfSystem_Unlock(mSystem);
  572. if (result == NULL)
  573. return;
  574. std::string fileNamesStr;
  575. fileNamesStr += result;
  576. if (fileNamesStr.length() == 0)
  577. return;
  578. int curIdx = -1;
  579. while (curIdx < (int)fileNamesStr.length())
  580. {
  581. int nextBr = (int)fileNamesStr.find('\n', curIdx + 1);
  582. if (nextBr == -1)
  583. nextBr = (int)fileNamesStr.length();
  584. linkLine.Append(fileNamesStr.substr(curIdx + 1, nextBr - curIdx - 1));
  585. linkLine.Append(" ");
  586. curIdx = nextBr;
  587. }
  588. linkLine.Append("-out:");
  589. IDEUtils::AppendWithOptionalQuotes(linkLine, targetPath);
  590. linkLine.Append(" ");
  591. if (mTargetType == BfTargetType_BeefConsoleApplication)
  592. linkLine.Append("-subsystem:console ");
  593. else
  594. linkLine.Append("-subsystem:windows ");
  595. linkLine.Append("-defaultlib:libcmtd ");
  596. linkLine.Append("-nologo ");
  597. linkLine.Append("-pdb:");
  598. int lastDotPos = (int)targetPath.LastIndexOf('.');
  599. if (lastDotPos == -1)
  600. lastDotPos = (int)targetPath.length();
  601. auto pdbName = String(targetPath, 0, lastDotPos);
  602. pdbName.Append(".pdb");
  603. IDEUtils::AppendWithOptionalQuotes(linkLine, pdbName);
  604. linkLine.Append(" ");
  605. linkLine.Append("-debug ");
  606. int checkIdx = 0;
  607. while (true)
  608. {
  609. int libIdx = (int)vsStr.IndexOf("LIB64\t", checkIdx);
  610. if (libIdx == -1)
  611. break;
  612. int libCrIdx = (int)vsStr.IndexOf('\n', libIdx + 1);
  613. if (libCrIdx == -1)
  614. break;
  615. String libPath = vsStr.Substring(libIdx + 6, libCrIdx - libIdx - 6);
  616. linkLine.Append("-libpath:\"");
  617. linkLine.Append(libPath);
  618. linkLine.Append("\" ");
  619. checkIdx = libCrIdx + 1;
  620. }
  621. linkLine.Append(mLinkParams);
  622. BfpSpawnFlags flags = BfpSpawnFlag_None;
  623. flags = (BfpSpawnFlags)(BfpSpawnFlag_UseArgsFile | BfpSpawnFlag_UseArgsFile_Native | BfpSpawnFlag_UseArgsFile_BOM);
  624. auto runCmd = QueueRun(linkerPath, linkLine, mWorkingDir, flags);
  625. }
  626. #endif
  627. void BootApp::DoLinkGNU()
  628. {
  629. String linkerPath;
  630. if (FileExists("/usr/bin/clang++"))
  631. linkerPath = "/usr/bin/clang++";
  632. else
  633. linkerPath = "/usr/bin/c++";
  634. String linkLine;
  635. String targetPath = mTargetPath;
  636. bool hadOutputChanges;
  637. const char* result = BfCompiler_GetUsedOutputFileNames(mCompiler, mProject, true, &hadOutputChanges);
  638. if (result == NULL)
  639. return;
  640. std::string fileNamesStr;
  641. fileNamesStr += result;
  642. if (fileNamesStr.length() == 0)
  643. return;
  644. int curIdx = -1;
  645. while (curIdx < (int)fileNamesStr.length())
  646. {
  647. int nextBr = (int)fileNamesStr.find('\n', curIdx + 1);
  648. if (nextBr == -1)
  649. nextBr = (int)fileNamesStr.length();
  650. linkLine.Append(fileNamesStr.substr(curIdx + 1, nextBr - curIdx - 1));
  651. linkLine.Append(" ");
  652. curIdx = nextBr;
  653. }
  654. linkLine.Append("-o ");
  655. IDEUtils::AppendWithOptionalQuotes(linkLine, targetPath);
  656. linkLine.Append(" ");
  657. linkLine.Append("-g ");
  658. linkLine.Append("-debug ");
  659. #ifdef BF_PLATFORM_LINUX
  660. linkLine.Append("-no-pie ");
  661. #endif
  662. linkLine.Append(mLinkParams);
  663. auto runCmd = QueueRun(linkerPath, linkLine, mWorkingDir, BfpSpawnFlag_UseArgsFile);
  664. }
  665. bool BootApp::Compile()
  666. {
  667. DWORD startTick = BFTickCount();
  668. mSystem = BfSystem_Create();
  669. mCompiler = BfSystem_CreateCompiler(mSystem, false);
  670. String projectName = GetFileName(mTargetPath);
  671. int dotPos = (int)projectName.IndexOf('.');
  672. if (dotPos != -1)
  673. projectName.RemoveToEnd(dotPos);
  674. if (projectName.IsEmpty())
  675. projectName.Append("BeefProject");
  676. mProject = BfSystem_CreateProject(mSystem, projectName.c_str(), GetFileDir(mTargetPath).c_str());
  677. if (mIsCERun)
  678. {
  679. mCELibProject = BfSystem_CreateProject(mSystem, "BeefLib", GetFileDir(mTargetPath).c_str());
  680. BfProjectFlags flags = BfProjectFlags_None;
  681. BfProject_SetOptions(mCELibProject, BfTargetType_BeefLib, "", mDefines.c_str(), mOptLevel, 0, 0, 0, flags);
  682. }
  683. if (!mDefines.IsEmpty())
  684. mDefines.Append("\n");
  685. mDefines.Append("BF_64_BIT");
  686. mDefines.Append("\nBF_LITTLE_ENDIAN");
  687. mDefines.Append("\n");
  688. mDefines.Append(BF_PLATFORM_NAME);
  689. int ltoType = 0;
  690. BfProjectFlags flags = BfProjectFlags_None;
  691. if (mIsCERun)
  692. {
  693. flags = (BfProjectFlags)(flags | BfProjectFlags_SingleModule | BfProjectFlags_AlwaysIncludeAll);
  694. if (mAsmKind == BfAsmKind_ATT)
  695. flags = (BfProjectFlags)(flags | BfProjectFlags_AsmOutput | BfProjectFlags_AsmOutput_ATT);
  696. else if (mAsmKind == BfAsmKind_Intel)
  697. flags = (BfProjectFlags)(flags | BfProjectFlags_AsmOutput);
  698. }
  699. BfProject_SetOptions(mProject, mTargetType, mStartupObject.c_str(), mDefines.c_str(), mOptLevel, ltoType, 0, 0, flags);
  700. if (mCELibProject != NULL)
  701. BfProject_AddDependency(mProject, mCELibProject);
  702. mPassInstance = BfSystem_CreatePassInstance(mSystem);
  703. Beefy::String exePath;
  704. BfpGetStrHelper(exePath, [](char* outStr, int* inOutStrSize, BfpResult* result)
  705. {
  706. BfpSystem_GetExecutablePath(outStr, inOutStrSize, (BfpSystemResult*)result);
  707. });
  708. mBuildDir = GetFileDir(exePath) + "/build";
  709. RecursiveCreateDirectory(mBuildDir + "/" + projectName);
  710. if (mIsCERun)
  711. RecursiveCreateDirectory(mBuildDir + "/BeefLib");
  712. BfCompilerOptionFlags optionFlags = (BfCompilerOptionFlags)(BfCompilerOptionFlag_EmitDebugInfo | BfCompilerOptionFlag_EmitLineInfo | BfCompilerOptionFlag_GenerateOBJ | BfCompilerOptionFlag_OmitDebugHelpers);
  713. if (mEmitIR)
  714. optionFlags = (BfCompilerOptionFlags)(optionFlags | BfCompilerOptionFlag_WriteIR);
  715. int maxWorkerThreads = BfpSystem_GetNumLogicalCPUs(NULL);
  716. if (maxWorkerThreads <= 1)
  717. maxWorkerThreads = 6;
  718. BfCompiler_SetOptions(mCompiler, NULL, 0, mTargetTriple.c_str(), "", mToolset, BfSIMDSetting_SSE2, 1, maxWorkerThreads, optionFlags, "malloc", "free");
  719. if (mIsCERun)
  720. {
  721. QueueFile(mCESrc, mProject);
  722. }
  723. for (auto& srcName : mRequestedSrc)
  724. {
  725. String absPath = GetAbsPath(srcName, mWorkingDir);
  726. QueuePath(absPath);
  727. }
  728. if (!mHadErrors)
  729. {
  730. DoCompile();
  731. OutputLine(StrFormat("TIMING: Beef compiling: %0.1fs", (BFTickCount() - startTick) / 1000.0), OutputPri_Normal);
  732. if (!mCEDest.IsEmpty())
  733. {
  734. String ext;
  735. String srcResult = mBuildDir + "/BeefProject/BeefProject";
  736. if (mAsmKind == BfAsmKind_None)
  737. srcResult += BF_OBJ_EXT;
  738. else
  739. srcResult += ".s";
  740. CopyFile(srcResult, mCEDest);
  741. }
  742. if ((mIsCERun) && (mEmitIR))
  743. {
  744. String ext;
  745. String srcResult = mBuildDir + "/BeefProject/BeefProject";
  746. String irDestPath = mCEDest;
  747. int dotPos = (int)irDestPath.LastIndexOf('.');
  748. if (dotPos != -1)
  749. irDestPath.RemoveToEnd(dotPos);
  750. if (mOptLevel == BfOptLevel_OgPlus)
  751. {
  752. srcResult += ".beir";
  753. irDestPath += ".ll";
  754. }
  755. else
  756. {
  757. srcResult += ".ll";
  758. irDestPath += ".ll";
  759. }
  760. CopyFile(srcResult, irDestPath);
  761. }
  762. }
  763. while (true)
  764. {
  765. const char* msg = BfPassInstance_PopOutString(mPassInstance);
  766. if (msg == NULL)
  767. break;
  768. if ((strncmp(msg, ":warn ", 6) == 0))
  769. {
  770. OutputLine(msg + 6, OutputPri_Warning);
  771. }
  772. else if ((strncmp(msg, ":error ", 7) == 0))
  773. {
  774. OutputLine(msg + 7, OutputPri_Error);
  775. }
  776. else if ((strncmp(msg, ":med ", 5) == 0))
  777. {
  778. OutputLine(msg + 5, OutputPri_Normal);
  779. }
  780. else if ((strncmp(msg, ":low ", 5) == 0))
  781. {
  782. OutputLine(msg + 5, OutputPri_Low);
  783. }
  784. else if ((strncmp(msg, "ERROR(", 6) == 0) || (strncmp(msg, "ERROR:", 6) == 0))
  785. {
  786. OutputLine(msg, OutputPri_Error);
  787. }
  788. else if ((strncmp(msg, "WARNING(", 8) == 0) || (strncmp(msg, "WARNING:", 8) == 0))
  789. {
  790. OutputLine(msg, OutputPri_Warning);
  791. }
  792. else
  793. OutputLine(msg);
  794. }
  795. if ((!mHadErrors) && (!mTargetPath.IsEmpty()))
  796. {
  797. if (mVerbosity == Verbosity_Normal)
  798. {
  799. std::cout << "Linking " << mTargetPath.c_str() << "...";
  800. std::cout.flush();
  801. }
  802. #ifdef BF_PLATFORM_WINDOWS
  803. DoLinkMS();
  804. #else
  805. DoLinkGNU();
  806. #endif
  807. if (mVerbosity == Verbosity_Normal)
  808. std::cout << std::endl;
  809. }
  810. BfPassInstance_Delete(mPassInstance);
  811. BfCompiler_Delete(mCompiler);
  812. BfSystem_Delete(mSystem);
  813. return !mHadErrors;
  814. }