1 // =================================
   2 // Copyright (c) 2021 Seppo Laakko
   3 // Distributed under the MIT license
   4 // =================================
   5 
   6 #include <cmajor/build/Build.hpp>
   7 #include <cmajor/build/MessageBody.hpp>
   8 #include <cmajor/cmtoolchain/ToolChains.hpp>
   9 #include <cmajor/codegen/EmittingContext.hpp>
  10 #include <cmajor/codegen/Interface.hpp>
  11 #include <cmajor/cmtoolchain/ToolChains.hpp>
  12 #include <soulng/lexer/XmlParsingLog.hpp>
  13 #include <sngcm/cmlexer/ContainerFileLexer.hpp>
  14 #include <sngcm/cmlexer/CmajorLexer.hpp>
  15 #include <sngcm/cmparser/ProjectFile.hpp>
  16 #include <sngcm/cmparser/SolutionFile.hpp>
  17 #include <sngcm/cmparser/CompileUnit.hpp>
  18 #include <sngxml/dom/Document.hpp>
  19 #include <sngxml/dom/Element.hpp>
  20 #include <sngxml/dom/Parser.hpp>
  21 #include <sngxml/xpath/XPathEvaluate.hpp>
  22 #include <soulng/lexer/ParsingException.hpp>
  23 #include <soulng/util/MappedInputFile.hpp>
  24 #include <cmajor/binder/BoundCompileUnit.hpp>
  25 #include <cmajor/binder/BoundFunction.hpp>
  26 #include <cmajor/binder/TypeBinder.hpp>
  27 #include <cmajor/binder/OverloadResolution.hpp>
  28 #include <cmajor/binder/StatementBinder.hpp>
  29 #include <cmajor/binder/BoundStatement.hpp>
  30 #include <cmajor/binder/ControlFlowAnalyzer.hpp>
  31 #include <cmajor/binder/AttributeBinder.hpp>
  32 #include <cmajor/symbols/GlobalFlags.hpp>
  33 #include <cmajor/symbols/Warning.hpp>
  34 #include <cmajor/symbols/Module.hpp>
  35 #include <cmajor/symbols/ModuleCache.hpp>
  36 #include <cmajor/symbols/SymbolWriter.hpp>
  37 #include <cmajor/symbols/SymbolReader.hpp>
  38 #include <cmajor/symbols/SymbolCreatorVisitor.hpp>
  39 #include <cmajor/symbols/Meta.hpp>
  40 #include <cmajor/ast2dom/Ast2Dom.hpp>
  41 #include <cmajor/bdt2dom/Bdt2Dom.hpp>
  42 #include <cmajor/cmdoclib/Input.hpp>
  43 #include <cmajor/cmdoclib/Global.hpp>
  44 #include <cmajor/cmdoclib/ParserDoc.hpp>
  45 #include <cmajor/cmdoclib/SourceCodePrinter.hpp>
  46 #include <cmajor/cmdoclib/SymbolTableXml.hpp>
  47 #include <cmajor/cmdoclib/File.hpp>
  48 #ifdef _WIN32
  49 #include <cmajor/cmres/ResourceProcessor.hpp>
  50 #endif
  51 #include <sngjson/json/JsonLexer.hpp>
  52 #include <sngjson/json/JsonParser.hpp>
  53 #include <sngcm/ast/Attribute.hpp>
  54 #include <sngcm/ast/Function.hpp>
  55 #include <sngcm/ast/BasicType.hpp>
  56 #include <sngcm/ast/Identifier.hpp>
  57 #include <sngcm/ast/TypeExpr.hpp>
  58 #include <sngcm/ast/Expression.hpp>
  59 #include <sngcm/ast/Literal.hpp>
  60 #include <sngcm/ast/SystemFileIndex.hpp>
  61 #include <soulng/util/Unicode.hpp>
  62 #include <soulng/util/Path.hpp>
  63 #include <soulng/util/System.hpp>
  64 #include <soulng/util/TextUtils.hpp>
  65 #include <soulng/util/Log.hpp>
  66 #include <soulng/util/Time.hpp>
  67 #include <soulng/util/Sha1.hpp>
  68 #include <soulng/util/Process.hpp>
  69 #include <algorithm>
  70 #include <iostream>
  71 #include <fstream>
  72 #include <stdexcept>
  73 #include <mutex>
  74 #include <chrono>
  75 #include <thread>
  76 #include <list>
  77 #include <condition_variable>
  78 
  79 using namespace sngcm::ast;
  80 using namespace cmajor::symbols;
  81 using namespace cmajor::binder;
  82 using namespace soulng::util;
  83 using namespace soulng::unicode;
  84 
  85 namespace cmajor { namespace build {
  86 
  87 LogFileWriter* buildLogWriter = nullptr;
  88 
  89 void SetBuildLogWriter(LogFileWriter* buildLogWriter_)
  90 {
  91     buildLogWriter = buildLogWriter_;
  92 }
  93 
  94 bool stopBuild = false;
  95 
  96 void StopBuild()
  97 {
  98     stopBuild = true;
  99 }
 100 
 101 void ResetStopBuild()
 102 {
 103     stopBuild = false;
 104 }
 105 
 106 Solution* currentSolution = nullptr;
 107 
 108 std::std::vector<std::std::unique_ptr<CompileUnitNode>>ParseSourcesInMainThread(Module*moduleconststd::std::vector<std::string>&sourceFilePathsbool&stop)
 109 {
 110     if (GetGlobalFlag(GlobalFlags::verbose))
 111     {
 112         std::string s;
 113         if (sourceFilePaths.size() != 1)
 114         {
 115             s = "s";
 116         }
 117         LogMessage(module->LogStreamId()"Parsing " + std::to_string(sourceFilePaths.size()) + " source file" + s + " in main thread...");
 118     }
 119     std::vector<std::std::unique_ptr<CmajorLexer>>lexers;
 120     std::vector<std::std::unique_ptr<CompileUnitNode>>compileUnits;
 121     try
 122     {
 123         for (const std::string& sourceFilePath : sourceFilePaths)
 124         {
 125             if (stop)
 126             {
 127                 return std::vector<std::std::unique_ptr<CompileUnitNode>>();
 128             }
 129             if (boost::filesystem::file_size(sourceFilePath) == 0)
 130             {
 131                 std::unique_ptr<CompileUnitNode> compileUnit(new CompileUnitNode(Span()boost::uuids::nil_uuid()sourceFilePath));
 132                 compileUnit->SetHash(GetSha1MessageDigest(""));
 133                 int32_t fileIndex = module->GetFileTable().RegisterFilePath(sourceFilePath);
 134                 compileUnits.push_back(std::move(compileUnit));
 135                 lexers.push_back(std::unique_ptr<CmajorLexer>());
 136             }
 137             else
 138             {
 139                 MappedInputFile sourceFile(sourceFilePath);
 140                 int32_t fileIndex = module->GetFileTable().RegisterFilePath(sourceFilePath);
 141                 ParsingContext parsingContext;
 142                 std::string fileContent(sourceFile.Begin()sourceFile.End());
 143                 std::u32string s(ToUtf32(fileContent));
 144                 std::unique_ptr<CmajorLexer> lexer(new CmajorLexer(ssourceFilePathfileIndex));
 145                 try
 146                 {
 147                     soulng::lexer::XmlParsingLog log(std::cout);
 148                     if (GetGlobalFlag(GlobalFlags::debugParsing))
 149                     {
 150                         lexer->SetLog(&log);
 151                     }
 152                     boost::uuids::uuid moduleId = module->Id();
 153                     std::unique_ptr<CompileUnitNode> compileUnit = CompileUnitParser::Parse(*lexer&moduleId&parsingContext);
 154                     compileUnit->SetHash(GetSha1MessageDigest(fileContent));
 155                     if (GetGlobalFlag(GlobalFlags::ast2xml))
 156                     {
 157                         std::unique_ptr<sngxml::dom::Document> ast2xmlDoc = cmajor::ast2dom::GenerateAstDocument(compileUnit.get());
 158                         std::string ast2xmlFilePath = Path::ChangeExtension(sourceFilePath".ast.xml");
 159                         std::ofstream ast2xmlFile(ast2xmlFilePath);
 160                         CodeFormatter formatter(ast2xmlFile);
 161                         formatter.SetIndentSize(1);
 162                         ast2xmlDoc->Write(formatter);
 163                     }
 164                     if (GetGlobalFlag(GlobalFlags::generateDebugInfo) || GetGlobalFlag(GlobalFlags::cmdoc))
 165                     {
 166                         compileUnit->ComputeLineStarts(s);
 167                     }
 168                     compileUnits.push_back(std::move(compileUnit));
 169                 }
 170                 catch (...)
 171                 {
 172                     lexers.push_back(std::move(lexer));
 173                     throw ;
 174                 }
 175                 lexers.push_back(std::move(lexer));
 176             }
 177         }
 178         if (GetGlobalFlag(GlobalFlags::verbose))
 179         {
 180             std::string s;
 181             if (sourceFilePaths.size() != 1)
 182             {
 183                 s = "s";
 184             }
 185             LogMessage(module->LogStreamId()"Source file" + s + " parsed.");
 186         }
 187     }
 188     catch (...)
 189     {
 190         module->SetLexers(std::move(lexers));
 191         throw ;
 192     }
 193     module->SetLexers(std::move(lexers));
 194     return compileUnits;
 195 }
 196 
 197 struct ParserData 
 198 {
 199     ParserData(const boost::uuids::uuid& moduleId_const std::std::vector<std::string>&sourceFilePaths_std::std::vector<std::std::unique_ptr<CompileUnitNode>>&compileUnits_
 200         std::std::vector<std::std::unique_ptr<CmajorLexer>>&lexers_conststd::std::vector<uint32_t>&fileIndeces_std::std::vector<std::exception_ptr>&exceptions_bool&stop_):
 201         moduleId(moduleId_)sourceFilePaths(sourceFilePaths_)compileUnits(compileUnits_)lexers(lexers_)fileIndeces(fileIndeces_)stop(stop_)exceptions(exceptions_)
 202     {
 203     }
 204     boost::uuids::uuid moduleId;
 205     const std::std::vector<std::string>&sourceFilePaths;
 206     std::std::vector<std::std::unique_ptr<CompileUnitNode>>&compileUnits;
 207     std::std::vector<std::std::unique_ptr<CmajorLexer>>&lexers;
 208     const std::std::vector<uint32_t>&fileIndeces;
 209     std::list<int> indexQueue;
 210     std::mutex indexQueueMutex;
 211     bool& stop;
 212     std::std::vector<std::exception_ptr>&exceptions;
 213 };
 214 
 215 void ParseSourceFile(ParserData* parserData)
 216 {
 217     int index = -1;
 218     try
 219     {
 220         while (!parserData->stop)
 221         {
 222             {
 223                 std::lock_guard<std::mutex> lock(parserData->indexQueueMutex);
 224                 if (parserData->indexQueue.empty()) return;
 225                 index = parserData->indexQueue.front();
 226                 parserData->indexQueue.pop_front();
 227             }
 228             const std::string& sourceFilePath = parserData->sourceFilePaths[index];
 229             if (boost::filesystem::file_size(sourceFilePath) == 0)
 230             {
 231                 std::unique_ptr<CompileUnitNode> compileUnit(new CompileUnitNode(Span()boost::uuids::nil_uuid()sourceFilePath));
 232                 compileUnit->SetHash(GetSha1MessageDigest(""));
 233                 parserData->compileUnits[index].reset(compileUnit.release());
 234                 parserData->lexers[index].reset();
 235             }
 236             else
 237             {
 238                 MappedInputFile sourceFile(sourceFilePath);
 239                 ParsingContext parsingContext;
 240                 int fileIndex = parserData->fileIndeces[index];
 241                 std::string fileContent(sourceFile.Begin()sourceFile.End());
 242                 std::u32string s(ToUtf32(fileContent));
 243                 std::unique_ptr<CmajorLexer> lexer(new CmajorLexer(ssourceFilePathfileIndex));
 244                 try
 245                 {
 246                     std::unique_ptr<CompileUnitNode> compileUnit = CompileUnitParser::Parse(*lexer&parserData->moduleId&parsingContext);
 247                     compileUnit->SetHash(GetSha1MessageDigest(fileContent));
 248                     if (GetGlobalFlag(GlobalFlags::ast2xml))
 249                     {
 250                         std::unique_ptr<sngxml::dom::Document> ast2xmlDoc = cmajor::ast2dom::GenerateAstDocument(compileUnit.get());
 251                         std::string ast2xmlFilePath = Path::ChangeExtension(sourceFilePath".ast.xml");
 252                         std::ofstream ast2xmlFile(ast2xmlFilePath);
 253                         CodeFormatter formatter(ast2xmlFile);
 254                         formatter.SetIndentSize(1);
 255                         ast2xmlDoc->Write(formatter);
 256                     }
 257                     if (GetGlobalFlag(GlobalFlags::generateDebugInfo) || GetGlobalFlag(GlobalFlags::cmdoc))
 258                     {
 259                         compileUnit->ComputeLineStarts(s);
 260                     }
 261                     parserData->compileUnits[index].reset(compileUnit.release());
 262                 }
 263                 catch (...)
 264                 {
 265                     parserData->lexers[index].reset(lexer.release());
 266                     throw ;
 267                 }
 268                 parserData->lexers[index].reset(lexer.release());
 269             }
 270         }
 271     }
 272     catch (...)
 273     {
 274         if (index != -1)
 275         {
 276             parserData->exceptions[index] = std::current_exception();
 277             parserData->stop = true;
 278         }
 279     }
 280 }
 281 
 282 std::std::vector<std::std::unique_ptr<CompileUnitNode>>ParseSourcesConcurrently(Module*moduleconststd::std::vector<std::string>&sourceFilePathsintnumThreadsbool&stop)
 283 {
 284     if (GetGlobalFlag(GlobalFlags::verbose))
 285     {
 286         std::string s;
 287         if (sourceFilePaths.size() != 1)
 288         {
 289             s = "s";
 290         }
 291         LogMessage(module->LogStreamId()"Parsing " + std::to_string(sourceFilePaths.size()) + " source file" + s + " using " + std::to_string(numThreads) + " threads...");
 292     }
 293     std::vector<std::std::unique_ptr<CompileUnitNode>>compileUnits;
 294     std::vector<std::std::unique_ptr<CmajorLexer>>lexers;
 295     try
 296     {
 297         int n = int(sourceFilePaths.size());
 298         compileUnits.resize(n);
 299         lexers.resize(n);
 300         std::vector<uint32_t> fileIndeces;
 301         for (int i = 0; i < n; ++i)
 302         {
 303             const std::string& sourceFilePath = sourceFilePaths[i];
 304             int32_t fileIndex = module->GetFileTable().RegisterFilePath(sourceFilePath);
 305             fileIndeces.push_back(fileIndex);
 306         }
 307         std::vector<std::exception_ptr> exceptions;
 308         exceptions.resize(n);
 309         ParserData parserData(module->Id()sourceFilePathscompileUnitslexersfileIndecesexceptionsstop);
 310         for (int i = 0; i < n; ++i)
 311         {
 312             parserData.indexQueue.push_back(i);
 313         }
 314         std::vector<std::thread> threads;
 315         for (int i = 0; i < numThreads; ++i)
 316         {
 317             threads.push_back(std::thread(ParseSourceFile&parserData));
 318             if (parserData.stop) break;
 319         }
 320         int numStartedThreads = int(threads.size());
 321         for (int i = 0; i < numStartedThreads; ++i)
 322         {
 323             if (threads[i].joinable())
 324             {
 325                 threads[i].join();
 326             }
 327         }
 328         for (int i = 0; i < n; ++i)
 329         {
 330             if (exceptions[i])
 331             {
 332                 std::rethrow_exception(exceptions[i]);
 333             }
 334         }
 335         if (GetGlobalFlag(GlobalFlags::verbose))
 336         {
 337             std::string s;
 338             if (sourceFilePaths.size() != 1)
 339             {
 340                 s = "s";
 341             }
 342             LogMessage(module->LogStreamId()"Source file" + s + " parsed.");
 343         }
 344     }
 345     catch (...)
 346     {
 347         module->SetLexers(std::move(lexers));
 348         throw ;
 349     }
 350     module->SetLexers(std::move(lexers));
 351     return compileUnits;
 352 }
 353 
 354 std::std::vector<std::std::unique_ptr<CompileUnitNode>>ParseSources(Module*moduleconststd::std::vector<std::string>&sourceFilePathsbool&stop)
 355 {
 356     try
 357     {
 358         int numThreads = std::min(static_cast<int>(std::thread::hardware_concurrency())static_cast<int>(sourceFilePaths.size()));
 359         if (numThreads <= 1)
 360         {
 361             numThreads = 1;
 362         }
 363         if (numThreads == 1 || GetGlobalFlag(GlobalFlags::debugParsing))
 364         {
 365             return ParseSourcesInMainThread(modulesourceFilePathsstop);
 366         }
 367         else
 368         {
 369             return ParseSourcesConcurrently(modulesourceFilePathsnumThreadsstop);
 370         }
 371     }
 372     catch (soulng::lexer::ParsingException& ex;)
 373     {
 374         ex.SetProject(ToUtf8(module->Name()));
 375         ex.SetModule(module);
 376         throw ;
 377     }
 378     catch (const AttributeNotUniqueException& ex;)
 379     {
 380         throw Exception(ex.what()ex.GetSpan()ex.ModuleId()ex.PrevSpan()ex.PrevModuleId());
 381     }
 382 }
 383 
 384 void Preprocess(Project* projectstd::std::vector<std::std::unique_ptr<CompileUnitNode>>&compileUnits)
 385 {
 386     std::string projectHashContent;
 387     for (const std::string& dependsOnId : project->DependsOnIds())
 388     {
 389         projectHashContent.append(dependsOnId);
 390     }
 391     for (std::std::unique_ptr<CompileUnitNode>&compileUnit : compileUnits)
 392     {
 393         if (compileUnit->GlobalNs()->HasUnnamedNs())
 394         {
 395             sngcm::ast::AddNamespaceImportsForUnnamedNamespaces(*compileUnit);
 396         }
 397         projectHashContent.append(compileUnit->Hash());
 398     }
 399     project->SetHash(GetSha1MessageDigest(projectHashContent));
 400 }
 401 
 402 void CreateSymbols(SymbolTable& symbolTableconst std::std::vector<std::std::unique_ptr<CompileUnitNode>>&compileUnitsbool&stop)
 403 {
 404     SymbolCreatorVisitor symbolCreator(symbolTable);
 405     for (const std::std::unique_ptr<CompileUnitNode>&compileUnit : compileUnits)
 406     {
 407         if (stop)
 408         {
 409             return;
 410         }
 411         symbolTable.SetCurrentCompileUnit(compileUnit.get());
 412         compileUnit->Accept(symbolCreator);
 413     }
 414 }
 415 
 416 std::std::vector<std::std::unique_ptr<BoundCompileUnit>>BindTypes(Module&moduleconststd::std::vector<std::std::unique_ptr<CompileUnitNode>>&compileUnitsAttributeBinder*attributeBinder
 417     bool& stop)
 418 {
 419     std::vector<std::std::unique_ptr<BoundCompileUnit>>boundCompileUnits;
 420     for (const std::std::unique_ptr<CompileUnitNode>&compileUnit : compileUnits)
 421     {
 422         if (stop)
 423         {
 424             return std::vector<std::std::unique_ptr<BoundCompileUnit>>();
 425         }
 426         std::unique_ptr<BoundCompileUnit> boundCompileUnit(new BoundCompileUnit(modulecompileUnit.get()attributeBinder));
 427         boundCompileUnit->PushBindingTypes();
 428         TypeBinder typeBinder(*boundCompileUnit);
 429         compileUnit->Accept(typeBinder);
 430         boundCompileUnit->PopBindingTypes();
 431         boundCompileUnits.push_back(std::move(boundCompileUnit));
 432     }
 433     return boundCompileUnits;
 434 }
 435 
 436 void BindStatements(BoundCompileUnit& boundCompileUnit)
 437 {
 438     StatementBinder statementBinder(boundCompileUnit);
 439     boundCompileUnit.GetCompileUnitNode()->Accept(statementBinder);
 440 }
 441 
 442 void GenerateLibraryCpp(Module* moduleconst std::std::vector<std::string>&objectFilePathsconststd::string&libraryFilePath)
 443 {
 444     if (GetGlobalFlag(GlobalFlags::disableCodeGen)) return;
 445     if (GetGlobalFlag(GlobalFlags::verbose) && !GetGlobalFlag(GlobalFlags::unitTest))
 446     {
 447         LogMessage(module->LogStreamId()"Creating library...");
 448     }
 449     const Tool& libraryManagerTool = GetLibraryManagerTool(GetPlatform()GetToolChain());
 450     const Configuration& configuration = GetToolConfiguration(libraryManagerToolGetConfig());
 451     module->SetCurrentToolName(ToUtf32(libraryManagerTool.commandName));
 452     std::string command;
 453     std::string errors;
 454     command.append(libraryManagerTool.commandName);
 455     for (const std::string& arg : configuration.args)
 456     {
 457         std::string a = arg;
 458         if (a.find('$') != std::string::npos)
 459         {
 460             if (a.find("$LIBRARY_FILE$") != std::string::npos)
 461             {
 462                 a = soulng::util::Replace(a"$LIBRARY_FILE$"QuotedPath(libraryFilePath));
 463             }
 464             else if (a.find("$OBJECT_FILES$") != std::string::npos)
 465             {
 466                 std::string value;
 467                 bool first = true;
 468                 for (const std::string& objectFilePath : objectFilePaths)
 469                 {
 470                     if (first)
 471                     {
 472                         first = false;
 473                     }
 474                     else
 475                     {
 476                         value.append(" ");
 477                     }
 478                     value.append(QuotedPath(objectFilePath));
 479                 }
 480                 a = soulng::util::Replace(a"$OBJECT_FILES$"value);
 481             }
 482         }
 483         command.append(1' ').append(a);
 484     }
 485     try
 486     {
 487         Process::Redirections redirections = Process::Redirections::processStdErr;
 488         if (GetGlobalFlag(GlobalFlags::verbose))
 489         {
 490             redirections = redirections | Process::Redirections::processStdOut;
 491         }
 492         Process process(commandredirections);
 493         if (GetGlobalFlag(GlobalFlags::verbose))
 494         {
 495             while (!process.Eof(Process::StdHandle::stdOut))
 496             {
 497                 std::string line = process.ReadLine(Process::StdHandle::stdOut);
 498                 if (!line.empty())
 499                 {
 500                     LogMessage(module->LogStreamId()PlatformStringToUtf8(line));
 501                 }
 502             }
 503         }
 504         errors = process.ReadToEnd(Process::StdHandle::stdErr);
 505         process.WaitForExit();
 506         int exitCode = process.ExitCode();
 507         if (exitCode != 0)
 508         {
 509             throw std::runtime_error("executing '" + command + "' failed with exit code: " + std::to_string(exitCode));
 510         }
 511     }
 512     catch (const std::exception& ex;)
 513     {
 514         throw std::runtime_error("generating library '" + libraryFilePath + "' failed: " + ex.what() + ":\nerrors:\n" + errors);
 515     }
 516     if (GetGlobalFlag(GlobalFlags::verbose) && !GetGlobalFlag(GlobalFlags::unitTest))
 517     {
 518         LogMessage(module->LogStreamId()"==> " + libraryFilePath);
 519     }
 520 }
 521 
 522 #ifdef _WIN32
 523 
 524 
 525 
 526 
 527 
 528 
 529 
 530 
 531 
 532 
 533 
 534 
 535 
 536 
 537 
 538 
 539 
 540 
 541 
 542 
 543 
 544 
 545 
 546 
 547 
 548 
 549 
 550 
 551 
 552 
 553 
 554 
 555 
 556 
 557 
 558 
 559 
 560 
 561 
 562 
 563 
 564 
 565 
 566 
 567 
 568 
 569 
 570 
 571 
 572 
 573 
 574 
 575 
 576 
 577 
 578 
 579 
 580 
 581 
 582 
 583 
 584 
 585 
 586 
 587 
 588 
 589 
 590 
 591 
 592 
 593 
 594 
 595 
 596 
 597 
 598 
 599 
 600 
 601 
 602 
 603 
 604 
 605 
 606 
 607 
 608 
 609 
 610 
 611 
 612 
 613 
 614 
 615 
 616 
 617 
 618 
 619 
 620 
 621 
 622 
 623 
 624 
 625 
 626 
 627 
 628 
 629 
 630 
 631 
 632 
 633 
 634 
 635 
 636 
 637 
 638 
 639 
 640 
 641 
 642 
 643 #else
 644 
 645 void GenerateLibraryLlvm(Module* moduleconst std::std::vector<std::string>&objectFilePathsconststd::string&libraryFilePath)
 646 {
 647     if (GetGlobalFlag(GlobalFlags::verbose) && !GetGlobalFlag(GlobalFlags::unitTest))
 648     {
 649         LogMessage(module->LogStreamId()"Creating library...");
 650     }
 651     boost::filesystem::remove(libraryFilePath);
 652     module->SetCurrentToolName(U"ar");
 653     std::vector<std::string> args;
 654     args.push_back("-o " + QuotedPath(libraryFilePath));
 655     int n = objectFilePaths.size();
 656     for (int i = 0; i < n; ++i)
 657     {
 658         args.push_back(QuotedPath(objectFilePaths[i]));
 659     }
 660     std::string errors;
 661     std::string libCommandLine = "ar q";
 662     for (const std::string& arg : args)
 663     {
 664         libCommandLine.append(1' ').append(arg);
 665     }
 666     try
 667     {
 668         Process::Redirections redirections = Process::Redirections::processStdErr;
 669         if (GetGlobalFlag(GlobalFlags::verbose))
 670         {
 671             redirections = redirections | Process::Redirections::processStdOut;
 672         }
 673         Process process(libCommandLineredirections);
 674         if (GetGlobalFlag(GlobalFlags::verbose))
 675         {
 676             while (!process.Eof(Process::StdHandle::stdOut))
 677             {
 678                 std::string line = process.ReadLine(Process::StdHandle::stdOut);
 679                 if (!line.empty())
 680                 {
 681                     LogMessage(module->LogStreamId()PlatformStringToUtf8(line));
 682                 }
 683             }
 684         }
 685         errors = process.ReadToEnd(Process::StdHandle::stdErr);
 686         process.WaitForExit();
 687         int exitCode = process.ExitCode();
 688         if (exitCode != 0)
 689         {
 690             throw std::runtime_error("executing '" + libCommandLine + "' failed with exit code: " + std::to_string(exitCode));
 691         }
 692     }
 693     catch (const std::exception& ex;)
 694     {
 695         throw std::runtime_error("generating library '" + libraryFilePath + "' failed: " + ex.what() + ":\nerrors:\n" + errors);
 696     }
 697     if (GetGlobalFlag(GlobalFlags::verbose) && !GetGlobalFlag(GlobalFlags::unitTest))
 698     {
 699         LogMessage(module->LogStreamId()"==> " + libraryFilePath);
 700     }
 701 }
 702 
 703 #endif
 704 
 705 void GenerateLibrary(Module* moduleconst std::std::vector<std::string>&objectFilePathsconststd::string&libraryFilePath)
 706 {
 707     if (GetBackEnd() == cmajor::symbols::BackEnd::llvm)
 708     {
 709         GenerateLibraryLlvm(moduleobjectFilePathslibraryFilePath);
 710     }
 711     else if (GetBackEnd() == cmajor::symbols::BackEnd::cmcpp)
 712     {
 713         GenerateLibraryCpp(moduleobjectFilePathslibraryFilePath);
 714     }
 715 #ifdef _WIN32
 716 
 717 
 718 
 719 
 720 #endif
 721 }
 722 
 723 std::string GetBoostLibDirFromCompilerConfigXml()
 724 {
 725     std::string cmajorConfigDir = Path::Combine(CmajorRootDir()"config");
 726     std::string compilerConfigXmlFilePath = Path::Combine(cmajorConfigDir"compiler-config.xml");
 727     if (boost::filesystem::exists(compilerConfigXmlFilePath))
 728     {
 729         std::unique_ptr<sngxml::dom::Document> compilerConfigDoc = sngxml::dom::ReadDocument(compilerConfigXmlFilePath);
 730         std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/compiler/" + ToUtf32(GetPlatform()) + U"/" + ToUtf32(GetToolChain()) + U"/boost"compilerConfigDoc.get());
 731         if (result)
 732         {
 733             if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
 734             {
 735                 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
 736                 int n = nodeSet->Length();
 737                 for (int i = 0; i < n; ++i)
 738                 {
 739                     sngxml::dom::Node* node = (*nodeSet)[i];
 740                     if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
 741                     {
 742                         sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
 743                         std::u32string libraryDirAttr = element->GetAttribute(U"libraryDir");
 744                         if (!libraryDirAttr.empty())
 745                         {
 746                             return ToUtf8(libraryDirAttr);
 747                         }
 748                     }
 749                 }
 750             }
 751         }
 752     }
 753     return std::string();
 754 }
 755 
 756 std::string MakeGccLibraryName(const std::string& libraryFilePath)
 757 {
 758     if (StartsWith(libraryFilePath"lib") && EndsWith(libraryFilePath".a"))
 759     {
 760         return "-l" + Path::GetFileName(libraryFilePath.substr(3libraryFilePath.length() - (3 + 2)));
 761     }
 762     return libraryFilePath;
 763 }
 764 
 765 const char* dynamicRuntimeArg = "-lcmrt3100cpp";
 766 const char* dynamicDebugRuntimeArg = "-lcmrt3100cppd";
 767 
 768 void LinkCpp(Target targetconst std::string& executableFilePathconst std::string& libraryFilePathconst std::std::vector<std::string>&libraryFilePathsconststd::string&mainObjectFilePathModule&module)
 769 {
 770     if (GetGlobalFlag(GlobalFlags::disableCodeGen)) return;
 771     if (GetGlobalFlag(GlobalFlags::verbose) && !GetGlobalFlag(GlobalFlags::unitTest))
 772     {
 773         LogMessage(module.LogStreamId()"Linking...");
 774     }
 775     boost::filesystem::path bdp = executableFilePath;
 776     bdp.remove_filename();
 777     boost::filesystem::create_directories(bdp);
 778     std::string platform = GetPlatform();
 779     std::string toolChain = GetToolChain();
 780     const Tool& linkerTool = GetLinkerTool(platformtoolChain);
 781     const Configuration& configuration = GetToolConfiguration(linkerToolGetConfig());
 782     std::string toolChainDir = GetFullPath(Path::Combine(Path::Combine(CmajorRootDir()"lib")toolChain));
 783     std::string binDir = GetFullPath(Path::Combine(CmajorRootDir()"bin"));
 784     std::string linkCommandLine;
 785     linkCommandLine = linkerTool.commandName;
 786     std::set<std::string> libraryDirectories;
 787     libraryDirectories.insert(toolChainDir);
 788     libraryDirectories.insert(binDir);
 789     std::set<std::string> libraryNames;
 790     for (const std::string& libraryFilePath : libraryFilePaths)
 791     {
 792         std::string libraryDir = GetFullPath(Path::GetDirectoryName(libraryFilePath));
 793         libraryDirectories.insert(libraryDir);
 794         std::string libraryName = MakeGccLibraryName(libraryFilePath);
 795         libraryNames.insert(libraryName);
 796     }
 797     std::string boostLibDir = GetBoostLibDirFromCompilerConfigXml();
 798     if (!boostLibDir.empty())
 799     {
 800         libraryDirectories.insert(GetFullPath(boostLibDir));
 801     }
 802     std::string libraryPathFlag;
 803     for (const std::string& arg : configuration.args)
 804     {
 805         if (arg.find('$') != std::string::npos)
 806         {
 807             if (arg.find("$LIBRARY_PATH_FLAG$") != std::string::npos)
 808             {
 809                 libraryPathFlag = soulng::util::Replace(arg"$LIBRARY_PATH_FLAG$""");
 810             }
 811             else if (arg.find("$LIBRARY_DIRECTORIES$") != std::string::npos)
 812             {
 813                 std::string libraryPathArgs;
 814                 bool first = true;
 815                 for (const std::string& libraryDir : libraryDirectories)
 816                 {
 817                     if (first)
 818                     {
 819                         first = false;
 820                     }
 821                     else
 822                     {
 823                         libraryPathArgs.append(1' ');
 824                     }
 825                     libraryPathArgs.append(libraryPathFlag).append(QuotedPath(libraryDir));
 826                 }
 827                 linkCommandLine.append(1' ').append(soulng::util::Replace(arg"$LIBRARY_DIRECTORIES$"libraryPathArgs));
 828             }
 829             else if (arg.find("$RUNTIME_LIBS$") != std::string::npos)
 830             {
 831                 std::string libs = soulng::util::Replace(arg"$RUNTIME_LIBS$""");
 832                 if (libs == "DYNAMIC")
 833                 {
 834                     if (GetGlobalFlag(GlobalFlags::linkWithDebugRuntime))
 835                     {
 836                         libraryNames.insert(dynamicDebugRuntimeArg);
 837                     }
 838                     else
 839                     {
 840                         libraryNames.insert(dynamicRuntimeArg);
 841                     }
 842                 }
 843                 else
 844                 {
 845                     std::vector<std::string> runtimeLibs = Split(libs';');
 846                     for (const std::string& runtimeLib : runtimeLibs)
 847                     {
 848                         libraryNames.insert(runtimeLib);
 849                     }
 850                 }
 851             }
 852             else if (arg.find("$LIBRARY_FILES$") != std::string::npos)
 853             {
 854                 std::string libFilesArg;
 855                 for (const std::string& libraryName : libraryNames)
 856                 {
 857                     libFilesArg.append(1' ').append(QuotedPath(libraryName));
 858                 }
 859                 linkCommandLine.append(1' ').append(soulng::util::Replace(arg"$LIBRARY_FILES$"libFilesArg));
 860             }
 861             else if (arg.find("$RESOURCE_FILE$") != std::string::npos)
 862             {
 863                 if (!module.ResourceFilePath().empty())
 864                 {
 865                     linkCommandLine.append(1' ').append(soulng::util::Replace(arg"$RESOURCE_FILE$"QuotedPath(module.ResourceFilePath())));
 866                 }
 867             }
 868             else if (arg.find("$MAIN_OBJECT_FILE$") != std::string::npos)
 869             {
 870                 std::string mainObjectPath = mainObjectFilePath;
 871                 linkCommandLine.append(1' ').append(soulng::util::Replace(arg"$MAIN_OBJECT_FILE$"QuotedPath(mainObjectPath)));
 872             }
 873             else if (arg.find("$EXECUTABLE_FILE$") != std::string::npos)
 874             {
 875                 std::string exePath = executableFilePath;
 876                 if (Path::HasExtension(exePath))
 877                 {
 878                     exePath = Path::ChangeExtension(exePath"");
 879                 }
 880                 linkCommandLine.append(1' ').append(soulng::util::Replace(arg"$EXECUTABLE_FILE$"QuotedPath(exePath)));
 881             }
 882             else if (arg.find("$DEBUG_INFORMATION_FILE$") != std::string::npos)
 883             {
 884                 linkCommandLine.append(1' ').append(soulng::util::Replace(arg"$DEBUG_INFORMATION_FILE$"QuotedPath(Path::ChangeExtension(executableFilePathlinkerTool.debugInformationFileExtension))));
 885             }
 886             else if (arg.find("$ENTRY$") != std::string::npos)
 887             {
 888                 if (target == Target::winguiapp)
 889                 {
 890                     linkCommandLine.append(1' ').append(soulng::util::Replace(arg"$ENTRY$""wWinMain"));
 891                 }
 892                 else
 893                 {
 894                     linkCommandLine.append(1' ').append(soulng::util::Replace(arg"$ENTRY$""wmain"));
 895                 }
 896             }
 897             else if (arg.find("$SUBSYSTEM$") != std::string::npos)
 898             {
 899                 if (target == Target::winguiapp)
 900                 {
 901                     linkCommandLine.append(1' ').append(soulng::util::Replace(arg"$SUBSYSTEM$""windows"));
 902                 }
 903                 else
 904                 {
 905                     linkCommandLine.append(1' ').append(soulng::util::Replace(arg"$SUBSYSTEM$""console"));
 906                 }
 907             }
 908         }
 909         else
 910         {
 911             linkCommandLine.append(1' ').append(arg);
 912         }
 913     }
 914     std::string errors;
 915     try
 916     {
 917         Process::Redirections redirections = Process::Redirections::processStdErr;
 918         Process process(linkCommandLineredirections);
 919         errors = process.ReadToEnd(Process::StdHandle::stdErr);
 920         process.WaitForExit();
 921         int exitCode = process.ExitCode();
 922         if (exitCode != 0)
 923         {
 924             throw std::runtime_error("executing '" + linkCommandLine + "' failed with exit code: " + std::to_string(exitCode));
 925         }
 926     }
 927     catch (const std::exception& ex;)
 928     {
 929         throw std::runtime_error("linking executable '" + executableFilePath + "' failed: " + ex.what() + ":\nerrors:\n" + errors);
 930     }
 931     if (GetGlobalFlag(GlobalFlags::verbose) && !GetGlobalFlag(GlobalFlags::unitTest))
 932     {
 933         LogMessage(module.LogStreamId()"==> " + executableFilePath);
 934     }
 935 }
 936 
 937 std::string GetCppSolutionDirectoryPath(Project* project)
 938 {
 939     if (currentSolution == nullptr) return std::string();
 940     const Tool& libraryManagerTool = GetLibraryManagerTool(GetPlatform()GetToolChain());
 941     const Configuration& configuration = GetToolConfiguration(libraryManagerToolGetConfig());
 942     return GetFullPath(Path::Combine(Path::Combine(Path::Combine(Path::Combine(Path::GetDirectoryName(currentSolution->FilePath())"cpp")GetToolChain())GetConfig())configuration.outputDirectory));
 943 }
 944 
 945 void CreateCppProjectFile(Project* projectModule& moduleconst std::string& mainSourceFilePathconst std::string& libraryFilePathconst std::std::vector<std::string>&libraryFilePaths)
 946 {
 947     std::string toolChain = GetToolChain();
 948     if (toolChain != "vs") return;
 949     if (GetGlobalFlag(GlobalFlags::verbose) && !GetGlobalFlag(GlobalFlags::unitTest))
 950     {
 951         LogMessage(module.LogStreamId()"Creating project file...");
 952     }
 953     const Tool& projectFileGeneratorTool = GetProjectFileGeneratorTool(GetPlatform()toolChain);
 954     std::set<std::string> libraryDirectories;
 955     std::set<std::string> libraryNames;
 956     if (!GetGlobalFlag(GlobalFlags::disableCodeGen))
 957     {
 958         std::string libraryDir = GetFullPath(Path::GetDirectoryName(libraryFilePath));
 959         libraryDirectories.insert(libraryDir);
 960         std::string libraryName = QuotedPath(Path::GetFileName(libraryFilePath));
 961         libraryNames.insert(libraryName);
 962     }
 963     std::string solutionDir = GetCppSolutionDirectoryPath(project);
 964     if (!solutionDir.empty())
 965     {
 966         libraryDirectories.insert(solutionDir);
 967     }
 968     std::string cmajorLibDir = GetFullPath(Path::Combine(CmajorRootDir()"lib"));
 969     std::string toolChainDir = QuotedPath(GetFullPath(Path::Combine(Path::Combine(CmajorRootDir()"lib")GetToolChain())));
 970     libraryDirectories.insert(cmajorLibDir);
 971     libraryDirectories.insert(toolChainDir);
 972 #ifdef _WIN32
 973 
 974 
 975 #endif
 976     for (const std::string& libFilePath : libraryFilePaths)
 977     {
 978         if (GetGlobalFlag(GlobalFlags::disableCodeGen))
 979         {
 980             if (Path::GetFileName(libFilePath) == Path::GetFileName(libraryFilePath))
 981             {
 982                 continue;
 983             }
 984         }
 985         std::string libraryDir = GetFullPath(Path::GetDirectoryName(libFilePath));
 986         libraryDirectories.insert(libraryDir);
 987         std::string libraryName = QuotedPath(Path::GetFileName(libFilePath));
 988         libraryNames.insert(libraryName);
 989     }
 990     std::string config = GetConfig();
 991     const Configuration& configuration = GetToolConfiguration(projectFileGeneratorToolconfig);
 992     std::string commandLine;
 993     std::string errorFilePath;
 994     std::string projectFilePath;
 995     std::string options;
 996     std::string errors;
 997     commandLine = projectFileGeneratorTool.commandName;
 998     for (const std::string& arg : configuration.args)
 999     {
1000         if (arg.find('$') != std::string::npos)
1001         {
1002             if (arg.find("$PROJECT_NAME$") != std::string::npos)
1003             {
1004                 commandLine.append(1' ').append(soulng::util::Replace(arg"$PROJECT_NAME$"ToUtf8(project->Name())));
1005             }
1006             else if (arg.find("$PROJECT_FILE_PATH$") != std::string::npos)
1007             {
1008                 projectFilePath = GetFullPath(Path::Combine(Path::Combine(Path::Combine(Path::Combine(Path::Combine(project->SourceBasePath().generic_string()"lib")"cpp")toolChain)config)ToUtf8(project->Name()) + projectFileGeneratorTool.outputFileExtension));
1009                 commandLine.append(1' ').append(soulng::util::Replace(arg"$PROJECT_FILE_PATH$"projectFilePath));
1010             }
1011             else if (arg.find("$PROJECT_TARGET$") != std::string::npos)
1012             {
1013                 commandLine.append(1' ').append(soulng::util::Replace(arg"$PROJECT_TARGET$"TargetStr(project->GetTarget())));
1014             }
1015             else if (arg.find("$PROJECT_CONFIG$") != std::string::npos)
1016             {
1017                 commandLine.append(1' ').append(soulng::util::Replace(arg"$PROJECT_CONFIG$"config));
1018             }
1019             else if (arg.find("$RUNTIME_LIBS$") != std::string::npos)
1020             {
1021                 std::string runtimeLibs = soulng::util::Replace(arg"$RUNTIME_LIBS$""");
1022                 std::vector<std::string> libs = soulng::util::Split(runtimeLibs';');
1023                 for (const std::string& lib : libs)
1024                 {
1025                     libraryNames.insert(lib);
1026                 }
1027             }
1028             else if (arg.find("$LIBRARY_DIRECTORIES$") != std::string::npos)
1029             {
1030                 std::string libraryDirectoriesStr;
1031                 bool first = true;
1032                 for (const std::string& libraryDirectory : libraryDirectories)
1033                 {
1034                     if (first)
1035                     {
1036                         first = false;
1037                     }
1038                     else
1039                     {
1040                         libraryDirectoriesStr.append(1';');
1041                     }
1042                     libraryDirectoriesStr.append(QuotedPath(libraryDirectory));
1043                 }
1044                 commandLine.append(1' ').append(soulng::util::Replace(arg"$LIBRARY_DIRECTORIES$"libraryDirectoriesStr));
1045             }
1046             else if (arg.find("$LIBRARY_FILE_NAMES$") != std::string::npos)
1047             {
1048                 std::string libraryNamesStr;
1049                 bool first = true;
1050                 for (const std::string& libraryName : libraryNames)
1051                 {
1052                     if (first)
1053                     {
1054                         first = false;
1055                     }
1056                     else
1057                     {
1058                         libraryNamesStr.append(1';');
1059                     }
1060                     libraryNamesStr.append(QuotedPath(libraryName));
1061                 }
1062                 commandLine.append(1' ').append(soulng::util::Replace(arg"$LIBRARY_FILE_NAMES$"libraryNamesStr));
1063             }
1064             else if (arg.find("$GENERATE_ASSEMBLY_FILE_OPTION$") != std::string::npos)
1065             {
1066                 if (GetGlobalFlag(GlobalFlags::emitLlvm))
1067                 {
1068                     options.append(soulng::util::Replace(arg"$GENERATE_ASSEMBLY_FILE_OPTION$"""));
1069                 }
1070                 else
1071                 {
1072                     continue;
1073                 }
1074             }
1075             else if (arg.find("$GENERATE_JUST_MY_CODE_OPTION$") != std::string::npos)
1076             {
1077                 if (GetGlobalFlag(GlobalFlags::justMyCodeDebugging))
1078                 {
1079                     options.append(soulng::util::Replace(arg"$GENERATE_JUST_MY_CODE_OPTION$"""));
1080                 }
1081                 else
1082                 {
1083                     continue;
1084                 }
1085             }
1086             else if (arg.find("$ENABLE_RUNTIME_TYPE_INFORMATION_OPTION$") != std::string::npos)
1087             {
1088                 options.append(soulng::util::Replace(arg"$ENABLE_RUNTIME_TYPE_INFORMATION_OPTION$"""));
1089             }
1090             else if (arg.find("$OPTIONS$") != std::string::npos)
1091             {
1092                 if (!options.empty())
1093                 {
1094                     commandLine.append(1' ').append(soulng::util::Replace(arg"$OPTIONS$"QuotedPath(options)));
1095                 }
1096                 else
1097                 {
1098                     continue;
1099                 }
1100             }
1101             else if (arg.find("$SOURCE_FILES$") != std::string::npos)
1102             {
1103                 std::string sourceFilePaths;
1104                 for (const std::string& sourceFilePath : project->RelativeSourceFilePaths())
1105                 {
1106                     sourceFilePaths.append(1' ');
1107                     sourceFilePaths.append(QuotedPath(Path::ChangeExtension(sourceFilePath".cpp")));
1108                 }
1109                 sourceFilePaths.append(1' ');
1110                 sourceFilePaths.append(QuotedPath(mainSourceFilePath));
1111                 commandLine.append(1' ').append(soulng::util::Replace(arg"$SOURCE_FILES$"sourceFilePaths));
1112             }
1113         }
1114         else
1115         {
1116             commandLine.append(1' ').append(arg);
1117         }
1118     }
1119     try
1120     {
1121         Process::Redirections redirections = Process::Redirections::processStdErr;
1122         if (GetGlobalFlag(GlobalFlags::verbose))
1123         {
1124             redirections = redirections | Process::Redirections::processStdOut;
1125         }
1126         Process process(commandLineredirections);
1127         if (GetGlobalFlag(GlobalFlags::verbose))
1128         {
1129             while (!process.Eof(Process::StdHandle::stdOut))
1130             {
1131                 std::string line = process.ReadLine(Process::StdHandle::stdOut);
1132                 if (!line.empty())
1133                 {
1134                     LogMessage(module.LogStreamId()PlatformStringToUtf8(line));
1135                 }
1136             }
1137         }
1138         errors = process.ReadToEnd(Process::StdHandle::stdErr);
1139         process.WaitForExit();
1140         int exitCode = process.ExitCode();
1141         if (exitCode != 0)
1142         {
1143             throw std::runtime_error("executing '" + commandLine + "' failed with exit code: " + std::to_string(exitCode));
1144         }
1145     }
1146     catch (const std::exception& ex;)
1147     {
1148         throw std::runtime_error("generating C++ project file '" + projectFilePath + "' for project '" + ToUtf8(project->Name()) + "' failed: " + ex.what() + ":\nerrors:\n" + errors);
1149     }
1150     if (GetGlobalFlag(GlobalFlags::verbose) && !GetGlobalFlag(GlobalFlags::unitTest))
1151     {
1152         LogMessage(module.LogStreamId()"==> " + projectFilePath);
1153     }
1154 }
1155 
1156 void CreateCppSolutionFile(Solution* solutionconst std::std::vector<Project*>&projects)
1157 {
1158     std::string toolChain = GetToolChain();
1159     if (toolChain != "vs") return;
1160     std::string solutionFilePath;
1161     const Tool& solutionFileGeneratorTool = GetSolutionFileGeneratorTool(GetPlatform()toolChain);
1162     if (GetGlobalFlag(GlobalFlags::verbose) && !GetGlobalFlag(GlobalFlags::unitTest))
1163     {
1164         LogMessage(-1"Creating solution file...");
1165     }
1166     std::string commandLine;
1167     std::string projectFilePath;
1168     std::string errors;
1169     commandLine = solutionFileGeneratorTool.commandName;
1170     std::string config = GetConfig();
1171     const Configuration& configuration = GetToolConfiguration(solutionFileGeneratorToolconfig);
1172     for (const std::string& arg : configuration.args)
1173     {
1174         if (arg.find('$') != std::string::npos)
1175         {
1176             if (arg.find("$SOLUTION_NAME$") != std::string::npos)
1177             {
1178                 commandLine.append(1' ').append(soulng::util::Replace(arg"$SOLUTION_NAME$"ToUtf8(solution->Name())));
1179             }
1180             else if (arg.find("$SOLUTION_FILE_PATH$") != std::string::npos)
1181             {
1182                 solutionFilePath = soulng::util::Replace(arg"$SOLUTION_FILE_PATH$"
1183                     QuotedPath(Path::Combine(Path::Combine(Path::Combine(Path::Combine(Path::GetDirectoryName(solution->FilePath())"cpp")toolChain)config)
1184                         Path::ChangeExtension(Path::GetFileName(solution->FilePath())".sln"))));
1185                 commandLine.append(1' ').append(solutionFilePath);
1186             }
1187             else if (arg.find("$PROJECT_FILE_PATHS$") != std::string::npos)
1188             {
1189                 std::string projectFilePaths;
1190                 int n = solution->RelativeProjectFilePaths().size();
1191                 for (int i = 0; i < n; ++i)
1192                 {
1193                     const std::string& relativeProjectFilePath = solution->RelativeProjectFilePaths()[i];
1194                     std::string projectFilePath = "../../../" + Path::GetDirectoryName(relativeProjectFilePath) + "/lib/cpp/" + toolChain + "/" + config +  "/" + Path::ChangeExtension(Path::GetFileName(relativeProjectFilePath)".vcxproj");
1195                     projectFilePaths.append(" ").append(QuotedPath(projectFilePath));
1196                 }
1197                 commandLine.append(1' ').append(soulng::util::Replace(arg"$PROJECT_FILE_PATHS$"projectFilePaths));
1198             }
1199         }
1200         else
1201         {
1202             commandLine.append(1' ').append(arg);
1203         }
1204     }
1205     try
1206     {
1207         Process::Redirections redirections = Process::Redirections::processStdErr;
1208         if (GetGlobalFlag(GlobalFlags::verbose))
1209         {
1210             redirections = redirections | Process::Redirections::processStdOut;
1211         }
1212         Process process(commandLineredirections);
1213         if (GetGlobalFlag(GlobalFlags::verbose))
1214         {
1215             while (!process.Eof(Process::StdHandle::stdOut))
1216             {
1217                 std::string line = process.ReadLine(Process::StdHandle::stdOut);
1218                 if (!line.empty())
1219                 {
1220                     LogMessage(-1PlatformStringToUtf8(line));
1221                 }
1222             }
1223         }
1224         errors = process.ReadToEnd(Process::StdHandle::stdErr);
1225         process.WaitForExit();
1226         int exitCode = process.ExitCode();
1227         if (exitCode != 0)
1228         {
1229             throw std::runtime_error("executing '" + commandLine + "' failed with exit code: " + std::to_string(exitCode));
1230         }
1231     }
1232     catch (const std::exception& ex;)
1233     {
1234         throw std::runtime_error("generating C++ solution file '" + solutionFilePath + "' for solution '" + ToUtf8(solution->Name()) + "' failed: " + ex.what() + ":\nerrors:\n" + errors);
1235     }
1236     if (GetGlobalFlag(GlobalFlags::verbose) && !GetGlobalFlag(GlobalFlags::unitTest))
1237     {
1238         LogMessage(-1"==> " + solutionFilePath);
1239     }
1240 }
1241 
1242 #ifdef _WIN32
1243 
1244 
1245 
1246 
1247 
1248 
1249 
1250 
1251 
1252 
1253 
1254 
1255 
1256 
1257 
1258 
1259 
1260 
1261 
1262 
1263 
1264 
1265 
1266 
1267 
1268 
1269 
1270 
1271 
1272 
1273 
1274 
1275 
1276 
1277 
1278 
1279 
1280 
1281 
1282 
1283 
1284 
1285 
1286 
1287 
1288 
1289 
1290 
1291 
1292 
1293 
1294 
1295 
1296 
1297 
1298 
1299 
1300 
1301 
1302 
1303 
1304 
1305 
1306 
1307 
1308 
1309 
1310 
1311 
1312 
1313 
1314 
1315 
1316 
1317 
1318 
1319 
1320 
1321 
1322 
1323 
1324 
1325 
1326 
1327 
1328 
1329 
1330 
1331 
1332 
1333 
1334 
1335 
1336 
1337 
1338 
1339 
1340 
1341 
1342 
1343 
1344 
1345 
1346 
1347 
1348 
1349 
1350 
1351 
1352 
1353 
1354 
1355 
1356 
1357 
1358 
1359 
1360 
1361 
1362 
1363 
1364 
1365 
1366 
1367 
1368 
1369 
1370 
1371 
1372 
1373 
1374 
1375 
1376 
1377 
1378 
1379 
1380 
1381 
1382 
1383 
1384 
1385 
1386 
1387 
1388 
1389 
1390 
1391 
1392 
1393 
1394 
1395 
1396 
1397 
1398 
1399 
1400 
1401 
1402 
1403 
1404 
1405 
1406 
1407 
1408 
1409 
1410 
1411 
1412 
1413 
1414 
1415 
1416 
1417 
1418 
1419 
1420 
1421 
1422 
1423 
1424 
1425 
1426 
1427 
1428 
1429 
1430 
1431 #else
1432 
1433 void CreateDynamicListFile(const std::string& dynamicListFilePathModule& module)
1434 {
1435     std::ofstream defFile(dynamicListFilePath);
1436     CodeFormatter formatter(defFile);
1437     formatter.WriteLine("{");
1438     formatter.IncIndent();
1439     for (const std::string& fun : module.AllExportedFunctions())
1440     {
1441         formatter.WriteLine(fun + ";");
1442     }
1443     for (const std::string& fun : module.ExportedFunctions())
1444     {
1445         formatter.WriteLine(fun + ";");
1446     }
1447     for (const std::string& data : module.AllExportedData())
1448     {
1449         formatter.WriteLine(data + ";");
1450     }
1451     for (const std::string& data : module.ExportedData())
1452     {
1453         formatter.WriteLine(data + ";");
1454     }
1455     formatter.DecIndent();
1456     formatter.WriteLine("};");
1457 }
1458 
1459 void LinkLlvm(Target targetconst std::string& executableFilePathconst std::string& libraryFilePathconst std::std::vector<std::string>&libraryFilePathsconststd::string&mainObjectFilePathModule&module)
1460 {
1461     if (GetGlobalFlag(GlobalFlags::verbose) && !GetGlobalFlag(GlobalFlags::unitTest))
1462     {
1463         LogMessage(module.LogStreamId()"Linking...");
1464     }
1465     module.SetCurrentToolName(U"clang++");
1466     boost::filesystem::path bdp = executableFilePath;
1467     bdp.remove_filename();
1468     boost::filesystem::create_directories(bdp);
1469     std::vector<std::string> args;
1470     args.push_back("-L" + Path::Combine(CmajorRootDir()"lib"));
1471     char* cmajorLibDir = getenv("CMAJOR_LIBDIR");
1472     if (cmajorLibDir && *cmajorLibDir)
1473     {
1474         args.push_back("-L" + std::string(cmajorLibDir));
1475     }
1476     args.push_back(QuotedPath(mainObjectFilePath));
1477     args.push_back("-Xlinker --start-group");
1478     int n = libraryFilePaths.size();
1479     args.push_back(QuotedPath(libraryFilePaths.back()));
1480     for (int i = 0; i < n - 1; ++i)
1481     {
1482         args.push_back(QuotedPath(libraryFilePaths[i]));
1483     }
1484     if (GetGlobalFlag(GlobalFlags::linkWithDebugRuntime))
1485     {
1486         std::string cmrtLibName = "cmrtd";
1487         args.push_back("-l" + cmrtLibName);
1488     }
1489     else
1490     {
1491         std::string cmrtLibName = "cmrt";
1492         args.push_back("-l" + cmrtLibName);
1493     }
1494     args.push_back("-lboost_filesystem -lboost_iostreams -lboost_system -lbz2 -lz");
1495     args.push_back("-Xlinker --end-group");
1496     args.push_back("-o " + QuotedPath(executableFilePath));
1497     std::string linkCommandLine;
1498     std::string errors;
1499     linkCommandLine = "clang++";
1500     for (const std::string& arg : args)
1501     {
1502         linkCommandLine.append(1' ').append(arg);
1503     }
1504     try
1505     {
1506         Process::Redirections redirections = Process::Redirections::processStdErr;
1507         if (GetGlobalFlag(GlobalFlags::verbose))
1508         {
1509             redirections = redirections | Process::Redirections::processStdOut;
1510         }
1511         Process process(linkCommandLineredirections);
1512         if (GetGlobalFlag(GlobalFlags::verbose))
1513         {
1514             while (!process.Eof(Process::StdHandle::stdOut))
1515             {
1516                 std::string line = process.ReadLine(Process::StdHandle::stdOut);
1517                 if (!line.empty())
1518                 {
1519                     LogMessage(-1PlatformStringToUtf8(line));
1520                 }
1521             }
1522         }
1523         errors = process.ReadToEnd(Process::StdHandle::stdErr);
1524         process.WaitForExit();
1525         int exitCode = process.ExitCode();
1526         if (exitCode != 0)
1527         {
1528             throw std::runtime_error("executing '" + linkCommandLine + "' failed with exit code: " + std::to_string(exitCode));
1529         }
1530     }
1531     catch (const std::exception& ex;)
1532     {
1533         throw std::runtime_error("linking executable '" + executableFilePath + "' failed: " + ex.what() + ":\nerrors:\n" + errors);
1534     }
1535     if (GetGlobalFlag(GlobalFlags::verbose) && !GetGlobalFlag(GlobalFlags::unitTest))
1536     {
1537         LogMessage(module.LogStreamId()"==> " + executableFilePath);
1538     }
1539 }
1540 
1541 #endif
1542 
1543 void Link(Target targetconst std::string& executableFilePathconst std::string& libraryFilePathconst std::std::vector<std::string>&libraryFilePathsconststd::string&mainObjectFilePathModule&module)
1544 {
1545     if (GetBackEnd() == cmajor::symbols::BackEnd::llvm)
1546     {
1547         LinkLlvm(targetexecutableFilePathlibraryFilePathlibraryFilePathsmainObjectFilePathmodule);
1548     }
1549     else if (GetBackEnd() == cmajor::symbols::BackEnd::cmcpp)
1550     {
1551         LinkCpp(targetexecutableFilePathlibraryFilePathlibraryFilePathsmainObjectFilePathmodule);
1552     }
1553 #ifdef _WIN32
1554 
1555 
1556 
1557 
1558 #endif
1559 }
1560 
1561 void CleanProject(Project* project)
1562 {
1563     std::string config = GetConfig();
1564     if (GetGlobalFlag(GlobalFlags::verbose))
1565     {
1566         LogMessage(project->LogStreamId()"Cleaning project '" + ToUtf8(project->Name()) + "' (" + project->FilePath() + ") using " + config + " configuration...");
1567     }
1568     boost::filesystem::path mfp = project->ModuleFilePath();
1569     RemoveModuleFromCache(project->ModuleFilePath());
1570     mfp.remove_filename();
1571     boost::filesystem::remove_all(mfp);
1572     if (project->GetTarget() == Target::program || project->GetTarget() == Target::winguiapp || project->GetTarget() == Target::winapp)
1573     {
1574         boost::filesystem::path efp = project->ExecutableFilePath();
1575         efp.remove_filename();
1576         boost::filesystem::remove_all(efp);
1577     }
1578     if (GetGlobalFlag(GlobalFlags::verbose))
1579     {
1580         LogMessage(project->LogStreamId()"Project '" + ToUtf8(project->Name()) + "' cleaned successfully.");
1581     }
1582 }
1583 
1584 void CheckMainFunctionSymbol(Module& module)
1585 {
1586     FunctionSymbol* userMain = module.GetSymbolTable().MainFunctionSymbol();
1587     if (!userMain)
1588     {
1589         throw Exception("program has no main function"Span()boost::uuids::nil_uuid());
1590     }
1591     if (!userMain->Parameters().empty())
1592     {
1593         if (userMain->Parameters().size() != 2)
1594         {
1595             throw Exception("main function must either take no parameters or take two parameters"userMain->GetSpan()userMain->SourceModuleId());
1596         }
1597         if (!TypesEqual(userMain->Parameters()[0]->GetType()module.GetSymbolTable().GetTypeByName(U"int")))
1598         {
1599             throw Exception("first parameter of main function must be of int type"userMain->GetSpan()userMain->SourceModuleId());
1600         }
1601         if (!TypesEqual(userMain->Parameters()[1]->GetType()module.GetSymbolTable().GetTypeByName(U"char")->AddConst(
1602             userMain->GetSpan()userMain->SourceModuleId())->AddPointer(userMain->GetSpan()userMain->SourceModuleId())->AddPointer(userMain->GetSpan()userMain->SourceModuleId())))
1603         {
1604             throw Exception("second parameter of main function must be of 'const char**' type"userMain->GetSpan()userMain->SourceModuleId());
1605         }
1606     }
1607     if (userMain->ReturnType() && !userMain->ReturnType()->IsVoidType())
1608     {
1609         if (!TypesEqual(userMain->ReturnType()module.GetSymbolTable().GetTypeByName(U"int")))
1610         {
1611             throw Exception("main function must either be void function or return an int"userMain->GetSpan()userMain->SourceModuleId());
1612         }
1613     }
1614 }
1615 
1616 void CreateJsonRegistrationUnit(std::std::vector<std::string>&objectFilePathsModule&modulecmajor::codegen::EmittingContext&emittingContextAttributeBinder*attributeBinder)
1617 {
1618     CompileUnitNode jsonRegistrationCompileUnit(Span()boost::uuids::nil_uuid()boost::filesystem::path(module.OriginalFilePath()).parent_path().append("__json__.cm").generic_string());
1619     jsonRegistrationCompileUnit.SetSynthesizedUnit();
1620     jsonRegistrationCompileUnit.GlobalNs()->AddMember(new NamespaceImportNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"System")));
1621     jsonRegistrationCompileUnit.GlobalNs()->AddMember(new NamespaceImportNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"System.Json")));
1622     FunctionNode * jsonRegistrationFunction(new FunctionNode(Span()boost::uuids::nil_uuid()Specifiers::public_new IntNode(Span()boost::uuids::nil_uuid())U"RegisterJsonClasses"nullptr));
1623     jsonRegistrationFunction->SetReturnTypeExpr(new VoidNode(Span()boost::uuids::nil_uuid()));
1624     CompoundStatementNode* jsonRegistrationFunctionBody = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
1625     const std::std::unordered_set<std::u32string>&jsonClasses=module.GetSymbolTable().JsonClasses();
1626     for (const std::u32string& jsonClass : jsonClasses)
1627     {
1628         InvokeNode* invokeRegisterJsonClass = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RegisterJsonClass"));
1629         invokeRegisterJsonClass->AddArgument(new TypeNameNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()jsonClass)));
1630         invokeRegisterJsonClass->AddArgument(new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()jsonClass)
1631             new IdentifierNode(Span()boost::uuids::nil_uuid()U"Create")));
1632         ExpressionStatementNode* registerStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeRegisterJsonClass);
1633         jsonRegistrationFunctionBody->AddStatement(registerStatement);
1634     }
1635     jsonRegistrationFunction->SetBody(jsonRegistrationFunctionBody);
1636     jsonRegistrationCompileUnit.GlobalNs()->AddMember(jsonRegistrationFunction);
1637     SymbolCreatorVisitor symbolCreator(module.GetSymbolTable());
1638     jsonRegistrationCompileUnit.Accept(symbolCreator);
1639     BoundCompileUnit boundJsonCompileUnit(module&jsonRegistrationCompileUnitattributeBinder);
1640     boundJsonCompileUnit.PushBindingTypes();
1641     TypeBinder typeBinder(boundJsonCompileUnit);
1642     jsonRegistrationCompileUnit.Accept(typeBinder);
1643     boundJsonCompileUnit.PopBindingTypes();
1644     StatementBinder statementBinder(boundJsonCompileUnit);
1645     jsonRegistrationCompileUnit.Accept(statementBinder);
1646     if (boundJsonCompileUnit.HasGotos())
1647     {
1648         AnalyzeControlFlow(boundJsonCompileUnit);
1649     }
1650     cmajor::codegen::GenerateCode(emittingContextboundJsonCompileUnit);
1651     objectFilePaths.push_back(boundJsonCompileUnit.ObjectFilePath());
1652 }
1653 
1654 void CreateMainUnitLlvm(std::std::vector<std::string>&objectFilePathsModule&modulecmajor::codegen::EmittingContext&emittingContextAttributeBinder*attributeBinder
1655     std::string& mainObjectFilePath)
1656 {
1657     CompileUnitNode mainCompileUnit(Span()boost::uuids::nil_uuid()boost::filesystem::path(module.OriginalFilePath()).parent_path().append("__main__.cm").generic_string());
1658     mainCompileUnit.SetSynthesizedUnit();
1659     mainCompileUnit.SetProgramMainUnit();
1660     mainCompileUnit.GlobalNs()->AddMember(new NamespaceImportNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"System")));
1661     mainCompileUnit.GlobalNs()->AddMember(MakePolymorphicClassArray(module.GetSymbolTable().PolymorphicClasses()U"@polymorphicClassArray"));
1662     mainCompileUnit.GlobalNs()->AddMember(MakeStaticClassArray(module.GetSymbolTable().ClassesHavingStaticConstructor()U"@staticClassArray"));
1663     FunctionNode * mainFunction(new FunctionNode(Span()boost::uuids::nil_uuid()Specifiers::public_new IntNode(Span()boost::uuids::nil_uuid())U"main"nullptr));
1664 #ifndef _WIN32
1665     mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new IntNode(Span()boost::uuids::nil_uuid())new IdentifierNode(Span()boost::uuids::nil_uuid()U"argc")));
1666     mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()
1667         new CharNode(Span()boost::uuids::nil_uuid())))new IdentifierNode(Span()boost::uuids::nil_uuid()U"argv")));
1668 #endif
1669     mainFunction->SetProgramMain();
1670     CompoundStatementNode* mainFunctionBody = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
1671     ConstructionStatementNode* constructExitCode = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new IntNode(Span()boost::uuids::nil_uuid())
1672         new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode"));
1673     mainFunctionBody->AddStatement(constructExitCode);
1674     ExpressionStatementNode* rtInitCall = nullptr;
1675     if (GetGlobalFlag(GlobalFlags::profile))
1676     {
1677         InvokeNode* invokeRtInit = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtStartProfiling"));
1678         invokeRtInit->AddArgument(new DivNode(Span()boost::uuids::nil_uuid()
1679             new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"@polymorphicClassArray")
1680                 new IdentifierNode(Span()boost::uuids::nil_uuid()U"Length")))
1681             new LongLiteralNode(Span()boost::uuids::nil_uuid()4)));
1682         invokeRtInit->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()
1683             new IdentifierNode(Span()boost::uuids::nil_uuid()U"@polymorphicClassArray")new IdentifierNode(Span()boost::uuids::nil_uuid()U"CBegin"))));
1684         invokeRtInit->AddArgument(new DivNode(Span()boost::uuids::nil_uuid()
1685             new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"@staticClassArray")
1686                 new IdentifierNode(Span()boost::uuids::nil_uuid()U"Length")))
1687             new LongLiteralNode(Span()boost::uuids::nil_uuid()2)));
1688         invokeRtInit->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()
1689             new IdentifierNode(Span()boost::uuids::nil_uuid()U"@staticClassArray")new IdentifierNode(Span()boost::uuids::nil_uuid()U"CBegin"))));
1690         invokeRtInit->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"GlobalInitCompileUnits"));
1691         rtInitCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeRtInit);
1692     }
1693     else
1694     {
1695         InvokeNode* invokeRtInit = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtInit"));
1696         invokeRtInit->AddArgument(new DivNode(Span()boost::uuids::nil_uuid()
1697             new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"@polymorphicClassArray")
1698                 new IdentifierNode(Span()boost::uuids::nil_uuid()U"Length")))
1699             new LongLiteralNode(Span()boost::uuids::nil_uuid()4)));
1700         invokeRtInit->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()
1701             new IdentifierNode(Span()boost::uuids::nil_uuid()U"@polymorphicClassArray")new IdentifierNode(Span()boost::uuids::nil_uuid()U"CBegin"))));
1702         invokeRtInit->AddArgument(new DivNode(Span()boost::uuids::nil_uuid()
1703             new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"@staticClassArray")
1704                 new IdentifierNode(Span()boost::uuids::nil_uuid()U"Length")))
1705             new LongLiteralNode(Span()boost::uuids::nil_uuid()2)));
1706         invokeRtInit->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()
1707             new IdentifierNode(Span()boost::uuids::nil_uuid()U"@staticClassArray")new IdentifierNode(Span()boost::uuids::nil_uuid()U"CBegin"))));
1708         invokeRtInit->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"GlobalInitCompileUnits"));
1709         rtInitCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeRtInit);
1710     }
1711     mainFunctionBody->AddStatement(rtInitCall);
1712 #ifdef _WIN32
1713 
1714 
1715 
1716 
1717 
1718 
1719 
1720 
1721 
1722 #endif
1723     CompoundStatementNode* tryBlock = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
1724     if (!module.GetSymbolTable().JsonClasses().empty())
1725     {
1726         ExpressionStatementNode* registerJsonClassesCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()
1727             new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RegisterJsonClasses")));
1728         tryBlock->AddStatement(registerJsonClassesCall);
1729     }
1730     FunctionSymbol* userMain = module.GetSymbolTable().MainFunctionSymbol();
1731     InvokeNode* invokeMain = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()userMain->GroupName()));
1732     if (!userMain->Parameters().empty())
1733     {
1734         invokeMain->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"argc"));
1735         invokeMain->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"argv"));
1736     }
1737     StatementNode* callMainStatement = nullptr;
1738     if (!userMain->ReturnType() || userMain->ReturnType()->IsVoidType())
1739     {
1740         callMainStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeMain);
1741     }
1742     else
1743     {
1744         callMainStatement = new AssignmentStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode")invokeMain);
1745     }
1746     InvokeNode* invokeInitialize = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"Initialize"));
1747     StatementNode* callInitializeStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeInitialize);
1748     tryBlock->AddStatement(callInitializeStatement);
1749     tryBlock->AddStatement(callMainStatement);
1750     TryStatementNode* tryStatement = new TryStatementNode(Span()boost::uuids::nil_uuid()tryBlock);
1751     CompoundStatementNode* catchBlock = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
1752     InvokeNode* consoleError = new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()
1753         new IdentifierNode(Span()boost::uuids::nil_uuid()U"System.Console")new IdentifierNode(Span()boost::uuids::nil_uuid()U"Error")));
1754     DotNode* writeLine = new DotNode(Span()boost::uuids::nil_uuid()consoleErrornew IdentifierNode(Span()boost::uuids::nil_uuid()U"WriteLine"));
1755     InvokeNode* printEx = new InvokeNode(Span()boost::uuids::nil_uuid()writeLine);
1756     InvokeNode* exToString = new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"ex")
1757         new IdentifierNode(Span()boost::uuids::nil_uuid()U"ToString")));
1758     printEx->AddArgument(exToString);
1759     ExpressionStatementNode* printExStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()printEx);
1760     catchBlock->AddStatement(printExStatement);
1761     AssignmentStatementNode* assignExitCodeStatement = new AssignmentStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode")
1762         new IntLiteralNode(Span()boost::uuids::nil_uuid()1));
1763     catchBlock->AddStatement(assignExitCodeStatement);
1764     CatchNode* catchAll = new CatchNode(Span()boost::uuids::nil_uuid()new ConstNode(Span()boost::uuids::nil_uuid()new LValueRefNode(Span()boost::uuids::nil_uuid()
1765         new IdentifierNode(Span()boost::uuids::nil_uuid()U"System.Exception")))new IdentifierNode(Span()boost::uuids::nil_uuid()U"ex")catchBlock);
1766     tryStatement->AddCatch(catchAll);
1767     mainFunctionBody->AddStatement(tryStatement);
1768     ExpressionStatementNode* rtDoneCall = nullptr;
1769     if (GetGlobalFlag(GlobalFlags::profile))
1770     {
1771         rtDoneCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()new InvokeNode(Span()boost::uuids::nil_uuid()
1772             new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtEndProfiling")));
1773     }
1774     else
1775     {
1776         rtDoneCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtDone")));
1777     }
1778     mainFunctionBody->AddStatement(rtDoneCall);
1779     InvokeNode* exitCall = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtExit"));
1780     exitCall->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode"));
1781     ExpressionStatementNode* rtExitCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()exitCall);
1782     mainFunctionBody->AddStatement(rtExitCall);
1783     ReturnStatementNode* returnStatement = new ReturnStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode"));
1784     mainFunctionBody->AddStatement(returnStatement);
1785     mainFunction->SetBody(mainFunctionBody);
1786     mainCompileUnit.GlobalNs()->AddMember(mainFunction);
1787     SymbolCreatorVisitor symbolCreator(module.GetSymbolTable());
1788     mainCompileUnit.Accept(symbolCreator);
1789     BoundCompileUnit boundMainCompileUnit(module&mainCompileUnitattributeBinder);
1790     boundMainCompileUnit.PushBindingTypes();
1791     TypeBinder typeBinder(boundMainCompileUnit);
1792     mainCompileUnit.Accept(typeBinder);
1793     boundMainCompileUnit.PopBindingTypes();
1794     StatementBinder statementBinder(boundMainCompileUnit);
1795     mainCompileUnit.Accept(statementBinder);
1796     if (boundMainCompileUnit.HasGotos())
1797     {
1798         AnalyzeControlFlow(boundMainCompileUnit);
1799     }
1800     cmajor::codegen::GenerateCode(emittingContextboundMainCompileUnit);
1801     mainObjectFilePath = boundMainCompileUnit.ObjectFilePath();
1802 }
1803 
1804 void CreateMainUnitCpp(std::std::vector<std::string>&objectFilePathsModule&modulecmajor::codegen::EmittingContext&emittingContextAttributeBinder*attributeBinder
1805     std::string& mainObjectFilePathstd::string& mainSourceFilePath)
1806 {
1807     bool vsToolChain = GetToolChain() == "vs";
1808     CompileUnitNode mainCompileUnit(Span()boost::uuids::nil_uuid()boost::filesystem::path(module.OriginalFilePath()).parent_path().append("__main__.cm").generic_string());
1809     mainCompileUnit.SetSynthesizedUnit();
1810     mainCompileUnit.SetProgramMainUnit();
1811     mainCompileUnit.GlobalNs()->AddMember(new NamespaceImportNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"System")));
1812     mainCompileUnit.GlobalNs()->AddMember(MakePolymorphicClassArray(module.GetSymbolTable().PolymorphicClasses()U"__polymorphicClassArray"));
1813     mainCompileUnit.GlobalNs()->AddMember(MakeStaticClassArray(module.GetSymbolTable().ClassesHavingStaticConstructor()U"__staticClassArray"));
1814     std::string platform = GetPlatform();
1815     FunctionNode* mainFunction = nullptr;
1816     if (platform == "windows")
1817     {
1818         mainFunction = new FunctionNode(Span()boost::uuids::nil_uuid()Specifiers::public_new IntNode(Span()boost::uuids::nil_uuid())U"wmain"nullptr);
1819     }
1820     else
1821     {
1822         mainFunction = new FunctionNode(Span()boost::uuids::nil_uuid()Specifiers::public_new IntNode(Span()boost::uuids::nil_uuid())U"main"nullptr);
1823     }
1824     if (platform != "windows")
1825     {
1826         mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new IntNode(Span()boost::uuids::nil_uuid())
1827             new IdentifierNode(Span()boost::uuids::nil_uuid()U"argc")));
1828         mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()
1829             new PointerNode(Span()boost::uuids::nil_uuid()new CharNode(Span()boost::uuids::nil_uuid())))new IdentifierNode(Span()boost::uuids::nil_uuid()U"argv")));
1830     }
1831 /*
1832     if (!vsToolChain)
1833     {
1834         mainFunction->AddParameter(new ParameterNode(Span(), new IntNode(Span()), new IdentifierNode(Span(), U"argc")));
1835         mainFunction->AddParameter(new ParameterNode(Span(), new PointerNode(Span(), new PointerNode(Span(), new CharNode(Span()))), new IdentifierNode(Span(), U"argv")));
1836     }
1837 */
1838 
1839     mainFunction->SetProgramMain();
1840     CompoundStatementNode* mainFunctionBody = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
1841     ConstructionStatementNode* constructExitCode = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new IntNode(Span()boost::uuids::nil_uuid())
1842         new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode"));
1843     mainFunctionBody->AddStatement(constructExitCode);
1844     ExpressionStatementNode* rtInitCall = nullptr;
1845     if (GetGlobalFlag(GlobalFlags::profile))
1846     {
1847         InvokeNode* invokeRtInit = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtStartProfiling"));
1848         invokeRtInit->AddArgument(new DivNode(Span()boost::uuids::nil_uuid()
1849             new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"__polymorphicClassArray")
1850                 new IdentifierNode(Span()boost::uuids::nil_uuid()U"Length")))
1851             new LongLiteralNode(Span()boost::uuids::nil_uuid()4)));
1852         invokeRtInit->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()
1853             new IdentifierNode(Span()boost::uuids::nil_uuid()U"__polymorphicClassArray")new IdentifierNode(Span()boost::uuids::nil_uuid()U"CBegin"))));
1854         invokeRtInit->AddArgument(new DivNode(Span()boost::uuids::nil_uuid()
1855             new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"__staticClassArray")
1856                 new IdentifierNode(Span()boost::uuids::nil_uuid()U"Length")))
1857             new LongLiteralNode(Span()boost::uuids::nil_uuid()2)));
1858         invokeRtInit->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()
1859             new IdentifierNode(Span()boost::uuids::nil_uuid()U"__staticClassArray")new IdentifierNode(Span()boost::uuids::nil_uuid()U"CBegin"))));
1860         invokeRtInit->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"GlobalInitCompileUnits"));
1861         rtInitCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeRtInit);
1862     }
1863     else
1864     {
1865         InvokeNode* invokeRtInit = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtInit"));
1866         invokeRtInit->AddArgument(new DivNode(Span()boost::uuids::nil_uuid()
1867             new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()
1868                 new IdentifierNode(Span()boost::uuids::nil_uuid()U"__polymorphicClassArray")new IdentifierNode(Span()boost::uuids::nil_uuid()U"Length")))
1869             new LongLiteralNode(Span()boost::uuids::nil_uuid()4)));
1870         invokeRtInit->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()
1871             new IdentifierNode(Span()boost::uuids::nil_uuid()U"__polymorphicClassArray")new IdentifierNode(Span()boost::uuids::nil_uuid()U"CBegin"))));
1872         invokeRtInit->AddArgument(new DivNode(Span()boost::uuids::nil_uuid()
1873             new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"__staticClassArray")
1874                 new IdentifierNode(Span()boost::uuids::nil_uuid()U"Length")))
1875             new LongLiteralNode(Span()boost::uuids::nil_uuid()2)));
1876         invokeRtInit->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()
1877             new IdentifierNode(Span()boost::uuids::nil_uuid()U"__staticClassArray")new IdentifierNode(Span()boost::uuids::nil_uuid()U"CBegin"))));
1878         invokeRtInit->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"GlobalInitCompileUnits"));
1879         rtInitCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeRtInit);
1880     }
1881     mainFunctionBody->AddStatement(rtInitCall);
1882 
1883     if (platform == "windows")
1884     {
1885         ConstructionStatementNode* argc = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new IntNode(Span()boost::uuids::nil_uuid())
1886             new IdentifierNode(Span()boost::uuids::nil_uuid()U"argc"));
1887         argc->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtArgc")));
1888         mainFunctionBody->AddStatement(argc);
1889         ConstructionStatementNode* argv = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new ConstNode(Span()boost::uuids::nil_uuid()
1890             new PointerNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()new CharNode(Span()boost::uuids::nil_uuid()))))
1891             new IdentifierNode(Span()boost::uuids::nil_uuid()U"argv"));
1892         argv->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtArgv")));
1893         mainFunctionBody->AddStatement(argv);
1894     }
1895 
1896     /*
1897     if (vsToolChain)
1898     {
1899         ConstructionStatementNode* argc = new ConstructionStatementNode(Span(), new IntNode(Span()), new IdentifierNode(Span(), U"argc"));
1900         argc->AddArgument(new InvokeNode(Span(), new IdentifierNode(Span(), U"RtArgc")));
1901         mainFunctionBody->AddStatement(argc);
1902         ConstructionStatementNode* argv = new ConstructionStatementNode(Span(), new ConstNode(Span(), new PointerNode(Span(), new PointerNode(Span(), new CharNode(Span())))), new IdentifierNode(Span(), U"argv"));
1903         argv->AddArgument(new InvokeNode(Span(), new IdentifierNode(Span(), U"RtArgv")));
1904         mainFunctionBody->AddStatement(argv);
1905     }
1906 */
1907 
1908     CompoundStatementNode* tryBlock = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
1909     if (!module.GetSymbolTable().JsonClasses().empty())
1910     {
1911         ExpressionStatementNode* registerJsonClassesCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()
1912             new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RegisterJsonClasses")));
1913         tryBlock->AddStatement(registerJsonClassesCall);
1914     }
1915     FunctionSymbol* userMain = module.GetSymbolTable().MainFunctionSymbol();
1916     InvokeNode* invokeMain = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()userMain->GroupName()));
1917     if (!userMain->Parameters().empty())
1918     {
1919         invokeMain->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"argc"));
1920         invokeMain->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"argv"));
1921     }
1922     StatementNode* callMainStatement = nullptr;
1923     if (!userMain->ReturnType() || userMain->ReturnType()->IsVoidType())
1924     {
1925         callMainStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeMain);
1926     }
1927     else
1928     {
1929         callMainStatement = new AssignmentStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode")invokeMain);
1930     }
1931     InvokeNode* invokeInitialize = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"Initialize"));
1932     StatementNode* callInitializeStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeInitialize);
1933     tryBlock->AddStatement(callInitializeStatement);
1934     tryBlock->AddStatement(callMainStatement);
1935     TryStatementNode* tryStatement = new TryStatementNode(Span()boost::uuids::nil_uuid()tryBlock);
1936     CompoundStatementNode* catchBlock = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
1937     InvokeNode* consoleError = new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"System.Console")
1938         new IdentifierNode(Span()boost::uuids::nil_uuid()U"Error")));
1939     DotNode* writeLine = new DotNode(Span()boost::uuids::nil_uuid()consoleErrornew IdentifierNode(Span()boost::uuids::nil_uuid()U"WriteLine"));
1940     InvokeNode* printEx = new InvokeNode(Span()boost::uuids::nil_uuid()writeLine);
1941     InvokeNode* exToString = new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"ex")
1942         new IdentifierNode(Span()boost::uuids::nil_uuid()U"ToString")));
1943     printEx->AddArgument(exToString);
1944     ExpressionStatementNode* printExStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()printEx);
1945     catchBlock->AddStatement(printExStatement);
1946     AssignmentStatementNode* assignExitCodeStatement = new AssignmentStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode")
1947         new IntLiteralNode(Span()boost::uuids::nil_uuid()1));
1948     catchBlock->AddStatement(assignExitCodeStatement);
1949     CatchNode* catchAll = new CatchNode(Span()boost::uuids::nil_uuid()new ConstNode(Span()boost::uuids::nil_uuid()new LValueRefNode(Span()boost::uuids::nil_uuid()
1950         new IdentifierNode(Span()boost::uuids::nil_uuid()U"System.Exception")))new IdentifierNode(Span()boost::uuids::nil_uuid()U"ex")catchBlock);
1951     tryStatement->AddCatch(catchAll);
1952     mainFunctionBody->AddStatement(tryStatement);
1953     ExpressionStatementNode* rtDoneCall = nullptr;
1954     if (GetGlobalFlag(GlobalFlags::profile))
1955     {
1956         rtDoneCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()new InvokeNode(Span()boost::uuids::nil_uuid()
1957             new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtEndProfiling")));
1958     }
1959     else
1960     {
1961         rtDoneCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtDone")));
1962     }
1963     mainFunctionBody->AddStatement(rtDoneCall);
1964     InvokeNode* exitCall = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtExit"));
1965     exitCall->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode"));
1966     ExpressionStatementNode* rtExitCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()exitCall);
1967     mainFunctionBody->AddStatement(rtExitCall);
1968     ReturnStatementNode* returnStatement = new ReturnStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode"));
1969     mainFunctionBody->AddStatement(returnStatement);
1970     mainFunction->SetBody(mainFunctionBody);
1971     mainCompileUnit.GlobalNs()->AddMember(mainFunction);
1972     SymbolCreatorVisitor symbolCreator(module.GetSymbolTable());
1973     mainCompileUnit.Accept(symbolCreator);
1974     BoundCompileUnit boundMainCompileUnit(module&mainCompileUnitattributeBinder);
1975     boundMainCompileUnit.PushBindingTypes();
1976     TypeBinder typeBinder(boundMainCompileUnit);
1977     mainCompileUnit.Accept(typeBinder);
1978     boundMainCompileUnit.PopBindingTypes();
1979     StatementBinder statementBinder(boundMainCompileUnit);
1980     mainCompileUnit.Accept(statementBinder);
1981     if (boundMainCompileUnit.HasGotos())
1982     {
1983         AnalyzeControlFlow(boundMainCompileUnit);
1984     }
1985     cmajor::codegen::GenerateCode(emittingContextboundMainCompileUnit);
1986     mainObjectFilePath = boundMainCompileUnit.ObjectFilePath();
1987     mainSourceFilePath = Path::ChangeExtension(boundMainCompileUnit.LLFilePath()".cpp");
1988 }
1989 
1990 void CreateMainUnitSystemX(std::std::vector<std::string>&objectFilePathsModule&modulecmajor::codegen::EmittingContext&emittingContextAttributeBinder*attributeBinder
1991     std::string& mainObjectFilePath)
1992 {
1993     CompileUnitNode mainCompileUnit(Span()boost::uuids::nil_uuid()boost::filesystem::path(module.OriginalFilePath()).parent_path().append("__main__.cm").generic_string());
1994     mainCompileUnit.SetSynthesizedUnit();
1995     mainCompileUnit.SetProgramMainUnit();
1996     mainCompileUnit.GlobalNs()->AddMember(new NamespaceImportNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"System")));
1997     FunctionNode * mainFunction(new FunctionNode(Span()boost::uuids::nil_uuid()Specifiers::public_new IntNode(Span()boost::uuids::nil_uuid())U"main"nullptr));
1998     mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new IntNode(Span()boost::uuids::nil_uuid())new IdentifierNode(Span()boost::uuids::nil_uuid()U"argc")));
1999     mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()
2000         new CharNode(Span()boost::uuids::nil_uuid())))new IdentifierNode(Span()boost::uuids::nil_uuid()U"argv")));
2001     mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()
2002         new CharNode(Span()boost::uuids::nil_uuid())))new IdentifierNode(Span()boost::uuids::nil_uuid()U"envp")));
2003     mainFunction->SetProgramMain();
2004     CompoundStatementNode* mainFunctionBody = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
2005     ConstructionStatementNode* constructExitCode = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new IntNode(Span()boost::uuids::nil_uuid())
2006         new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode"));
2007     mainFunctionBody->AddStatement(constructExitCode);
2008     CompoundStatementNode* tryBlock = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
2009     InvokeNode* invokeSetupEnvironment = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"StartupSetupEnvironment"));
2010     invokeSetupEnvironment->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"envp"));
2011     StatementNode* callSetEnvironmentStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeSetupEnvironment);
2012     tryBlock->AddStatement(callSetEnvironmentStatement);
2013     FunctionSymbol* userMain = module.GetSymbolTable().MainFunctionSymbol();
2014     InvokeNode* invokeMain = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()userMain->GroupName()));
2015     if (!userMain->Parameters().empty())
2016     {
2017         invokeMain->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"argc"));
2018         invokeMain->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"argv"));
2019     }
2020     StatementNode* callMainStatement = nullptr;
2021     if (!userMain->ReturnType() || userMain->ReturnType()->IsVoidType())
2022     {
2023         callMainStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeMain);
2024     }
2025     else
2026     {
2027         callMainStatement = new AssignmentStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode")invokeMain);
2028     }
2029     tryBlock->AddStatement(callMainStatement);
2030     TryStatementNode* tryStatement = new TryStatementNode(Span()boost::uuids::nil_uuid()tryBlock);
2031     CompoundStatementNode* catchBlock = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
2032     InvokeNode* consoleError = new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"System.Console")
2033         new IdentifierNode(Span()boost::uuids::nil_uuid()U"Error")));
2034     DotNode* writeLine = new DotNode(Span()boost::uuids::nil_uuid()consoleErrornew IdentifierNode(Span()boost::uuids::nil_uuid()U"WriteLine"));
2035     InvokeNode* printEx = new InvokeNode(Span()boost::uuids::nil_uuid()writeLine);
2036     InvokeNode* exToString = new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"ex")
2037         new IdentifierNode(Span()boost::uuids::nil_uuid()U"ToString")));
2038     printEx->AddArgument(exToString);
2039     ExpressionStatementNode* printExStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()printEx);
2040     catchBlock->AddStatement(printExStatement);
2041     AssignmentStatementNode* assignExitCodeStatement = new AssignmentStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode")
2042         new IntLiteralNode(Span()boost::uuids::nil_uuid()1));
2043     catchBlock->AddStatement(assignExitCodeStatement);
2044     CatchNode* catchAll = new CatchNode(Span()boost::uuids::nil_uuid()new ConstNode(Span()boost::uuids::nil_uuid()new LValueRefNode(Span()boost::uuids::nil_uuid()
2045         new IdentifierNode(Span()boost::uuids::nil_uuid()U"System.Exception")))new IdentifierNode(Span()boost::uuids::nil_uuid()U"ex")catchBlock);
2046     tryStatement->AddCatch(catchAll);
2047     mainFunctionBody->AddStatement(tryStatement);
2048     ReturnStatementNode* returnStatement = new ReturnStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode"));
2049     mainFunctionBody->AddStatement(returnStatement);
2050     mainFunction->SetBody(mainFunctionBody);
2051     mainCompileUnit.GlobalNs()->AddMember(mainFunction);
2052     SymbolCreatorVisitor symbolCreator(module.GetSymbolTable());
2053     mainCompileUnit.Accept(symbolCreator);
2054     BoundCompileUnit boundMainCompileUnit(module&mainCompileUnitattributeBinder);
2055     boundMainCompileUnit.PushBindingTypes();
2056     TypeBinder typeBinder(boundMainCompileUnit);
2057     mainCompileUnit.Accept(typeBinder);
2058     boundMainCompileUnit.PopBindingTypes();
2059     StatementBinder statementBinder(boundMainCompileUnit);
2060     mainCompileUnit.Accept(statementBinder);
2061     if (boundMainCompileUnit.HasGotos())
2062     {
2063         AnalyzeControlFlow(boundMainCompileUnit);
2064     }
2065     cmajor::codegen::GenerateCode(emittingContextboundMainCompileUnit);
2066     mainObjectFilePath = boundMainCompileUnit.ObjectFilePath();
2067 }
2068 
2069 void CreateMainUnitLlvmWindowsGUI(std::std::vector<std::string>&objectFilePathsModule&modulecmajor::codegen::EmittingContext&emittingContextAttributeBinder*attributeBinder
2070     std::string& mainObjectFilePath)
2071 {
2072     CompileUnitNode mainCompileUnit(Span()boost::uuids::nil_uuid()boost::filesystem::path(module.OriginalFilePath()).parent_path().append("__main__.cm").generic_string());
2073     mainCompileUnit.SetSynthesizedUnit();
2074     mainCompileUnit.SetProgramMainUnit();
2075     mainCompileUnit.GlobalNs()->AddMember(new NamespaceImportNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"System")));
2076     mainCompileUnit.GlobalNs()->AddMember(MakePolymorphicClassArray(module.GetSymbolTable().PolymorphicClasses()U"@polymorphicClassArray"));
2077     mainCompileUnit.GlobalNs()->AddMember(MakeStaticClassArray(module.GetSymbolTable().ClassesHavingStaticConstructor()U"@staticClassArray"));
2078     FunctionNode * mainFunction(new FunctionNode(Span()boost::uuids::nil_uuid()Specifiers::public_ | Specifiers::winapinew IntNode(Span()boost::uuids::nil_uuid())U"WinMain"nullptr));
2079     mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()new VoidNode(Span()boost::uuids::nil_uuid()))
2080         new IdentifierNode(Span()boost::uuids::nil_uuid()U"instance")));
2081     mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()new VoidNode(Span()boost::uuids::nil_uuid()))
2082         new IdentifierNode(Span()boost::uuids::nil_uuid()U"prevInstance")));
2083     mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()new CharNode(Span()boost::uuids::nil_uuid()))
2084         new IdentifierNode(Span()boost::uuids::nil_uuid()U"commandLine")));
2085     mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new IntNode(Span()boost::uuids::nil_uuid())new IdentifierNode(Span()boost::uuids::nil_uuid()U"cmdShow")));
2086     mainFunction->SetProgramMain();
2087     CompoundStatementNode* mainFunctionBody = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
2088     ConstructionStatementNode* constructExitCode = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new IntNode(Span()boost::uuids::nil_uuid())
2089         new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode"));
2090     mainFunctionBody->AddStatement(constructExitCode);
2091     ExpressionStatementNode* rtInitCall = nullptr;
2092     InvokeNode* invokeRtInit = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtInit"));
2093     invokeRtInit->AddArgument(new DivNode(Span()boost::uuids::nil_uuid()
2094         new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"@polymorphicClassArray")
2095             new IdentifierNode(Span()boost::uuids::nil_uuid()U"Length")))
2096         new LongLiteralNode(Span()boost::uuids::nil_uuid()4)));
2097     invokeRtInit->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()
2098         new IdentifierNode(Span()boost::uuids::nil_uuid()U"@polymorphicClassArray")new IdentifierNode(Span()boost::uuids::nil_uuid()U"CBegin"))));
2099     invokeRtInit->AddArgument(new DivNode(Span()boost::uuids::nil_uuid()
2100         new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"@staticClassArray")
2101             new IdentifierNode(Span()boost::uuids::nil_uuid()U"Length")))
2102         new LongLiteralNode(Span()boost::uuids::nil_uuid()2)));
2103     invokeRtInit->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"@staticClassArray")
2104         new IdentifierNode(Span()boost::uuids::nil_uuid()U"CBegin"))));
2105     invokeRtInit->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"GlobalInitCompileUnits"));
2106     rtInitCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeRtInit);
2107     mainFunctionBody->AddStatement(rtInitCall);
2108     ConstructionStatementNode* argc = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new IntNode(Span()boost::uuids::nil_uuid())
2109         new IdentifierNode(Span()boost::uuids::nil_uuid()U"argc"));
2110     argc->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtArgc")));
2111     mainFunctionBody->AddStatement(argc);
2112     ConstructionStatementNode* argv = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new ConstNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()
2113         new PointerNode(Span()boost::uuids::nil_uuid()new CharNode(Span()boost::uuids::nil_uuid()))))new IdentifierNode(Span()boost::uuids::nil_uuid()U"argv"));
2114     argv->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtArgv")));
2115     mainFunctionBody->AddStatement(argv);
2116     if (!module.GetSymbolTable().JsonClasses().empty())
2117     {
2118         ExpressionStatementNode* registerJsonClassesCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()new InvokeNode(Span()boost::uuids::nil_uuid()
2119             new IdentifierNode(Span()boost::uuids::nil_uuid()U"RegisterJsonClasses")));
2120         mainFunctionBody->AddStatement(registerJsonClassesCall);
2121     }
2122     CompoundStatementNode* tryBlock = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
2123     if (!module.GetSymbolTable().JsonClasses().empty())
2124     {
2125         ExpressionStatementNode* registerJsonClassesCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()new InvokeNode(Span()boost::uuids::nil_uuid()
2126             new IdentifierNode(Span()boost::uuids::nil_uuid()U"RegisterJsonClasses")));
2127         tryBlock->AddStatement(registerJsonClassesCall);
2128     }
2129     FunctionSymbol* userMain = module.GetSymbolTable().MainFunctionSymbol();
2130     InvokeNode* invokeMain = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()userMain->GroupName()));
2131     if (!userMain->Parameters().empty())
2132     {
2133         invokeMain->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"argc"));
2134         invokeMain->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"argv"));
2135     }
2136     StatementNode* callMainStatement = nullptr;
2137     if (!userMain->ReturnType() || userMain->ReturnType()->IsVoidType())
2138     {
2139         callMainStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeMain);
2140     }
2141     else
2142     {
2143         callMainStatement = new AssignmentStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode")invokeMain);
2144     }
2145     InvokeNode* invokeInitialize = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"Initialize"));
2146     StatementNode* callInitializeStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeInitialize);
2147     tryBlock->AddStatement(callInitializeStatement);
2148     InvokeNode* invokeSetInstance = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"WinSetInstance"));
2149     ExpressionStatementNode* setInstanceStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeSetInstance);
2150     tryBlock->AddStatement(setInstanceStatement);
2151     tryBlock->AddStatement(callMainStatement);
2152     TryStatementNode* tryStatement = new TryStatementNode(Span()boost::uuids::nil_uuid()tryBlock);
2153     CompoundStatementNode* catchBlock = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
2154     CatchNode* catchAll = new CatchNode(Span()boost::uuids::nil_uuid()new ConstNode(Span()boost::uuids::nil_uuid()new LValueRefNode(Span()boost::uuids::nil_uuid()
2155         new IdentifierNode(Span()boost::uuids::nil_uuid()U"System.Exception")))new IdentifierNode(Span()boost::uuids::nil_uuid()U"ex")catchBlock);
2156     tryStatement->AddCatch(catchAll);
2157     InvokeNode* invokeWinShowMessageBox = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"WinShowMessageBoxWithType"));
2158     InvokeNode* exToString = new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"ex")
2159         new IdentifierNode(Span()boost::uuids::nil_uuid()U"ToString")));
2160     ConstructionStatementNode* constructExStr = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"string")
2161         new IdentifierNode(Span()boost::uuids::nil_uuid()U"exStr"));
2162     constructExStr->AddArgument(exToString);
2163     catchBlock->AddStatement(constructExStr);
2164     ConstructionStatementNode* constructExCharPtr = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()
2165         new CharNode(Span()boost::uuids::nil_uuid()))new IdentifierNode(Span()boost::uuids::nil_uuid()U"exCharPtr"));
2166     catchBlock->AddStatement(constructExCharPtr);
2167     InvokeNode* invokeExChars = new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exStr")
2168         new IdentifierNode(Span()boost::uuids::nil_uuid()U"Chars")));
2169     constructExCharPtr->AddArgument(invokeExChars);
2170     invokeWinShowMessageBox->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"exCharPtr"));
2171     invokeWinShowMessageBox->AddArgument(new NullLiteralNode(Span()boost::uuids::nil_uuid()));
2172     invokeWinShowMessageBox->AddArgument(new NullLiteralNode(Span()boost::uuids::nil_uuid()));
2173     invokeWinShowMessageBox->AddArgument(new UIntLiteralNode(Span()boost::uuids::nil_uuid()0x00000010 | 0x00000000));
2174     ExpressionStatementNode* showMessageBoxStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeWinShowMessageBox);
2175     catchBlock->AddStatement(showMessageBoxStatement);
2176     AssignmentStatementNode* assignExitCodeStatement = new AssignmentStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode")
2177         new IntLiteralNode(Span()boost::uuids::nil_uuid()1));
2178     catchBlock->AddStatement(assignExitCodeStatement);
2179     mainFunctionBody->AddStatement(tryStatement);
2180     ExpressionStatementNode* winDoneCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()new InvokeNode(Span()boost::uuids::nil_uuid()
2181         new IdentifierNode(Span()boost::uuids::nil_uuid()U"WinDone")));
2182     mainFunctionBody->AddStatement(winDoneCall);
2183     ExpressionStatementNode* rtDoneCall = nullptr;
2184     rtDoneCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtDone")));
2185     mainFunctionBody->AddStatement(rtDoneCall);
2186     InvokeNode* exitCall = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtExit"));
2187     exitCall->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode"));
2188     ExpressionStatementNode* rtExitCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()exitCall);
2189     mainFunctionBody->AddStatement(rtExitCall);
2190     ReturnStatementNode* returnStatement = new ReturnStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode"));
2191     mainFunctionBody->AddStatement(returnStatement);
2192     mainFunction->SetBody(mainFunctionBody);
2193     mainCompileUnit.GlobalNs()->AddMember(mainFunction);
2194     SymbolCreatorVisitor symbolCreator(module.GetSymbolTable());
2195     mainCompileUnit.Accept(symbolCreator);
2196     BoundCompileUnit boundMainCompileUnit(module&mainCompileUnitattributeBinder);
2197     boundMainCompileUnit.PushBindingTypes();
2198     TypeBinder typeBinder(boundMainCompileUnit);
2199     mainCompileUnit.Accept(typeBinder);
2200     boundMainCompileUnit.PopBindingTypes();
2201     StatementBinder statementBinder(boundMainCompileUnit);
2202     mainCompileUnit.Accept(statementBinder);
2203     if (boundMainCompileUnit.HasGotos())
2204     {
2205         AnalyzeControlFlow(boundMainCompileUnit);
2206     }
2207     cmajor::codegen::GenerateCode(emittingContextboundMainCompileUnit);
2208     mainObjectFilePath = boundMainCompileUnit.ObjectFilePath();
2209 }
2210 
2211 void CreateMainUnitCppWindowsGUI(std::std::vector<std::string>&objectFilePathsModule&modulecmajor::codegen::EmittingContext&emittingContextAttributeBinder*attributeBinder
2212     std::string& mainObjectFilePathstd::string& mainSourceFilePath)
2213 {
2214     CompileUnitNode mainCompileUnit(Span()boost::uuids::nil_uuid()boost::filesystem::path(module.OriginalFilePath()).parent_path().append("__main__.cm").generic_string());
2215     mainCompileUnit.SetSynthesizedUnit();
2216     mainCompileUnit.SetProgramMainUnit();
2217     mainCompileUnit.GlobalNs()->AddMember(new NamespaceImportNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"System")));
2218     mainCompileUnit.GlobalNs()->AddMember(MakePolymorphicClassArray(module.GetSymbolTable().PolymorphicClasses()U"__polymorphicClassArray"));
2219     mainCompileUnit.GlobalNs()->AddMember(MakeStaticClassArray(module.GetSymbolTable().ClassesHavingStaticConstructor()U"__staticClassArray"));
2220     FunctionNode * mainFunction(new FunctionNode(Span()boost::uuids::nil_uuid()Specifiers::public_ | Specifiers::winapinew IntNode(Span()boost::uuids::nil_uuid())U"wWinMain"nullptr));
2221     mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()new VoidNode(Span()boost::uuids::nil_uuid()))
2222         new IdentifierNode(Span()boost::uuids::nil_uuid()U"instance")));
2223     mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()new VoidNode(Span()boost::uuids::nil_uuid()))
2224         new IdentifierNode(Span()boost::uuids::nil_uuid()U"prevInstance")));
2225     mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()new CharNode(Span()boost::uuids::nil_uuid()))
2226         new IdentifierNode(Span()boost::uuids::nil_uuid()U"commandLine")));
2227     mainFunction->AddParameter(new ParameterNode(Span()boost::uuids::nil_uuid()new IntNode(Span()boost::uuids::nil_uuid())new IdentifierNode(Span()boost::uuids::nil_uuid()U"cmdShow")));
2228     mainFunction->SetProgramMain();
2229     CompoundStatementNode* mainFunctionBody = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
2230     ConstructionStatementNode* constructExitCode = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new IntNode(Span()boost::uuids::nil_uuid())
2231         new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode"));
2232     mainFunctionBody->AddStatement(constructExitCode);
2233     ExpressionStatementNode* rtInitCall = nullptr;
2234     InvokeNode* invokeRtInit = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtInit"));
2235     invokeRtInit->AddArgument(new DivNode(Span()boost::uuids::nil_uuid()
2236         new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"__polymorphicClassArray")
2237             new IdentifierNode(Span()boost::uuids::nil_uuid()U"Length")))
2238         new LongLiteralNode(Span()boost::uuids::nil_uuid()4)));
2239     invokeRtInit->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()
2240         U"__polymorphicClassArray")new IdentifierNode(Span()boost::uuids::nil_uuid()U"CBegin"))));
2241     invokeRtInit->AddArgument(new DivNode(Span()boost::uuids::nil_uuid()
2242         new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"__staticClassArray")
2243             new IdentifierNode(Span()boost::uuids::nil_uuid()U"Length")))
2244         new LongLiteralNode(Span()boost::uuids::nil_uuid()2)));
2245     invokeRtInit->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()
2246         new IdentifierNode(Span()boost::uuids::nil_uuid()U"__staticClassArray")new IdentifierNode(Span()boost::uuids::nil_uuid()U"CBegin"))));
2247     invokeRtInit->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"GlobalInitCompileUnits"));
2248     rtInitCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeRtInit);
2249     mainFunctionBody->AddStatement(rtInitCall);
2250     ConstructionStatementNode* argc = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new IntNode(Span()boost::uuids::nil_uuid())
2251         new IdentifierNode(Span()boost::uuids::nil_uuid()U"argc"));
2252     argc->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtArgc")));
2253     mainFunctionBody->AddStatement(argc);
2254     ConstructionStatementNode* argv = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new ConstNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()
2255         new PointerNode(Span()boost::uuids::nil_uuid()new CharNode(Span()boost::uuids::nil_uuid()))))new IdentifierNode(Span()boost::uuids::nil_uuid()U"argv"));
2256     argv->AddArgument(new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtArgv")));
2257     mainFunctionBody->AddStatement(argv);
2258     if (!module.GetSymbolTable().JsonClasses().empty())
2259     {
2260         ExpressionStatementNode* registerJsonClassesCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()new InvokeNode(Span()boost::uuids::nil_uuid()
2261             new IdentifierNode(Span()boost::uuids::nil_uuid()U"RegisterJsonClasses")));
2262         mainFunctionBody->AddStatement(registerJsonClassesCall);
2263     }
2264     CompoundStatementNode* tryBlock = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
2265     if (!module.GetSymbolTable().JsonClasses().empty())
2266     {
2267         ExpressionStatementNode* registerJsonClassesCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()new InvokeNode(Span()boost::uuids::nil_uuid()
2268             new IdentifierNode(Span()boost::uuids::nil_uuid()U"RegisterJsonClasses")));
2269         tryBlock->AddStatement(registerJsonClassesCall);
2270     }
2271     FunctionSymbol* userMain = module.GetSymbolTable().MainFunctionSymbol();
2272     InvokeNode* invokeMain = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()userMain->GroupName()));
2273     if (!userMain->Parameters().empty())
2274     {
2275         invokeMain->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"argc"));
2276         invokeMain->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"argv"));
2277     }
2278     StatementNode* callMainStatement = nullptr;
2279     if (!userMain->ReturnType() || userMain->ReturnType()->IsVoidType())
2280     {
2281         callMainStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeMain);
2282     }
2283     else
2284     {
2285         callMainStatement = new AssignmentStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode")invokeMain);
2286     }
2287     InvokeNode* invokeInitialize = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"Initialize"));
2288     StatementNode* callInitializeStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeInitialize);
2289     tryBlock->AddStatement(callInitializeStatement);
2290     InvokeNode* invokeSetInstance = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"WinSetInstance"));
2291     ExpressionStatementNode* setInstanceStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeSetInstance);
2292     tryBlock->AddStatement(setInstanceStatement);
2293     tryBlock->AddStatement(callMainStatement);
2294     TryStatementNode* tryStatement = new TryStatementNode(Span()boost::uuids::nil_uuid()tryBlock);
2295     CompoundStatementNode* catchBlock = new CompoundStatementNode(Span()boost::uuids::nil_uuid());
2296     CatchNode* catchAll = new CatchNode(Span()boost::uuids::nil_uuid()new ConstNode(Span()boost::uuids::nil_uuid()new LValueRefNode(Span()boost::uuids::nil_uuid()
2297         new IdentifierNode(Span()boost::uuids::nil_uuid()U"System.Exception")))new IdentifierNode(Span()boost::uuids::nil_uuid()U"ex")catchBlock);
2298     tryStatement->AddCatch(catchAll);
2299     InvokeNode* invokeWinShowMessageBox = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"WinShowMessageBoxWithType"));
2300     InvokeNode* exToString = new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"ex")
2301         new IdentifierNode(Span()boost::uuids::nil_uuid()U"ToString")));
2302     ConstructionStatementNode* constructExStr = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"string")
2303         new IdentifierNode(Span()boost::uuids::nil_uuid()U"exStr"));
2304     constructExStr->AddArgument(exToString);
2305     catchBlock->AddStatement(constructExStr);
2306     ConstructionStatementNode* constructExCharPtr = new ConstructionStatementNode(Span()boost::uuids::nil_uuid()new PointerNode(Span()boost::uuids::nil_uuid()
2307         new CharNode(Span()boost::uuids::nil_uuid()))new IdentifierNode(Span()boost::uuids::nil_uuid()U"exCharPtr"));
2308     catchBlock->AddStatement(constructExCharPtr);
2309     InvokeNode* invokeExChars = new InvokeNode(Span()boost::uuids::nil_uuid()new DotNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exStr")
2310         new IdentifierNode(Span()boost::uuids::nil_uuid()U"Chars")));
2311     constructExCharPtr->AddArgument(invokeExChars);
2312     invokeWinShowMessageBox->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"exCharPtr"));
2313     invokeWinShowMessageBox->AddArgument(new NullLiteralNode(Span()boost::uuids::nil_uuid()));
2314     invokeWinShowMessageBox->AddArgument(new NullLiteralNode(Span()boost::uuids::nil_uuid()));
2315     invokeWinShowMessageBox->AddArgument(new UIntLiteralNode(Span()boost::uuids::nil_uuid()0x00000010 | 0x00000000));
2316     ExpressionStatementNode* showMessageBoxStatement = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()invokeWinShowMessageBox);
2317     catchBlock->AddStatement(showMessageBoxStatement);
2318     AssignmentStatementNode* assignExitCodeStatement = new AssignmentStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode")
2319         new IntLiteralNode(Span()boost::uuids::nil_uuid()1));
2320     catchBlock->AddStatement(assignExitCodeStatement);
2321     mainFunctionBody->AddStatement(tryStatement);
2322     ExpressionStatementNode* winDoneCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()new InvokeNode(Span()boost::uuids::nil_uuid()
2323         new IdentifierNode(Span()boost::uuids::nil_uuid()U"WinDone")));
2324     mainFunctionBody->AddStatement(winDoneCall);
2325     ExpressionStatementNode* rtDoneCall = nullptr;
2326     rtDoneCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtDone")));
2327     mainFunctionBody->AddStatement(rtDoneCall);
2328     InvokeNode* exitCall = new InvokeNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"RtExit"));
2329     exitCall->AddArgument(new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode"));
2330     ExpressionStatementNode* rtExitCall = new ExpressionStatementNode(Span()boost::uuids::nil_uuid()exitCall);
2331     mainFunctionBody->AddStatement(rtExitCall);
2332     ReturnStatementNode* returnStatement = new ReturnStatementNode(Span()boost::uuids::nil_uuid()new IdentifierNode(Span()boost::uuids::nil_uuid()U"exitCode"));
2333     mainFunctionBody->AddStatement(returnStatement);
2334     mainFunction->SetBody(mainFunctionBody);
2335     mainCompileUnit.GlobalNs()->AddMember(mainFunction);
2336     SymbolCreatorVisitor symbolCreator(module.GetSymbolTable());
2337     mainCompileUnit.Accept(symbolCreator);
2338     BoundCompileUnit boundMainCompileUnit(module&mainCompileUnitattributeBinder);
2339     boundMainCompileUnit.PushBindingTypes();
2340     TypeBinder typeBinder(boundMainCompileUnit);
2341     mainCompileUnit.Accept(typeBinder);
2342     boundMainCompileUnit.PopBindingTypes();
2343     StatementBinder statementBinder(boundMainCompileUnit);
2344     mainCompileUnit.Accept(statementBinder);
2345     if (boundMainCompileUnit.HasGotos())
2346     {
2347         AnalyzeControlFlow(boundMainCompileUnit);
2348     }
2349     cmajor::codegen::GenerateCode(emittingContextboundMainCompileUnit);
2350     mainObjectFilePath = boundMainCompileUnit.ObjectFilePath();
2351     mainSourceFilePath = Path::ChangeExtension(boundMainCompileUnit.LLFilePath()".cpp");
2352 }
2353 
2354 void SetDefines(Module* moduleconst std::string& definesFilePath)
2355 {
2356     module->ClearDefines();
2357     if (GetConfig() == "debug")
2358     {
2359         module->DefineSymbol(U"DEBUG");
2360     }
2361     else if (GetConfig() == "release")
2362     {
2363         module->DefineSymbol(U"RELEASE");
2364     }
2365     else if (GetConfig() == "profile")
2366     {
2367         module->DefineSymbol(U"RELEASE");
2368         module->DefineSymbol(U"PROFILE");
2369     }
2370 #ifdef _WIN32
2371 
2372 #else
2373     module->DefineSymbol(U"LINUX");
2374 #endif
2375     std::ifstream definesFile(definesFilePath);
2376     if (definesFile)
2377     {
2378         std::string line;
2379         while (std::getline(definesFileline))
2380         {
2381             module->DefineSymbol(ToUtf32(line));
2382         }
2383     }
2384 }
2385 
2386 void InstallSystemLibraries(Module* systemInstallModule)
2387 {
2388     if (GetGlobalFlag(GlobalFlags::verbose))
2389     {
2390         LogMessage(systemInstallModule->LogStreamId()"Installing system libraries...");
2391     }
2392     sngcm::ast::BackEnd backend = sngcm::ast::BackEnd::llvm;
2393     if (GetBackEnd() == cmajor::symbols::BackEnd::cmsx)
2394     {
2395         backend = sngcm::ast::BackEnd::cmsx;
2396     }
2397     else if (GetBackEnd() == cmajor::symbols::BackEnd::cmcpp)
2398     {
2399         backend = sngcm::ast::BackEnd::cppcm;
2400     }
2401     SystemDirKind systemDirKind = SystemDirKind::regular;
2402     if (GetGlobalFlag(GlobalFlags::repository))
2403     {
2404         systemDirKind = SystemDirKind::repository;
2405     }
2406     boost::filesystem::path systemLibDir = CmajorSystemLibDir(GetConfig()backendGetToolChain()systemDirKind);
2407     boost::filesystem::create_directories(systemLibDir);
2408     for (Module* systemModule : systemInstallModule->AllReferencedModules())
2409     {
2410         boost::filesystem::path from = systemModule->OriginalFilePath();
2411         boost::filesystem::path to = systemLibDir / from.filename();
2412         if (boost::filesystem::exists(to))
2413         {
2414             boost::filesystem::remove(to);
2415         }
2416         boost::filesystem::copy(fromto);
2417         if (GetGlobalFlag(GlobalFlags::verbose))
2418         {
2419             LogMessage(systemInstallModule->LogStreamId()from.generic_string() + " -> " + to.generic_string());
2420         }
2421         if (!systemModule->LibraryFilePath().empty() && !GetGlobalFlag(GlobalFlags::disableCodeGen))
2422         {
2423             from = systemModule->LibraryFilePath();
2424             to = systemLibDir / from.filename();
2425             if (boost::filesystem::exists(to))
2426             {
2427                 boost::filesystem::remove(to);
2428             }
2429             boost::filesystem::copy(fromto);
2430             if (GetGlobalFlag(GlobalFlags::verbose))
2431             {
2432                 LogMessage(systemInstallModule->LogStreamId()from.generic_string() + " -> " + to.generic_string());
2433             }
2434         }
2435     }
2436     if (GetGlobalFlag(GlobalFlags::verbose))
2437     {
2438         LogMessage(systemInstallModule->LogStreamId()"System libraries installed.");
2439     }
2440 }
2441 
2442 void InstallSystemWindowsLibraries(Module* systemInstallWindowsModule)
2443 {
2444     if (GetGlobalFlag(GlobalFlags::verbose))
2445     {
2446         LogMessage(systemInstallWindowsModule->LogStreamId()"Installing system libraries (Windows)...");
2447     }
2448     sngcm::ast::BackEnd backend = sngcm::ast::BackEnd::llvm;
2449     if (GetBackEnd() == cmajor::symbols::BackEnd::cmsx)
2450     {
2451         backend = sngcm::ast::BackEnd::cmsx;
2452     }
2453     else if (GetBackEnd() == cmajor::symbols::BackEnd::cmcpp)
2454     {
2455         backend = sngcm::ast::BackEnd::cppcm;
2456     }
2457     SystemDirKind systemDirKind = SystemDirKind::regular;
2458     if (GetGlobalFlag(GlobalFlags::repository))
2459     {
2460         systemDirKind = SystemDirKind::repository;
2461     }
2462     boost::filesystem::path systemLibDir = CmajorSystemLibDir(GetConfig()backendGetToolChain()systemDirKind);
2463     boost::filesystem::create_directories(systemLibDir);
2464     for (Module* systemModule : systemInstallWindowsModule->AllReferencedModules())
2465     {
2466         boost::filesystem::path from = systemModule->OriginalFilePath();
2467         boost::filesystem::path to = systemLibDir / from.filename();
2468         if (boost::filesystem::exists(to))
2469         {
2470             boost::filesystem::remove(to);
2471         }
2472         boost::filesystem::copy(fromto);
2473         if (GetGlobalFlag(GlobalFlags::verbose))
2474         {
2475             LogMessage(systemInstallWindowsModule->LogStreamId()from.generic_string() + " -> " + to.generic_string());
2476         }
2477         if (!systemModule->LibraryFilePath().empty() && !GetGlobalFlag(GlobalFlags::disableCodeGen))
2478         {
2479             from = systemModule->LibraryFilePath();
2480             to = systemLibDir / from.filename();
2481             if (boost::filesystem::exists(to))
2482             {
2483                 boost::filesystem::remove(to);
2484             }
2485             boost::filesystem::copy(fromto);
2486             if (GetGlobalFlag(GlobalFlags::verbose))
2487             {
2488                 LogMessage(systemInstallWindowsModule->LogStreamId()from.generic_string() + " -> " + to.generic_string());
2489             }
2490         }
2491     }
2492     if (GetGlobalFlag(GlobalFlags::verbose))
2493     {
2494         LogMessage(systemInstallWindowsModule->LogStreamId()"System libraries installed.");
2495     }
2496 }
2497 
2498 void CompileSingleThreaded(Project* projectModule* rootModulestd::std::vector<std::std::unique_ptr<BoundCompileUnit>>&boundCompileUnitscmajor::codegen::EmittingContext&emittingContext
2499     std::std::vector<std::string>&objectFilePathsstd::std::unordered_map<intcmdoclib::File>&docFileMapbool&stop)
2500 {
2501     if (GetGlobalFlag(GlobalFlags::verbose))
2502     {
2503         LogMessage(project->LogStreamId()"Compiling...");
2504     }
2505     rootModule->StartBuild();
2506     int maxFileIndex = 0;
2507     for (std::std::unique_ptr<BoundCompileUnit>&boundCompileUnit : boundCompileUnits)
2508     {
2509         if (stop)
2510         {
2511             return;
2512         }
2513         if (GetGlobalFlag(GlobalFlags::verbose))
2514         {
2515             LogMessage(project->LogStreamId()"> " + boost::filesystem::path(boundCompileUnit->GetCompileUnitNode()->FilePath()).filename().generic_string());
2516         }
2517         BindStatements(*boundCompileUnit);
2518         if (boundCompileUnit->HasGotos())
2519         {
2520             AnalyzeControlFlow(*boundCompileUnit);
2521         }
2522         if (GetGlobalFlag(GlobalFlags::bdt2xml))
2523         {
2524             std::unique_ptr<sngxml::dom::Document> bdtDoc = cmajor::bdt2dom::GenerateBdtDocument(boundCompileUnit.get());
2525             std::string bdtXmlFilePath = Path::ChangeExtension(boundCompileUnit->GetCompileUnitNode()->FilePath()".bdt.xml");
2526             std::ofstream bdtXmlFile(bdtXmlFilePath);
2527             CodeFormatter formatter(bdtXmlFile);
2528             formatter.SetIndentSize(1);
2529             bdtDoc->Write(formatter);
2530         }
2531         if (GetGlobalFlag(GlobalFlags::cmdoc))
2532         {
2533             cmdoclib::GenerateSourceCode(projectboundCompileUnit.get()docFileMap);
2534             maxFileIndex = std::max(maxFileIndexboundCompileUnit->GetCompileUnitNode()->GetSpan().fileIndex);
2535         }
2536         else
2537         {
2538             cmajor::codegen::GenerateCode(emittingContext*boundCompileUnit);
2539             objectFilePaths.push_back(boundCompileUnit->ObjectFilePath());
2540         }
2541     }
2542     if (GetGlobalFlag(GlobalFlags::cmdoc))
2543     {
2544         cmdoclib::GenerateLexerAndParserHtmlSources(projectmaxFileIndexdocFileMap);
2545     }
2546     rootModule->StopBuild();
2547     if (GetGlobalFlag(GlobalFlags::verbose))
2548     {
2549         LogMessage(rootModule->LogStreamId()ToUtf8(rootModule->Name()) + " compilation time: " + FormatTimeMs(rootModule->GetBuildTimeMs()));
2550     }
2551 }
2552 
2553 int64_t compileDebugStart = 0;
2554 
2555 std::string CurrentCompileDebugMsStr()
2556 {
2557     return FormatTimeMs(static_cast<int32_t>(CurrentMs() - compileDebugStart));
2558 }
2559 
2560 int compileGetTimeoutSecs = 3;
2561 
2562 class CompileQueue 
2563 {
2564 public:
2565     CompileQueue(std::mutex* mtx_const std::string& name_bool& stop_bool& ready_int logStreamId_);
2566     void Put(int compileUnitIndex);
2567     int Get();
2568     void NotifyAll();
2569 private:
2570     std::mutex* mtx;
2571     std::string name;
2572     std::list<int> queue;
2573     std::condition_variable cond;
2574     bool& stop;
2575     bool& ready;
2576     int logStreamId;
2577 };
2578 
2579 CompileQueue::CompileQueue(std::mutex* mtx_const std::string& name_bool& stop_bool& ready_int logStreamId_) :
2580     mtx(mtx_)name(name_)stop(stop_)ready(ready_)logStreamId(logStreamId_)
2581 {
2582 }
2583 
2584 void CompileQueue::Put(int compileUnitIndex)
2585 {
2586     std::lock_guard<std::mutex> lock(*mtx);
2587     queue.push_back(compileUnitIndex);
2588     cond.notify_one();
2589 }
2590 
2591 int CompileQueue::Get()
2592 {
2593     while (!stop && !ready)
2594     {
2595         std::unique_lock<std::mutex> lock(*mtx);
2596         cond.wait(lock[this] { return stop || ready || !queue.empty(); });
2597         if (stop || ready) return -1;
2598         int compileUnitIndex = queue.front();
2599         queue.pop_front();
2600         return compileUnitIndex;
2601     }
2602     return -1;
2603 }
2604 
2605 void CompileQueue::NotifyAll()
2606 {
2607     cond.notify_all();
2608 }
2609 
2610 struct CompileData 
2611 {
2612     CompileData(std::mutex* mtx_Module* rootModule_std::std::vector<std::std::unique_ptr<BoundCompileUnit>>&boundCompileUnits_std::std::vector<std::string>&objectFilePaths_bool&stop_bool&ready_
2613         int numThreads_CompileQueue& input_CompileQueue& output_) :
2614         mtx(mtx_)rootModule(rootModule_)boundCompileUnits(boundCompileUnits_)objectFilePaths(objectFilePaths_)stop(stop_)ready(ready_)numThreads(numThreads_)
2615         input(input_)output(output_)
2616     {
2617         exceptions.resize(numThreads);
2618         sourceFileFilePaths.resize(boundCompileUnits.size());
2619         for (int i = 0; i < boundCompileUnits.size(); ++i)
2620         {
2621             sourceFileFilePaths[i] = boundCompileUnits[i]->GetCompileUnitNode()->FilePath();
2622         }
2623     }
2624     std::mutex* mtx;
2625     Module* rootModule;
2626     std::vector<std::string> sourceFileFilePaths;
2627     std::std::vector<std::std::unique_ptr<BoundCompileUnit>>&boundCompileUnits;
2628     std::std::vector<std::string>&objectFilePaths;
2629     bool& stop;
2630     bool& ready;
2631     int numThreads;
2632     CompileQueue& input;
2633     CompileQueue& output;
2634     std::vector<std::exception_ptr> exceptions;
2635 };
2636 
2637 void GenerateCode(CompileData* dataint threadId)
2638 {
2639     try
2640     {
2641         SetRootModuleForCurrentThread(data->rootModule);
2642         cmajor::codegen::EmittingContext emittingContext(GetOptimizationLevel());
2643         while (!data->stop && !data->ready)
2644         {
2645             int compileUnitIndex = data->input.Get();
2646             if (compileUnitIndex >= 0 && compileUnitIndex < data->boundCompileUnits.size())
2647             {
2648                 if (GetGlobalFlag(GlobalFlags::debugCompile))
2649                 {
2650                     LogMessage(-1data->sourceFileFilePaths[compileUnitIndex] + " " + std::to_string(compileUnitIndex) + " : GET INPUT " + std::to_string(compileUnitIndex));
2651                 }
2652                 BoundCompileUnit* compileUnit = data->boundCompileUnits[compileUnitIndex].get();
2653                 cmajor::codegen::GenerateCode(emittingContext*compileUnit);
2654                 if (GetGlobalFlag(GlobalFlags::debugCompile))
2655                 {
2656                     LogMessage(-1data->sourceFileFilePaths[compileUnitIndex] + " " + std::to_string(compileUnitIndex) + " : PUT OUTPUT " + std::to_string(compileUnitIndex));
2657                 }
2658                 {
2659                     std::lock_guard<std::mutex> lock(*data->mtx);
2660                     data->objectFilePaths.push_back(compileUnit->ObjectFilePath());
2661                     data->boundCompileUnits[compileUnitIndex].reset();
2662                 }
2663                 data->output.Put(compileUnitIndex);
2664             }
2665         }
2666     }
2667     catch (...)
2668     {
2669         std::lock_guard<std::mutex> lock(*data->mtx);
2670         std::exception_ptr exception = std::current_exception();
2671         if (threadId >= 0 && threadId < data->exceptions.size())
2672         {
2673             data->exceptions[threadId] = exception;
2674         }
2675         data->stop = true;
2676         data->output.NotifyAll();
2677     }
2678 }
2679 
2680 void CompileMultiThreaded(Project* projectModule* rootModulestd::std::vector<std::std::unique_ptr<BoundCompileUnit>>&boundCompileUnitsstd::std::vector<std::string>&objectFilePaths
2681     bool& stop)
2682 {
2683     int numThreads = std::min(static_cast<int>(std::thread::hardware_concurrency())static_cast<int>(boundCompileUnits.size()));
2684     if (numThreads <= 0)
2685     {
2686         numThreads = 1;
2687     }
2688     if (GetGlobalFlag(GlobalFlags::verbose))
2689     {
2690         LogMessage(project->LogStreamId()"Compiling using " + std::to_string(numThreads) + " threads...");
2691     }
2692     compileDebugStart = CurrentMs();
2693     rootModule->StartBuild();
2694     bool ready = false;
2695     std::mutex mtx;
2696     CompileQueue input(&mtx"input"stopreadyrootModule->LogStreamId());
2697     CompileQueue output(&mtx"output"stopreadyrootModule->LogStreamId());
2698     CompileData compileData(&mtxrootModuleboundCompileUnitsobjectFilePathsstopreadynumThreadsinputoutput);
2699     std::vector<std::thread> threads;
2700     for (int i = 0; i < numThreads; ++i)
2701     {
2702         threads.push_back(std::thread({GenerateCode&compileDatai }));
2703     }
2704     int n = boundCompileUnits.size();
2705     for (int i = 0; i < n; ++i)
2706     {
2707         BoundCompileUnit* compileUnit = boundCompileUnits[i].get();
2708         if (GetGlobalFlag(GlobalFlags::verbose))
2709         {
2710             LogMessage(rootModule->LogStreamId()"> " + compileUnit->GetCompileUnitNode()->FilePath());
2711         }
2712         try
2713         {
2714             BindStatements(*compileUnit);
2715             if (compileUnit->HasGotos())
2716             {
2717                 AnalyzeControlFlow(*compileUnit);
2718             }
2719             compileUnit->SetImmutable();
2720         }
2721         catch (...)
2722         {
2723             stop = true;
2724             input.NotifyAll();
2725             for (int i = 0; i < numThreads; ++i)
2726             {
2727                 if (threads[i].joinable())
2728                 {
2729                     threads[i].join();
2730                 }
2731             }
2732             throw ;
2733         }
2734         if (GetGlobalFlag(GlobalFlags::debugCompile))
2735         {
2736             LogMessage(rootModule->LogStreamId()compileData.sourceFileFilePaths[i] + " : PUT INPUT " + std::to_string(i));
2737         }
2738         input.Put(i);
2739     }
2740     int numOutputsReceived = 0;
2741     while (numOutputsReceived < n && !stop)
2742     {
2743         int compileUnitIndex = output.Get();
2744         if (compileUnitIndex != -1)
2745         {
2746             if (GetGlobalFlag(GlobalFlags::debugCompile))
2747             {
2748                 LogMessage(rootModule->LogStreamId()compileData.sourceFileFilePaths[compileUnitIndex] + " : GET OUTPUT " + std::to_string(compileUnitIndex));
2749             }
2750         }
2751         if (compileUnitIndex != -1)
2752         {
2753             ++numOutputsReceived;
2754         }
2755     }
2756     if (GetGlobalFlag(GlobalFlags::debugCompile))
2757     {
2758         LogMessage(rootModule->LogStreamId()ToUtf8(rootModule->Name()) + " > BEGIN READY");
2759     }
2760     {
2761         std::lock_guard<std::mutex> lock(mtx);
2762         ready = true;
2763         compileData.input.NotifyAll();
2764     }
2765     if (GetGlobalFlag(GlobalFlags::debugCompile))
2766     {
2767         LogMessage(rootModule->LogStreamId()ToUtf8(rootModule->Name()) + " < END READY");
2768     }
2769     for (int i = 0; i < numThreads; ++i)
2770     {
2771         if (threads[i].joinable())
2772         {
2773             threads[i].join();
2774         }
2775     }
2776     for (int i = 0; i < numThreads; ++i)
2777     {
2778         if (compileData.exceptions[i])
2779         {
2780             std::rethrow_exception(compileData.exceptions[i]);
2781         }
2782     }
2783     rootModule->StopBuild();
2784     if (GetGlobalFlag(GlobalFlags::verbose))
2785     {
2786         LogMessage(rootModule->LogStreamId()ToUtf8(rootModule->Name()) + " compilation time: " + FormatTimeMs(rootModule->GetBuildTimeMs()));
2787     }
2788 }
2789 
2790 std::std::unique_ptr<Project>ReadProject(conststd::string&projectFilePath)
2791 {
2792     SystemDirKind systemDirKind = SystemDirKind::regular;
2793     if (GetGlobalFlag(GlobalFlags::repository))
2794     {
2795         systemDirKind = SystemDirKind::repository;
2796     }
2797     std::string config = GetConfig();
2798     MappedInputFile projectFile(projectFilePath);
2799     std::u32string p(ToUtf32(std::string(projectFile.Begin()projectFile.End())));
2800     sngcm::ast::BackEnd backend = sngcm::ast::BackEnd::llvm;
2801     if (GetBackEnd() == cmajor::symbols::BackEnd::cmsx)
2802     {
2803         backend = sngcm::ast::BackEnd::cmsx;
2804     }
2805     else if (GetBackEnd() == cmajor::symbols::BackEnd::cmcpp)
2806     {
2807         backend = sngcm::ast::BackEnd::cppcm;
2808     }
2809     ContainerFileLexer containerFileLexer(pprojectFilePath0);
2810     std::unique_ptr<Project> project = ProjectFileParser::Parse(containerFileLexerconfigbackendGetToolChain()systemDirKind);
2811     project->ResolveDeclarations();
2812     return project;
2813 }
2814 
2815 void WriteProjectInfo(Project* projectstd::std::vector<std::std::unique_ptr<CompileUnitNode>>&compileUnits)
2816 {
2817     if (GetGlobalFlag(GlobalFlags::verbose))
2818     {
2819         LogMessage(project->LogStreamId()"Writing project info file...");
2820     }
2821     Preprocess(projectcompileUnits);
2822     ProjectInfo projectInfo;
2823     projectInfo.projectFilePath = project->FilePath();
2824     projectInfo.projectId = project->Id();
2825     projectInfo.projectHash = project->Hash();
2826     projectInfo.projectName = ToUtf8(project->Name());
2827     projectInfo.target = TargetStr(project->GetTarget());
2828     for (const std::string& dependsOnId : project->DependsOnIds())
2829     {
2830         projectInfo.dependsOnProjects.push_back(dependsOnId);
2831     }
2832     for (const auto& compileUnit : compileUnits)
2833     {
2834         SourceFileInfo sourceFileInfo;
2835         sourceFileInfo.filePath = compileUnit->FilePath();
2836         sourceFileInfo.fileId = compileUnit->Id();
2837         sourceFileInfo.fileHash = compileUnit->Hash();
2838         projectInfo.fileInfos.push_back(sourceFileInfo);
2839     }
2840     std::string projectInfoFilePath = Path::ChangeExtension(project->FilePath()".json");
2841     std::ofstream projectInfoFile(projectInfoFilePath);
2842     CodeFormatter formatter(projectInfoFile);
2843     std::unique_ptr<JsonValue> jsonValue =  projectInfo.ToJson();
2844     jsonValue->Write(formatter);
2845     if (GetGlobalFlag(GlobalFlags::verbose))
2846     {
2847         LogMessage(project->LogStreamId()"==> " + projectInfoFilePath);
2848     }
2849 }
2850 
2851 bool IsProjectInfoUpToDate(Project* projectconst std::string& projectInfoFilePath)
2852 {
2853     if (!boost::filesystem::exists(projectInfoFilePath))
2854     {
2855         return false;
2856     }
2857     time_t projectInfoFileWriteTime = boost::filesystem::last_write_time(projectInfoFilePath);
2858     time_t projectFileWriteTime = boost::filesystem::last_write_time(project->FilePath());
2859     if (projectFileWriteTime > projectInfoFileWriteTime)
2860     {
2861         return false;
2862     }
2863     for (const std::string& sourceFilePath : project->SourceFilePaths())
2864     {
2865         time_t sourceFileWriteTime = boost::filesystem::last_write_time(sourceFilePath);
2866         if (sourceFileWriteTime > projectInfoFileWriteTime)
2867         {
2868             return false;
2869         }
2870     }
2871     return true;
2872 }
2873 
2874 void GenerateProjectInfoFile(Project* project)
2875 {
2876     std::unique_ptr<Module> module(new Module());
2877     bool stop = false;
2878     for (const std::string& referencedProjectFilePath : project->ReferencedProjectFilePaths())
2879     {
2880         std::unique_ptr<Project> referencedProject = ReadProject(referencedProjectFilePath);
2881         project->AddDependsOnId(referencedProject->Id());
2882     }
2883     std::vector<std::std::unique_ptr<CompileUnitNode>>compileUnits=ParseSources(module.get()project->SourceFilePaths()stop);
2884     WriteProjectInfo(projectcompileUnits);
2885 }
2886 
2887 ProjectInfo ReadPojectInfo(Project* projectconst std::string& projectInfoFilePath)
2888 {
2889     if (project != nullptr)
2890     {
2891         bool projectInfoUpToDate = IsProjectInfoUpToDate(projectprojectInfoFilePath);
2892         if (!projectInfoUpToDate)
2893         {
2894             GenerateProjectInfoFile(project);
2895         }
2896     }
2897     ProjectInfo projectInfo;
2898     std::string projectInfoFile = ReadFile(projectInfoFilePath);
2899     std::u32string projectInfoFileContent = ToUtf32(projectInfoFile);
2900     JsonLexer lexer(projectInfoFileContentprojectInfoFilePath0);
2901     std::unique_ptr<JsonValue> projectInfoJsonValue = JsonParser::Parse(lexer);
2902     if (projectInfoJsonValue->Type() == JsonValueType::object)
2903     {
2904         JsonObject* projectFileInfo = static_cast<JsonObject*>(projectInfoJsonValue.get());
2905         projectInfo = ProjectInfo(projectFileInfo);
2906     }
2907     else
2908     {
2909         throw std::runtime_error("buildclient: JSON object expected");
2910     }
2911     return projectInfo;
2912 }
2913 
2914 void BuildProject(Project* projectstd::std::unique_ptr<Module>&rootModulebool&stopboolresetRootModulestd::std::set<std::string>&builtProjects)
2915 {
2916     try
2917     {
2918         if (!GetGlobalFlag(GlobalFlags::msbuild))
2919         {
2920             if (builtProjects.find(project->FilePath()) != builtProjects.cend()) return;
2921             builtProjects.insert(project->FilePath());
2922             for (const std::string& referencedProjectFilePath : project->ReferencedProjectFilePaths())
2923             {
2924                 SystemDirKind systemDirKind = SystemDirKind::regular;
2925                 if (GetGlobalFlag(GlobalFlags::repository))
2926                 {
2927                     systemDirKind = SystemDirKind::repository;
2928                 }
2929                 std::unique_ptr<Project> referencedProject = ReadProject(referencedProjectFilePath);
2930                 project->AddDependsOnId(referencedProject->Id());
2931                 if (GetGlobalFlag(GlobalFlags::buildAll))
2932                 {
2933                     if (builtProjects.find(referencedProjectFilePath) == builtProjects.cend())
2934                     {
2935                         std::unique_ptr<Module> module;
2936                         try
2937                         {
2938                             BuildProject(referencedProject.get()modulestopresetRootModulebuiltProjects);
2939                         }
2940                         catch (...)
2941                         {
2942                             rootModule.reset(module.release());
2943                             throw ;
2944                         }
2945                     }
2946                 }
2947             }
2948         }
2949         std::string config = GetConfig();
2950         bool isSystemModule = IsSystemModule(project->Name());
2951         if (isSystemModule)
2952         {
2953             project->SetSystemProject();
2954         }
2955         bool upToDate = false;
2956         sngcm::ast::BackEnd astBackEnd = sngcm::ast::BackEnd::llvm;
2957         if (GetBackEnd() == cmajor::symbols::BackEnd::cmsx)
2958         {
2959             astBackEnd = sngcm::ast::BackEnd::cmsx;
2960         }
2961         else if (GetBackEnd() == cmajor::symbols::BackEnd::cmcpp)
2962         {
2963             astBackEnd = sngcm::ast::BackEnd::cppcm;
2964         }
2965         if (!GetGlobalFlag(GlobalFlags::rebuild))
2966         {
2967             SystemDirKind systemDirKind = SystemDirKind::regular;
2968             if (GetGlobalFlag(GlobalFlags::repository))
2969             {
2970                 systemDirKind = SystemDirKind::repository;
2971             }
2972             upToDate = project->IsUpToDate(CmajorSystemModuleFilePath(configastBackEndGetToolChain()systemDirKind));
2973         }
2974         if (upToDate)
2975         {
2976             if (GetGlobalFlag(GlobalFlags::verbose))
2977             {
2978                 LogMessage(project->LogStreamId()"===== Project '" + ToUtf8(project->Name()) + "' (" + project->FilePath() + ") is up-to-date.");
2979             }
2980             return;
2981         }
2982         bool systemLibraryInstalled = false;
2983         if (project->GetTarget() == Target::unitTest)
2984         {
2985             throw std::runtime_error("cannot build unit test project '" + ToUtf8(project->Name()) + "' using cmc, use cmunit.");
2986         }
2987         if (GetGlobalFlag(GlobalFlags::verbose))
2988         {
2989             LogMessage(project->LogStreamId()"===== Building project '" + ToUtf8(project->Name()) + "' (" + project->FilePath() + ") using " + config + " configuration.");
2990         }
2991         if (GetGlobalFlag(GlobalFlags::cmdoc))
2992         {
2993             cmdoclib::SetEmptyLibraryPrefix(project->Name());
2994             if (GetGlobalFlag(GlobalFlags::optimizeCmDoc))
2995             {
2996                 if (cmdoclib::HtmlSourceFilePathsUpToDate(project) && cmdoclib::SymbolTableXmlFilesUpToDate(project))
2997                 {
2998                     if (GetGlobalFlag(GlobalFlags::verbose))
2999                     {
3000                         LogMessage(project->LogStreamId()"Project '" + ToUtf8(project->Name()) + " xml is up-to-date.");
3001                     }
3002                     return;
3003                 }
3004             }
3005         }
3006         rootModule.reset(new Module(project->Name()project->ModuleFilePath()project->GetTarget()));
3007         rootModule->SetRootModule();
3008         SetRootModuleForCurrentThread(rootModule.get());
3009         {
3010             rootModule->SetLogStreamId(project->LogStreamId());
3011             rootModule->SetCurrentProjectName(project->Name());
3012             rootModule->SetCurrentToolName(U"cmc");
3013             boost::filesystem::path libraryFilePath = project->LibraryFilePath();
3014             boost::filesystem::path libDir = libraryFilePath.remove_filename();
3015             std::string definesFilePath = GetFullPath((libDir / boost::filesystem::path("defines.txt")).generic_string());
3016             SetDefines(rootModule.get()definesFilePath);
3017             rootModule->SetFlag(cmajor::symbols::ModuleFlags::compiling);
3018             std::vector<std::std::unique_ptr<CompileUnitNode>>compileUnits=ParseSources(rootModule.get()project->SourceFilePaths()stop);
3019             AttributeBinder attributeBinder(rootModule.get());
3020             std::vector<ClassTypeSymbol*> classTypes;
3021             std::vector<ClassTemplateSpecializationSymbol*> classTemplateSpecializations;
3022             bool prevPreparing = rootModule->Preparing();
3023             rootModule->SetPreparing(true);
3024             PrepareModuleForCompilation(rootModule.get()project->References()project->GetTarget());
3025             Preprocess(projectcompileUnits);
3026             CreateSymbols(rootModule->GetSymbolTable()compileUnitsstop);
3027             if (GetGlobalFlag(GlobalFlags::sym2xml))
3028             {
3029                 std::unique_ptr<sngxml::dom::Document> symbolTableDoc = rootModule->GetSymbolTable().ToDomDocument();
3030                 std::string symbolTableXmlFilePath = Path::ChangeExtension(project->FilePath()".sym0.xml");
3031                 std::ofstream symbolTableXmlFile(symbolTableXmlFilePath);
3032                 CodeFormatter formatter(symbolTableXmlFile);
3033                 formatter.SetIndentSize(1);
3034                 symbolTableDoc->Write(formatter);
3035             }
3036             CompileUnitNode* compileUnit0 = nullptr;
3037             if (!compileUnits.empty())
3038             {
3039                 compileUnit0 = compileUnits[0].get();
3040             }
3041             if (GetGlobalFlag(GlobalFlags::verbose))
3042             {
3043                 LogMessage(project->LogStreamId()"Binding types...");
3044             }
3045             std::vector<std::std::unique_ptr<BoundCompileUnit>>boundCompileUnits=BindTypes(*rootModulecompileUnits&attributeBinderstop);
3046             if (stop)
3047             {
3048                 return;
3049             }
3050             rootModule->SetPreparing(prevPreparing);
3051             if (GetGlobalFlag(GlobalFlags::sym2xml))
3052             {
3053                 std::unique_ptr<sngxml::dom::Document> symbolTableDoc = rootModule->GetSymbolTable().ToDomDocument();
3054                 std::string symbolTableXmlFilePath = Path::ChangeExtension(project->FilePath()".sym1.xml");
3055                 std::ofstream symbolTableXmlFile(symbolTableXmlFilePath);
3056                 CodeFormatter formatter(symbolTableXmlFile);
3057                 formatter.SetIndentSize(1);
3058                 symbolTableDoc->Write(formatter);
3059             }
3060             std::unordered_map<intcmdoclib::File> docFileMap;
3061             cmajor::codegen::EmittingContext emittingContext(GetOptimizationLevel());
3062             std::vector<std::string> objectFilePaths;
3063             if (GetGlobalFlag(GlobalFlags::singleThreadedCompile))
3064             {
3065                 CompileSingleThreaded(projectrootModule.get()boundCompileUnitsemittingContextobjectFilePathsdocFileMapstop);
3066             }
3067             else
3068             {
3069                 CompileMultiThreaded(projectrootModule.get()boundCompileUnitsobjectFilePathsstop);
3070             }
3071             if (GetGlobalFlag(GlobalFlags::cmdoc))
3072             {
3073                 cmdoclib::GenerateSymbolTableXml(rootModule.get()docFileMap);
3074             }
3075             else
3076             {
3077                 if (GetGlobalFlag(GlobalFlags::sym2xml))
3078                 {
3079                     std::unique_ptr<sngxml::dom::Document> symbolTableDoc = rootModule->GetSymbolTable().ToDomDocument();
3080                     std::string symbolTableXmlFilePath = Path::ChangeExtension(project->FilePath()".sym2.xml");
3081                     std::ofstream symbolTableXmlFile(symbolTableXmlFilePath);
3082                     CodeFormatter formatter(symbolTableXmlFile);
3083                     formatter.SetIndentSize(1);
3084                     symbolTableDoc->Write(formatter);
3085                 }
3086                 std::string mainObjectFilePath;
3087                 std::string mainSourceFilePath;
3088                 if (project->GetTarget() == Target::program || project->GetTarget() == Target::winguiapp || project->GetTarget() == Target::winapp)
3089                 {
3090                     CheckMainFunctionSymbol(*rootModule);
3091                     rootModule->SetFlag(ModuleFlags::programModule);
3092                     if (!rootModule->GetSymbolTable().JsonClasses().empty())
3093                     {
3094                         CreateJsonRegistrationUnit(objectFilePaths*rootModuleemittingContext&attributeBinder);
3095                     }
3096                     if (GetBackEnd() == cmajor::symbols::BackEnd::llvm)
3097                     {
3098                         if (project->GetTarget() == Target::winguiapp)
3099                         {
3100                             CreateMainUnitLlvmWindowsGUI(objectFilePaths*rootModuleemittingContext&attributeBindermainObjectFilePath);
3101                         }
3102                         else
3103                         {
3104                             CreateMainUnitLlvm(objectFilePaths*rootModuleemittingContext&attributeBindermainObjectFilePath);
3105                         }
3106                     }
3107                     else if (GetBackEnd() == cmajor::symbols::BackEnd::cmcpp)
3108                     {
3109                         if (project->GetTarget() == Target::winguiapp)
3110                         {
3111                             CreateMainUnitCppWindowsGUI(objectFilePaths*rootModuleemittingContext&attributeBindermainObjectFilePathmainSourceFilePath);
3112                         }
3113                         else
3114                         {
3115                             CreateMainUnitCpp(objectFilePaths*rootModuleemittingContext&attributeBindermainObjectFilePathmainSourceFilePath);
3116                         }
3117                     }
3118                     else if (GetBackEnd() == cmajor::symbols::BackEnd::cmsx)
3119                     {
3120                         CreateMainUnitSystemX(objectFilePaths*rootModuleemittingContext&attributeBindermainObjectFilePath);
3121                     }
3122                 }
3123                 if (!objectFilePaths.empty())
3124                 {
3125                     GenerateLibrary(rootModule.get()objectFilePathsproject->LibraryFilePath());
3126                 }
3127 #ifdef _WIN32
3128 
3129 #endif
3130                 if (GetBackEnd() == BackEnd::cmcpp)
3131                 {
3132                     CreateCppProjectFile(project*rootModulemainSourceFilePathproject->LibraryFilePath()rootModule->LibraryFilePaths());
3133                 }
3134                 if (project->GetTarget() == Target::program || project->GetTarget() == Target::winguiapp || project->GetTarget() == Target::winapp)
3135                 {
3136                     Link(project->GetTarget()project->ExecutableFilePath()project->LibraryFilePath()rootModule->LibraryFilePaths()
3137                         mainObjectFilePath*rootModule);
3138                 }
3139                 if (GetGlobalFlag(GlobalFlags::verbose))
3140                 {
3141                     LogMessage(project->LogStreamId()"Writing module file...");
3142                 }
3143                 SymbolWriter writer(project->ModuleFilePath());
3144                 writer.SetLexers(rootModule->GetLexers());
3145                 writer.SetSpanConversionModuleId(rootModule->Id());
3146                 rootModule->Write(writer);
3147                 rootModule->ResetFlag(cmajor::symbols::ModuleFlags::compiling);
3148                 if (cmajor::symbols::GetGlobalFlag(cmajor::symbols::GlobalFlags::updateSourceFileModuleMap))
3149                 {
3150                     rootModule->UpdateSourceFileModuleMap();
3151                 }
3152                 if (GetGlobalFlag(GlobalFlags::verbose))
3153                 {
3154                     LogMessage(project->LogStreamId()"==> " + project->ModuleFilePath());
3155                 }
3156                 if (GetBackEnd() == BackEnd::cmcpp)
3157                 {
3158                     if (GetGlobalFlag(GlobalFlags::verbose))
3159                     {
3160                         LogMessage(project->LogStreamId()"Writing project debug info file...");
3161                     }
3162                     std::string pdiFilePath = Path::ChangeExtension(project->ModuleFilePath()".pdi");
3163                     rootModule->WriteProjectDebugInfoFile(pdiFilePath);
3164                     if (GetGlobalFlag(GlobalFlags::verbose))
3165                     {
3166                         LogMessage(project->LogStreamId()"==> " + pdiFilePath);
3167                     }
3168                 }
3169                 if (!GetGlobalFlag(GlobalFlags::msbuild))
3170                 {
3171                     WriteProjectInfo(projectcompileUnits);
3172                 }
3173                 if (GetBackEnd() == BackEnd::cmcpp)
3174                 {
3175                     if (project->GetTarget() == Target::program || project->GetTarget() == Target::winguiapp || project->GetTarget() == Target::winapp)
3176                     {
3177                         if (GetGlobalFlag(GlobalFlags::verbose))
3178                         {
3179                             LogMessage(project->LogStreamId()"Writing debug information file...");
3180                         }
3181 #ifdef _WIN32
3182 
3183 #else
3184                         std::string cmdbFilePath = project->ExecutableFilePath() + ".cmdb";
3185 #endif
3186                         rootModule->WriteCmdbFile(cmdbFilePath);
3187                         if (GetGlobalFlag(GlobalFlags::verbose))
3188                         {
3189                             LogMessage(project->LogStreamId()"==> " + cmdbFilePath);
3190                         }
3191                     }
3192                 }
3193                 if (GetGlobalFlag(GlobalFlags::verbose))
3194                 {
3195                     LogMessage(project->LogStreamId()std::to_string(rootModule->GetSymbolTable().NumSpecializations()) + " class template specializations, " + 
3196                         std::to_string(rootModule->GetSymbolTable().NumSpecializationsNew()) + " new, " + 
3197                         std::to_string(rootModule->GetSymbolTable().NumSpecializationsCopied()) + " copied.");
3198                     LogMessage(project->LogStreamId()"Project '" + ToUtf8(project->Name()) + "' built successfully.");
3199                 }
3200                 project->SetModuleFilePath(rootModule->OriginalFilePath());
3201                 project->SetLibraryFilePath(rootModule->LibraryFilePath());
3202                 if (rootModule->IsSystemModule())
3203                 {
3204                     project->SetSystemProject();
3205                 }
3206                 if (rootModule->Name() == U"System.Install")
3207                 {
3208                     InstallSystemLibraries(rootModule.get());
3209                     systemLibraryInstalled = true;
3210                 }
3211                 else if (rootModule->Name() == U"System.Windows.Install")
3212                 {
3213                     InstallSystemWindowsLibraries(rootModule.get());
3214                     systemLibraryInstalled = true;
3215                 }
3216             }
3217         }
3218         if (resetRootModule)
3219         {
3220             PutModuleToModuleCache(std::move(rootModule));
3221             rootModule.reset();
3222         }
3223         if (systemLibraryInstalled)
3224         {
3225             ResetModuleCache();
3226         }
3227     }
3228     catch (const std::exception& ex;)
3229     {
3230         LogMessage(-1"project: " + ToUtf8(project->Name()) + ": " + PlatformStringToUtf8(ex.what()));
3231         throw ;
3232     }
3233 }
3234 
3235 void BuildProject(const std::string& projectFilePathstd::std::unique_ptr<Module>&rootModulestd::std::set<std::string>&builtProjects)
3236 {
3237     std::unique_ptr<Project> project = ReadProject(projectFilePath);
3238     if (GetGlobalFlag(GlobalFlags::clean))
3239     {
3240         if (!GetGlobalFlag(GlobalFlags::msbuild))
3241         {
3242             for (const std::string& referencedProjectFilePath : project->ReferencedProjectFilePaths())
3243             {
3244                 SystemDirKind systemDirKind = SystemDirKind::regular;
3245                 if (GetGlobalFlag(GlobalFlags::repository))
3246                 {
3247                     systemDirKind = SystemDirKind::repository;
3248                 }
3249                 std::unique_ptr<Project> referencedProject = ReadProject(referencedProjectFilePath);
3250                 project->AddDependsOnId(referencedProject->Id());
3251                 if (currentSolution == nullptr && GetGlobalFlag(GlobalFlags::buildAll))
3252                 {
3253                     BuildProject(referencedProjectFilePathrootModulebuiltProjects);
3254                 }
3255             }
3256         }
3257         CleanProject(project.get());
3258     }
3259     else
3260     {
3261         stopBuild = false;
3262         BuildProject(project.get()rootModulestopBuildtruebuiltProjects);
3263     }
3264 }
3265 
3266 bool buildDebug = false;
3267 const int buildGetTimeoutSecs = 3;
3268 int64_t buildDebugStart = 0;
3269 
3270 std::string CurrentProjectDebugMsStr()
3271 {
3272     return FormatTimeMs(static_cast<int32_t>(CurrentMs() - buildDebugStart));
3273 }
3274 
3275 class ProjectQueue 
3276 {
3277 public:
3278     ProjectQueue(bool& stop_const std::string& name_std::mutex* mtx_);
3279     void Put(Project* project);
3280     Project* Get();
3281     void Stop();
3282 private:
3283     std::string name;
3284     std::list<Project*> queue;
3285     std::mutex* mtx;
3286     std::condition_variable cond;
3287     bool& stop;
3288 };
3289 
3290 
3291 ProjectQueue::ProjectQueue(bool& stop_const std::string& name_std::mutex* mtx_) : stop(stop_)name(name_)mtx(mtx_)
3292 {
3293 }
3294 
3295 void ProjectQueue::Put(Project* project)
3296 {
3297     if (buildDebug)
3298     {
3299         std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
3300         LogMessage(-1CurrentProjectDebugMsStr() + ">ProjectQueue(" + name + ")::Put: " + CurrentThreadIdStr() + " " + ToUtf8(project->Name()));
3301     }
3302     std::lock_guard<std::mutex> lock(*mtx);
3303     queue.push_back(project);
3304     cond.notify_one();
3305     if (buildDebug)
3306     {
3307         LogMessage(-1CurrentProjectDebugMsStr() + "<ProjectQueue(" + name + ")::Put: " + CurrentThreadIdStr() + " " + ToUtf8(project->Name()));
3308     }
3309 }
3310 
3311 Project* ProjectQueue::Get()
3312 {
3313     while (!stop)
3314     {
3315         if (buildDebug)
3316         {
3317             LogMessage(-1CurrentProjectDebugMsStr() + ">ProjectQueue(" + name + ")::Get: " + CurrentThreadIdStr());
3318         }
3319         std::unique_lock<std::mutex> lock(*mtx);
3320         cond.wait(lock[this] { return stop || !queue.empty(); });
3321         if (stop) return nullptr;
3322         Project* project = queue.front();
3323         queue.pop_front();
3324         if (buildDebug)
3325         {
3326             LogMessage(-1CurrentProjectDebugMsStr() + "<ProjectQueue(" + name + ")::Get: " + CurrentThreadIdStr() + " got project " + ToUtf8(project->Name()));
3327         }
3328         return project;
3329     }
3330     if (buildDebug)
3331     {
3332         LogMessage(-1CurrentProjectDebugMsStr() + "<ProjectQueue(" + name + ")::Get: " + CurrentThreadIdStr() + " stop");
3333     }
3334     return nullptr;
3335 }
3336 
3337 void ProjectQueue::Stop()
3338 {
3339     stop = true;
3340     cond.notify_all();
3341 }
3342 
3343 struct BuildData 
3344 {
3345     BuildData(std::mutex* mtx_bool& stop_
3346         ProjectQueue& buildQueue_ProjectQueue& readyQueue_std::std::vector<std::std::unique_ptr<Module>>&rootModules_bool&isSystemSolution_
3347         std::std::set<std::string>&builtProjects_):
3348         mtx(mtx_)stop(stop_)buildQueue(buildQueue_)readyQueue(readyQueue_)rootModules(rootModules_)isSystemSolution(isSystemSolution_)builtProjects(builtProjects_)
3349     {
3350     }
3351     std::mutex* mtx;
3352     bool& stop;
3353     ProjectQueue& buildQueue;
3354     ProjectQueue& readyQueue;
3355     std::std::vector<std::std::unique_ptr<Module>>&rootModules;
3356     std::vector<std::exception_ptr> exceptions;
3357     bool& isSystemSolution;
3358     std::std::set<std::string>&builtProjects;
3359 };
3360 
3361 void ProjectBuilder(BuildData* buildData)
3362 {
3363     try
3364     {
3365         Project* toBuild = buildData->buildQueue.Get();
3366         while (!buildData->stop)
3367         {
3368             if (toBuild)
3369             {
3370                 BuildProject(toBuildbuildData->rootModules[toBuild->Index()]buildData->stoptruebuildData->builtProjects);
3371                 if (toBuild->IsSystemProject())
3372                 {
3373                     buildData->isSystemSolution = true;
3374                 }
3375                 buildData->readyQueue.Put(toBuild);
3376             }
3377             toBuild = buildData->buildQueue.Get();
3378         }
3379     }
3380     catch (...)
3381     {
3382         if (buildDebug)
3383         {
3384             LogMessage(-1CurrentProjectDebugMsStr() + ">ProjectBuilder()::catch " + CurrentThreadIdStr());
3385         }
3386         std::lock_guard<std::mutex> lock(*buildData->mtx);
3387         buildData->exceptions.push_back(std::current_exception());
3388         buildData->buildQueue.Stop();
3389         buildData->readyQueue.Stop();
3390         if (buildDebug)
3391         {
3392             LogMessage(-1CurrentProjectDebugMsStr() + "<ProjectBuilder()::catch " + CurrentThreadIdStr());
3393         }
3394     }
3395 }
3396 
3397 struct CurrentSolutionGuard 
3398 {
3399     CurrentSolutionGuard(Solution* solution) { currentSolution = solution; }
3400     ~CurrentSolutionGuard() { currentSolution = nullptr; }
3401 };
3402 
3403 bool SolutionContainsSystemModule(const std::string& solutionFilePath)
3404 {
3405     MappedInputFile solutionFile(solutionFilePath);
3406     std::u32string s(ToUtf32(std::string(solutionFile.Begin()solutionFile.End())));
3407     ContainerFileLexer containerFileLexer(ssolutionFilePath0);
3408     std::unique_ptr<Solution> solution = SolutionFileParser::Parse(containerFileLexer);
3409     solution->ResolveDeclarations();
3410     int np = solution->ProjectFilePaths().size();
3411     for (int i = 0; i < np; ++i)
3412     {
3413         const std::string& projectFilePath = solution->ProjectFilePaths()[i];
3414         std::unique_ptr<Project> project = ReadProject(projectFilePath);
3415         if (cmajor::symbols::IsSystemModule(project->Name())) return true;
3416     }
3417     return false;
3418 }
3419 
3420 void BuildSolution(const std::string& solutionFilePathstd::std::vector<std::std::unique_ptr<Module>>&rootModules)
3421 {
3422     std::u32string solutionName;
3423     std::vector<std::u32string> moduleNames;
3424     BuildSolution(solutionFilePathrootModulessolutionNamemoduleNames);
3425 }
3426 
3427 void BuildSolution(const std::string& solutionFilePathstd::std::vector<std::std::unique_ptr<Module>>&rootModulesstd::u32string&solutionNamestd::std::vector<std::u32string>&moduleNames)
3428 {
3429     if (buildLogWriter)
3430     {
3431         buildLogWriter->WriteCurrentDateTime();
3432         buildLogWriter->WriteLine("Building solution '" + solutionFilePath + "'");
3433     }
3434     std::set<std::string> builtProjects;
3435     MappedInputFile solutionFile(solutionFilePath);
3436     std::u32string s(ToUtf32(std::string(solutionFile.Begin()solutionFile.End())));
3437     ContainerFileLexer containerFileLexer(ssolutionFilePath0);
3438     std::unique_ptr<Solution> solution = SolutionFileParser::Parse(containerFileLexer);
3439     solution->ResolveDeclarations();
3440     CurrentSolutionGuard currentSolutionGuard(solution.get());
3441     solutionName = solution->Name();
3442     std::string config = GetConfig();
3443     if (GetGlobalFlag(GlobalFlags::verbose))
3444     {
3445         if (GetGlobalFlag(GlobalFlags::clean))
3446         {
3447             LogMessage(-1"Cleaning solution '" + ToUtf8(solution->Name()) + "' (" + solution->FilePath() + ") using " + config + " configuration.");
3448         }
3449         else
3450         {
3451             LogMessage(-1"Building solution '" + ToUtf8(solution->Name()) + "' (" + solution->FilePath() + ") using " + config + " configuration.");
3452         }
3453     }
3454     int np = solution->ProjectFilePaths().size();
3455     for (int i = 0; i < np; ++i)
3456     {
3457         const std::string& projectFilePath = solution->ProjectFilePaths()[i];
3458         const std::string& relativeProjectFilePath = solution->RelativeProjectFilePaths()[i];
3459         std::unique_ptr<Project> project = ReadProject(projectFilePath);
3460         project->SetRelativeFilePath(relativeProjectFilePath);
3461         solution->AddProject(std::move(project));
3462     }
3463     std::vector<Project*> buildOrder = solution->CreateBuildOrder();
3464     std::vector<Project*> projectsToBuild;
3465     bool isSystemSolution = false;
3466     int n = buildOrder.size();
3467     for (int i = 0; i < n; ++i)
3468     {
3469         Project* project = buildOrder[i];
3470         project->SetLogStreamId(i);
3471         project->SetIndex(i);
3472         if (project->GetTarget() == Target::unitTest)
3473         {
3474             if (GetGlobalFlag(GlobalFlags::verbose))
3475             {
3476                 LogMessage(-1"skipping unit test project '" + ToUtf8(project->Name()) + "'");
3477             }
3478             continue;
3479         }
3480         if (GetGlobalFlag(GlobalFlags::clean))
3481         {
3482             CleanProject(project);
3483         }
3484         else
3485         {
3486             projectsToBuild.push_back(project);
3487         }
3488     }
3489     if (!projectsToBuild.empty())
3490     {
3491         for (Project* project : projectsToBuild)
3492         {
3493             moduleNames.push_back(project->Name());
3494         }
3495         if (GetGlobalFlag(GlobalFlags::cmdoc) && GetGlobalFlag(GlobalFlags::optimizeCmDoc))
3496         {
3497             cmdoclib::ReadGlobals(moduleNames);
3498         }
3499         int numProjectsToBuild = projectsToBuild.size();
3500         int numThreads = std::min(numProjectsToBuildint(std::thread::hardware_concurrency() * 2));
3501         int n = GetNumBuildThreads();
3502         if (n != -1)
3503         {
3504             numThreads = std::max(1n);
3505         }
3506         if (buildLogWriter)
3507         {
3508             buildLogWriter->WriteLine("building " + std::to_string(numProjectsToBuild) + " projects using " + std::to_string(numThreads) + " threads...");
3509         }
3510         rootModules.resize(numProjectsToBuild);
3511         if (numThreads <= 1)
3512         {
3513             if (GetGlobalFlag(GlobalFlags::verbose))
3514             {
3515                 LogMessage(-1"Building " + std::to_string(numProjectsToBuild) + " projects in main thread...");
3516             }
3517             for (int i = 0; i < numProjectsToBuild; ++i)
3518             {
3519                 Project* project = projectsToBuild[i];
3520                 stopBuild = false;
3521                 BuildProject(projectrootModules[i]stopBuildtruebuiltProjects);
3522             }
3523         }
3524         else
3525         {
3526             if (GetGlobalFlag(GlobalFlags::verbose))
3527             {
3528                 LogMessage(-1"Building " + std::to_string(numProjectsToBuild) + " projects using " + std::to_string(numThreads) + " threads...");
3529             }
3530             stopBuild = false;
3531             const char* buildDebugEnvVarDefined = std::getenv("CMAJOR_BUILD_DEBUG");
3532             if (buildDebugEnvVarDefined != nullptr && std::string(buildDebugEnvVarDefined) != "")
3533             {
3534                 buildDebugStart = CurrentMs();
3535                 buildDebug = true;
3536             }
3537             else
3538             {
3539                 buildDebug = false;
3540             }
3541             std::mutex mtx;
3542             ProjectQueue buildQueue(stopBuild"build"&mtx);
3543             ProjectQueue readyQueue(stopBuild"ready"&mtx);
3544             BuildData buildData(&mtxstopBuildbuildQueuereadyQueuerootModulesisSystemSolutionbuiltProjects);
3545             std::vector<std::thread> threads;
3546             for (int i = 0; i < numThreads; ++i)
3547             {
3548                 threads.push_back(std::thread(ProjectBuilder&buildData));
3549                 if (buildData.stop) break;
3550             }
3551             while (numProjectsToBuild > 0 && !stopBuild)
3552             {
3553                 std::vector<Project*> building;
3554                 for (Project* project : projectsToBuild)
3555                 {
3556                     if (project->Ready())
3557                     {
3558                         if (buildLogWriter)
3559                         {
3560                             buildLogWriter->WriteCurrentDateTime();
3561                             buildLogWriter->WriteLine("project '" + ToUtf8(project->Name()) + "' is ready to build");
3562                         }
3563                         building.push_back(project);
3564                         buildQueue.Put(project);
3565                     }
3566                 }
3567                 for (Project* project : building)
3568                 {
3569                     projectsToBuild.erase(std::remove(projectsToBuild.begin()projectsToBuild.end()project)projectsToBuild.end());
3570                 }
3571                 Project* ready = readyQueue.Get();
3572                 if (ready)
3573                 {
3574                     ready->SetBuilt();
3575                     --numProjectsToBuild;
3576                     if (buildLogWriter)
3577                     {
3578                         buildLogWriter->WriteCurrentDateTime();
3579                         buildLogWriter->WriteLine("project '" + ToUtf8(ready->Name()) + "' built");
3580                     }
3581                 }
3582             }
3583             if (stopBuild)
3584             {
3585                 LogMessage(-1"Build stopped.");
3586             }
3587             stopBuild = true;
3588             int numStartedThreads = threads.size();
3589             for (int i = 0; i < numStartedThreads; ++i)
3590             {
3591                 buildQueue.Put(nullptr);
3592             }
3593             for (int i = 0; i < numStartedThreads; ++i)
3594             {
3595                 if (threads[i].joinable())
3596                 {
3597                     threads[i].join();
3598                 }
3599             }
3600             if (!buildData.exceptions.empty())
3601             {
3602                 std::rethrow_exception(buildData.exceptions.front());
3603             }
3604         }
3605     }
3606     if (!GetGlobalFlag(GlobalFlags::clean))
3607     {
3608         if (GetBackEnd() == BackEnd::cmcpp)
3609         {
3610             CreateCppSolutionFile(solution.get()projectsToBuild);
3611         }
3612     }
3613     if (GetGlobalFlag(GlobalFlags::verbose))
3614     {
3615         if (GetGlobalFlag(GlobalFlags::clean))
3616         {
3617             LogMessage(-1"Solution '" + ToUtf8(solution->Name()) + "' cleaned successfully.");
3618         }
3619         else
3620         {
3621             LogMessage(-1"Solution '" + ToUtf8(solution->Name()) + "' built successfully.");
3622         }
3623     }
3624 }
3625 
3626 void BuildMsBuildProject(const std::string& projectNameconst std::string& projectDirectoryconst std::string& target
3627     const std::std::vector<std::string>&sourceFilesconststd::std::vector<std::string>&resourceFilesconststd::std::vector<std::string>&referenceFiles
3628     std::std::unique_ptr<Module>&rootModule)
3629 {
3630     std::set<std::string> builtProjects;
3631     std::string projectFilePath = GetFullPath(Path::Combine(projectDirectoryprojectName + ".cmproj"));
3632     std::unique_ptr<Project> project(new Project(ToUtf32(projectName)projectFilePathGetConfig()sngcm::ast::BackEnd::llvm""SystemDirKind::regular));
3633     if (target == "program")
3634     {
3635         project->AddDeclaration(new TargetDeclaration(Target::program));
3636     }
3637     else if (target == "winguiapp")
3638     {
3639         project->AddDeclaration(new TargetDeclaration(Target::winguiapp));
3640     }
3641     else if (target == "winapp")
3642     {
3643         project->AddDeclaration(new TargetDeclaration(Target::winapp));
3644     }
3645     else if (target == "library")
3646     {
3647         project->AddDeclaration(new TargetDeclaration(Target::library));
3648     }
3649     else if (target == "winlib")
3650     {
3651         project->AddDeclaration(new TargetDeclaration(Target::winlib));
3652     }
3653     else if (target == "unitTest")
3654     {
3655         project->AddDeclaration(new TargetDeclaration(Target::unitTest));
3656     }
3657     else
3658     {
3659         throw std::runtime_error("unsupported target '" + target + "'");
3660     }
3661     for (const std::string& sourceFile : sourceFiles)
3662     {
3663         project->AddDeclaration(new SourceFileDeclaration(sourceFile));
3664     }
3665     for (const std::string& resourceFile : resourceFiles)
3666     {
3667         project->AddDeclaration(new ResourceFileDeclaration(resourceFile));
3668     }
3669     for (const std::string& referenceFile : referenceFiles)
3670     {
3671         project->AddDeclaration(new ReferenceDeclaration(referenceFile));
3672     }
3673     project->ResolveDeclarations();
3674     project->SetLogStreamId(-1);
3675     stopBuild = false;
3676     BuildProject(project.get()rootModulestopBuildfalsebuiltProjects);
3677 }
3678 
3679 } } // namespace cmajor::build