1
2
3
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*module, conststd::std::vector<std::string>&sourceFilePaths, bool&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(s, sourceFilePath, fileIndex));
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(s, sourceFilePath, fileIndex));
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*module, conststd::std::vector<std::string>&sourceFilePaths, intnumThreads, bool&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(), sourceFilePaths, compileUnits, lexers, fileIndeces, exceptions, stop);
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*module, conststd::std::vector<std::string>&sourceFilePaths, bool&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(module, sourceFilePaths, stop);
366 }
367 else
368 {
369 return ParseSourcesConcurrently(module, sourceFilePaths, numThreads, stop);
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* project, std::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& symbolTable, const std::std::vector<std::std::unique_ptr<CompileUnitNode>>&compileUnits, bool&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&module, conststd::std::vector<std::std::unique_ptr<CompileUnitNode>>&compileUnits, AttributeBinder*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(module, compileUnit.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* module, const std::std::vector<std::string>&objectFilePaths, conststd::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(libraryManagerTool, GetConfig());
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(command, redirections);
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* module, const std::std::vector<std::string>&objectFilePaths, conststd::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(libCommandLine, redirections);
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* module, const std::std::vector<std::string>&objectFilePaths, conststd::string&libraryFilePath)
706 {
707 if (GetBackEnd() == cmajor::symbols::BackEnd::llvm)
708 {
709 GenerateLibraryLlvm(module, objectFilePaths, libraryFilePath);
710 }
711 else if (GetBackEnd() == cmajor::symbols::BackEnd::cmcpp)
712 {
713 GenerateLibraryCpp(module, objectFilePaths, libraryFilePath);
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(3, libraryFilePath.length() - (3 + 2)));
761 }
762 return libraryFilePath;
763 }
764
765 const char* dynamicRuntimeArg = "-lcmrt3100cpp";
766 const char* dynamicDebugRuntimeArg = "-lcmrt3100cppd";
767
768 void LinkCpp(Target target, const std::string& executableFilePath, const std::string& libraryFilePath, const std::std::vector<std::string>&libraryFilePaths, conststd::string&mainObjectFilePath, Module&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(platform, toolChain);
781 const Configuration& configuration = GetToolConfiguration(linkerTool, GetConfig());
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(executableFilePath, linkerTool.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(linkCommandLine, redirections);
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(libraryManagerTool, GetConfig());
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* project, Module& module, const std::string& mainSourceFilePath, const std::string& libraryFilePath, const 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(projectFileGeneratorTool, config);
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(commandLine, redirections);
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* solution, const 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(solutionFileGeneratorTool, config);
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(commandLine, redirections);
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(-1, PlatformStringToUtf8(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& dynamicListFilePath, Module& 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 target, const std::string& executableFilePath, const std::string& libraryFilePath, const std::std::vector<std::string>&libraryFilePaths, conststd::string&mainObjectFilePath, Module&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(linkCommandLine, redirections);
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(-1, PlatformStringToUtf8(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 target, const std::string& executableFilePath, const std::string& libraryFilePath, const std::std::vector<std::string>&libraryFilePaths, conststd::string&mainObjectFilePath, Module&module)
1544 {
1545 if (GetBackEnd() == cmajor::symbols::BackEnd::llvm)
1546 {
1547 LinkLlvm(target, executableFilePath, libraryFilePath, libraryFilePaths, mainObjectFilePath, module);
1548 }
1549 else if (GetBackEnd() == cmajor::symbols::BackEnd::cmcpp)
1550 {
1551 LinkCpp(target, executableFilePath, libraryFilePath, libraryFilePaths, mainObjectFilePath, module);
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>&objectFilePaths, Module&module, cmajor::codegen::EmittingContext&emittingContext, AttributeBinder*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, &jsonRegistrationCompileUnit, attributeBinder);
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(emittingContext, boundJsonCompileUnit);
1651 objectFilePaths.push_back(boundJsonCompileUnit.ObjectFilePath());
1652 }
1653
1654 void CreateMainUnitLlvm(std::std::vector<std::string>&objectFilePaths, Module&module, cmajor::codegen::EmittingContext&emittingContext, AttributeBinder*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(), consoleError, new 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, &mainCompileUnit, attributeBinder);
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(emittingContext, boundMainCompileUnit);
1801 mainObjectFilePath = boundMainCompileUnit.ObjectFilePath();
1802 }
1803
1804 void CreateMainUnitCpp(std::std::vector<std::string>&objectFilePaths, Module&module, cmajor::codegen::EmittingContext&emittingContext, AttributeBinder*attributeBinder,
1805 std::string& mainObjectFilePath, std::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
1833
1834
1835
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
1898
1899
1900
1901
1902
1903
1904
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(), consoleError, new 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, &mainCompileUnit, attributeBinder);
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(emittingContext, boundMainCompileUnit);
1986 mainObjectFilePath = boundMainCompileUnit.ObjectFilePath();
1987 mainSourceFilePath = Path::ChangeExtension(boundMainCompileUnit.LLFilePath(), ".cpp");
1988 }
1989
1990 void CreateMainUnitSystemX(std::std::vector<std::string>&objectFilePaths, Module&module, cmajor::codegen::EmittingContext&emittingContext, AttributeBinder*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(), consoleError, new 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, &mainCompileUnit, attributeBinder);
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(emittingContext, boundMainCompileUnit);
2066 mainObjectFilePath = boundMainCompileUnit.ObjectFilePath();
2067 }
2068
2069 void CreateMainUnitLlvmWindowsGUI(std::std::vector<std::string>&objectFilePaths, Module&module, cmajor::codegen::EmittingContext&emittingContext, AttributeBinder*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::winapi, new 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, &mainCompileUnit, attributeBinder);
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(emittingContext, boundMainCompileUnit);
2208 mainObjectFilePath = boundMainCompileUnit.ObjectFilePath();
2209 }
2210
2211 void CreateMainUnitCppWindowsGUI(std::std::vector<std::string>&objectFilePaths, Module&module, cmajor::codegen::EmittingContext&emittingContext, AttributeBinder*attributeBinder,
2212 std::string& mainObjectFilePath, std::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::winapi, new 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, &mainCompileUnit, attributeBinder);
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(emittingContext, boundMainCompileUnit);
2350 mainObjectFilePath = boundMainCompileUnit.ObjectFilePath();
2351 mainSourceFilePath = Path::ChangeExtension(boundMainCompileUnit.LLFilePath(), ".cpp");
2352 }
2353
2354 void SetDefines(Module* module, const 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(definesFile, line))
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(), backend, GetToolChain(), 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(from, to);
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(from, to);
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(), backend, GetToolChain(), 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(from, to);
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(from, to);
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* project, Module* rootModule, std::std::vector<std::std::unique_ptr<BoundCompileUnit>>&boundCompileUnits, cmajor::codegen::EmittingContext&emittingContext,
2499 std::std::vector<std::string>&objectFilePaths, std::std::unordered_map<int, cmdoclib::File>&docFileMap, bool&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(project, boundCompileUnit.get(), docFileMap);
2534 maxFileIndex = std::max(maxFileIndex, boundCompileUnit->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(project, maxFileIndex, docFileMap);
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* data, int 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(-1, data->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(-1, data->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* project, Module* rootModule, std::std::vector<std::std::unique_ptr<BoundCompileUnit>>&boundCompileUnits, std::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", stop, ready, rootModule->LogStreamId());
2697 CompileQueue output(&mtx, "output", stop, ready, rootModule->LogStreamId());
2698 CompileData compileData(&mtx, rootModule, boundCompileUnits, objectFilePaths, stop, ready, numThreads, input, output);
2699 std::vector<std::thread> threads;
2700 for (int i = 0; i < numThreads; ++i)
2701 {
2702 threads.push_back(std::thread({GenerateCode, &compileData, i }));
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(p, projectFilePath, 0);
2810 std::unique_ptr<Project> project = ProjectFileParser::Parse(containerFileLexer, config, backend, GetToolChain(), systemDirKind);
2811 project->ResolveDeclarations();
2812 return project;
2813 }
2814
2815 void WriteProjectInfo(Project* project, std::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(project, compileUnits);
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* project, const 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(project, compileUnits);
2885 }
2886
2887 ProjectInfo ReadPojectInfo(Project* project, const std::string& projectInfoFilePath)
2888 {
2889 if (project != nullptr)
2890 {
2891 bool projectInfoUpToDate = IsProjectInfoUpToDate(project, projectInfoFilePath);
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(projectInfoFileContent, projectInfoFilePath, 0);
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* project, std::std::unique_ptr<Module>&rootModule, bool&stop, boolresetRootModule, std::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(), module, stop, resetRootModule, builtProjects);
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(config, astBackEnd, GetToolChain(), 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(project, compileUnits);
3026 CreateSymbols(rootModule->GetSymbolTable(), compileUnits, stop);
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(*rootModule, compileUnits, &attributeBinder, stop);
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<int, cmdoclib::File> docFileMap;
3061 cmajor::codegen::EmittingContext emittingContext(GetOptimizationLevel());
3062 std::vector<std::string> objectFilePaths;
3063 if (GetGlobalFlag(GlobalFlags::singleThreadedCompile))
3064 {
3065 CompileSingleThreaded(project, rootModule.get(), boundCompileUnits, emittingContext, objectFilePaths, docFileMap, stop);
3066 }
3067 else
3068 {
3069 CompileMultiThreaded(project, rootModule.get(), boundCompileUnits, objectFilePaths, stop);
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, *rootModule, emittingContext, &attributeBinder);
3095 }
3096 if (GetBackEnd() == cmajor::symbols::BackEnd::llvm)
3097 {
3098 if (project->GetTarget() == Target::winguiapp)
3099 {
3100 CreateMainUnitLlvmWindowsGUI(objectFilePaths, *rootModule, emittingContext, &attributeBinder, mainObjectFilePath);
3101 }
3102 else
3103 {
3104 CreateMainUnitLlvm(objectFilePaths, *rootModule, emittingContext, &attributeBinder, mainObjectFilePath);
3105 }
3106 }
3107 else if (GetBackEnd() == cmajor::symbols::BackEnd::cmcpp)
3108 {
3109 if (project->GetTarget() == Target::winguiapp)
3110 {
3111 CreateMainUnitCppWindowsGUI(objectFilePaths, *rootModule, emittingContext, &attributeBinder, mainObjectFilePath, mainSourceFilePath);
3112 }
3113 else
3114 {
3115 CreateMainUnitCpp(objectFilePaths, *rootModule, emittingContext, &attributeBinder, mainObjectFilePath, mainSourceFilePath);
3116 }
3117 }
3118 else if (GetBackEnd() == cmajor::symbols::BackEnd::cmsx)
3119 {
3120 CreateMainUnitSystemX(objectFilePaths, *rootModule, emittingContext, &attributeBinder, mainObjectFilePath);
3121 }
3122 }
3123 if (!objectFilePaths.empty())
3124 {
3125 GenerateLibrary(rootModule.get(), objectFilePaths, project->LibraryFilePath());
3126 }
3127 #ifdef _WIN32
3128
3129 #endif
3130 if (GetBackEnd() == BackEnd::cmcpp)
3131 {
3132 CreateCppProjectFile(project, *rootModule, mainSourceFilePath, project->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(project, compileUnits);
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& projectFilePath, std::std::unique_ptr<Module>&rootModule, std::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(referencedProjectFilePath, rootModule, builtProjects);
3254 }
3255 }
3256 }
3257 CleanProject(project.get());
3258 }
3259 else
3260 {
3261 stopBuild = false;
3262 BuildProject(project.get(), rootModule, stopBuild, true, builtProjects);
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(-1, CurrentProjectDebugMsStr() + ">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(-1, CurrentProjectDebugMsStr() + "<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(-1, CurrentProjectDebugMsStr() + ">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(-1, CurrentProjectDebugMsStr() + "<ProjectQueue(" + name + ")::Get: " + CurrentThreadIdStr() + " got project " + ToUtf8(project->Name()));
3327 }
3328 return project;
3329 }
3330 if (buildDebug)
3331 {
3332 LogMessage(-1, CurrentProjectDebugMsStr() + "<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(toBuild, buildData->rootModules[toBuild->Index()], buildData->stop, true, buildData->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(-1, CurrentProjectDebugMsStr() + ">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(-1, CurrentProjectDebugMsStr() + "<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(s, solutionFilePath, 0);
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& solutionFilePath, std::std::vector<std::std::unique_ptr<Module>>&rootModules)
3421 {
3422 std::u32string solutionName;
3423 std::vector<std::u32string> moduleNames;
3424 BuildSolution(solutionFilePath, rootModules, solutionName, moduleNames);
3425 }
3426
3427 void BuildSolution(const std::string& solutionFilePath, std::std::vector<std::std::unique_ptr<Module>>&rootModules, std::u32string&solutionName, std::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(s, solutionFilePath, 0);
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(numProjectsToBuild, int(std::thread::hardware_concurrency() * 2));
3501 int n = GetNumBuildThreads();
3502 if (n != -1)
3503 {
3504 numThreads = std::max(1, n);
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(project, rootModules[i], stopBuild, true, builtProjects);
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(&mtx, stopBuild, buildQueue, readyQueue, rootModules, isSystemSolution, builtProjects);
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& projectName, const std::string& projectDirectory, const std::string& target,
3627 const std::std::vector<std::string>&sourceFiles, conststd::std::vector<std::string>&resourceFiles, conststd::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(projectDirectory, projectName + ".cmproj"));
3632 std::unique_ptr<Project> project(new Project(ToUtf32(projectName), projectFilePath, GetConfig(), 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(), rootModule, stopBuild, false, builtProjects);
3677 }
3678
3679 } }