1
2
3
4
5
6 #include <cmajor/cmcm/Compiler.hpp>
7 #include <cmajor/Build/Build.hpp>
8 #include <cmajor/cmres/InitDone.hpp>
9 #include <sngcm/ast/InitDone.hpp>
10 #include <soulng/lexer/ParsingException.hpp>
11 #include <soulng/util/InitDone.hpp>
12 #include <soulng/util/Path.hpp>
13 #include <soulng/util/Unicode.hpp>
14 #include <soulng/util/Log.hpp>
15 #include <soulng/util/System.hpp>
16 #include <cmajor/symbols/GlobalFlags.hpp>
17 #include <sngxml/dom/Parser.hpp>
18 #include <sngxml/dom/CharacterData.hpp>
19 #include <sngxml/xpath/InitDone.hpp>
20 #include <cmajor/symbols/InitDone.hpp>
21 #include <cmajor/symbols/Exception.hpp>
22 #include <cmajor/symbols/ModuleCache.hpp>
23 #include <boost/lexical_cast.hpp>
24 #include <string>
25 #include <iostream>
26 #include <sstream>
27 #include <memory>
28 #include <vector>
29 #include <mutex>
30 #include <stdexcept>
31
32 bool initialized = false;
33
34 using namespace soulng::unicode;
35
36 class CompileData
37 {
38 public:
39 static void Init();
40 static void Done();
41 static CompileData& Instance() { return *instance; }
42 int SetCompileResult(const std::u16string& compileResult);
43 int GetCompileResultLength(int compileResultHandle);
44 int GetCompileResult(int compileResultHandle, char16_t* buf, int length);
45 private:
46 static std::unique_ptr<CompileData> instance;
47 std::mutex mtx;
48 std::vector<std::std::unique_ptr<std::u16string>>compileResults;
49 };
50
51 std::unique_ptr<CompileData> CompileData::instance;
52
53 void CompileData::Init()
54 {
55 instance.reset(new CompileData());
56 }
57
58 void CompileData::Done()
59 {
60 instance.reset();
61 }
62
63 int CompileData::SetCompileResult(const std::u16string& compileResult)
64 {
65 std::lock_guard<std::mutex> lock(mtx);
66 int compileResultHandle = compileResults.size();
67 compileResults.push_back(std::unique_ptr<std::u16string>(new std::u16string(compileResult)));
68 return compileResultHandle;
69 }
70
71 int CompileData::GetCompileResultLength(int compileResultHandle)
72 {
73 std::lock_guard<std::mutex> lock(mtx);
74 if (compileResultHandle < 0 || compileResultHandle >= compileResults.size()) return -1;
75 if (!compileResults[compileResultHandle]) return -1;
76 const std::u16string& compileResult = *compileResults[compileResultHandle];
77 return compileResult.length();
78 }
79
80 int CompileData::GetCompileResult(int compileResultHandle, char16_t* buf, int size)
81 {
82 std::lock_guard<std::mutex> lock(mtx);
83 if (compileResultHandle < 0 || compileResultHandle >= compileResults.size()) return -1;
84 if (!compileResults[compileResultHandle]) return -1;
85 const std::u16string& compileResult = *compileResults[compileResultHandle];
86 int n = compileResult.length();
87 if (size <= n) return -1;
88 for (int i = 0; i < n; ++i)
89 {
90 buf[i] = compileResult[i];
91 }
92 for (int i = n; i < size; ++i)
93 {
94 buf[i] = u'\0';
95 }
96 compileResults[compileResultHandle].reset();
97 return 0;
98 }
99
100 extern "C" void Init()
101 {
102 soulng::util::Init();
103 sngcm::ast::Init();
104 cmajor::symbols::Init();
105 CompileData::Init();
106 soulng::util::SetLogMode(soulng::util::LogMode::queue);
107 soulng::util::DisableConsoleWindow();
108 sngxml::xpath::Init();
109 cmajor::resources::Init();
110 initialized = true;
111 }
112
113 extern "C" void Done()
114 {
115 initialized = false;
116 cmajor::resources::Done();
117 sngxml::xpath::Done();
118 CompileData::Done();
119 cmajor::symbols::Done();
120 sngcm::ast::Done();
121 soulng::util::Done();
122 }
123
124 std::std::unique_ptr<sngxml::dom::Element>SpanElement(cmajor::symbols::Module*module, constsoulng::lexer::Span&span)
125 {
126 std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
127 if (span.Valid() && module)
128 {
129 std::string fileName = module->GetFilePath(span.fileIndex);
130 if (fileName.empty()) return std::unique_ptr<sngxml::dom::Element>();
131 spanElement->SetAttribute(U"file", ToUtf32(fileName));
132 spanElement->SetAttribute(U"line", ToUtf32(std::to_string(span.line)));
133 std::u32string text = module->GetErrorLines(span);
134 int32_t startCol = 0;
135 int32_t endCol = 0;
136 module->GetColumns(span, startCol, endCol);
137 spanElement->SetAttribute(U"startCol", ToUtf32(std::to_string(startCol)));
138 spanElement->SetAttribute(U"endCol", ToUtf32(std::to_string(endCol)));
139 spanElement->SetAttribute(U"text", text);
140 }
141 else
142 {
143 spanElement.reset();
144 }
145 return spanElement;
146 }
147
148 void AddWarningsTo(sngxml::dom::Element* diagnosticsElement, cmajor::symbols::Module* module)
149 {
150 if (!module) return;
151 if (!module->WarningCollection().Warnings().empty())
152 {
153 for (const cmajor::symbols::Warning& warning : module->WarningCollection().Warnings())
154 {
155 std::unique_ptr<sngxml::dom::Element> diagnosticElement(new sngxml::dom::Element(U"diagnostic"));
156 diagnosticElement->SetAttribute(U"category", U"warning");
157 diagnosticElement->SetAttribute(U"message", ToUtf32(warning.Message()));
158 diagnosticElement->SetAttribute(U"project", warning.Project());
159 std::unique_ptr<sngxml::dom::Element> spanElement = SpanElement(module, warning.Defined());
160 if (spanElement)
161 {
162 diagnosticElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(spanElement.release()));
163 }
164 diagnosticsElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(diagnosticElement.release()));
165 for (const std::std::pair<soulng::lexer::Span, boost::uuids::uuid>&spanModuleId : warning.References())
166 {
167 if (!spanModuleId.first.Valid()) continue;
168 std::unique_ptr<sngxml::dom::Element> diagnosticElement(new sngxml::dom::Element(U"diagnostic"));
169 diagnosticElement->SetAttribute(U"category", U"info");
170 diagnosticElement->SetAttribute(U"message", ToUtf32("see reference to"));
171 cmajor::symbols::Module* mod = cmajor::symbols::GetModuleById(spanModuleId.second);
172 std::unique_ptr<sngxml::dom::Element> spanElement = SpanElement(mod, spanModuleId.first);
173 if (spanElement)
174 {
175 diagnosticElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(spanElement.release()));
176 diagnosticsElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(diagnosticElement.release()));
177 }
178 }
179 }
180 }
181 }
182
183 const char* version = "3.10.0";
184
185 extern "C" int Compile(const char16_t* compileXmlRequest)
186 {
187 if (!initialized) return -1;
188 std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
189 cmajor::symbols::ResetGlobalFlags();
190 cmajor::symbols::SetCompilerVersion(version);
191 cmajor::symbols::Module* module = nullptr;
192 bool noDebugInfo = false;
193 std::unique_ptr<cmajor::symbols::Module> rootModule;
194 std::vector<std::unique_ptr<cmajor::symbols::Module>> rootModules;
195 std::set<std::string> builtProjects;
196 sngxml::dom::Document compileResultDoc;
197 std::unique_ptr<sngxml::dom::Element> compileResultElement(new sngxml::dom::Element(U"compileResult"));
198 std::unique_ptr<sngxml::dom::Element> diagnosticsElement(new sngxml::dom::Element(U"diagnostics"));
199 try
200 {
201 std::u32string compileRequest = ToUtf32(compileXmlRequest);
202 std::unique_ptr<sngxml::dom::Document> compileRequestDoc = sngxml::dom::ParseDocument(compileRequest, "compileRequest");
203 sngxml::dom::Element* compileRequestElement = compileRequestDoc->DocumentElement();
204 std::string filePath = ToUtf8(compileRequestElement->GetAttribute(U"filePath"));
205 std::string config = ToUtf8(compileRequestElement->GetAttribute(U"config"));
206 if (config == "release")
207 {
208 cmajor::symbols::SetGlobalFlag(cmajor::symbols::GlobalFlags::release);
209 }
210 bool verbose = compileRequestElement->GetAttribute(U"verbose") == U"true";
211 if (verbose)
212 {
213 cmajor::symbols::SetGlobalFlag(cmajor::symbols::GlobalFlags::verbose);
214 }
215 bool clean = compileRequestElement->GetAttribute(U"clean") == U"true";
216 if (clean)
217 {
218 cmajor::symbols::SetGlobalFlag(cmajor::symbols::GlobalFlags::clean);
219 }
220 bool rebuild = compileRequestElement->GetAttribute(U"rebuild") == U"true";
221 if (rebuild)
222 {
223 cmajor::symbols::SetGlobalFlag(cmajor::symbols::GlobalFlags::rebuild);
224 }
225 bool time = compileRequestElement->GetAttribute(U"time") == U"true";
226 bool strictNothrow = compileRequestElement->GetAttribute(U"strict-nothrow") == U"true";
227 if (strictNothrow)
228 {
229 cmajor::symbols::SetGlobalFlag(cmajor::symbols::GlobalFlags::strictNothrow);
230 }
231 bool emitLlvm = compileRequestElement->GetAttribute(U"emit-llvm") == U"true";
232 if (emitLlvm)
233 {
234 cmajor::symbols::SetGlobalFlag(cmajor::symbols::GlobalFlags::emitLlvm);
235 }
236 bool emitOptLlvm = compileRequestElement->GetAttribute(U"emit-opt-llvm") == U"true";
237 if (emitOptLlvm)
238 {
239 cmajor::symbols::SetGlobalFlag(cmajor::symbols::GlobalFlags::emitOptLlvm);
240 }
241 bool linkWithDebugRuntime = compileRequestElement->GetAttribute(U"link-with-debug-runtime") == U"true";
242 if (linkWithDebugRuntime)
243 {
244 cmajor::symbols::SetGlobalFlag(cmajor::symbols::GlobalFlags::linkWithDebugRuntime);
245 }
246 bool linkUsingMsLink = compileRequestElement->GetAttribute(U"link-using-ms-link") == U"true";
247 if (linkUsingMsLink)
248 {
249 cmajor::symbols::SetGlobalFlag(cmajor::symbols::GlobalFlags::linkUsingMsLink);
250 }
251 bool singleThreadedCompile = compileRequestElement->GetAttribute(U"single-threaded-compile") == U"true";
252 if (singleThreadedCompile)
253 {
254 cmajor::symbols::SetGlobalFlag(cmajor::symbols::GlobalFlags::singleThreadedCompile);
255 }
256 std::string optimizationLevelStr = ToUtf8(compileRequestElement->GetAttribute(U"optimization-level"));
257 if (!optimizationLevelStr.empty())
258 {
259 int optimizationLevel = boost::lexical_cast<int>(optimizationLevelStr);
260 cmajor::symbols::SetOptimizationLevel(optimizationLevel);
261 }
262 std::string buildThreads = ToUtf8(compileRequestElement->GetAttribute(U"build-threads"));
263 if (!buildThreads.empty())
264 {
265 int numBuildThreads = boost::lexical_cast<int>(buildThreads);
266 cmajor::symbols::SetNumBuildThreads(numBuildThreads);
267 }
268 if (cmajor::symbols::GetGlobalFlag(cmajor::symbols::GlobalFlags::verbose))
269 {
270 LogMessage(-1, "Cmajor compiler with LLVM backend version " + std::string(version) + " for Windows x64");
271 }
272 if (!cmajor::symbols::GetGlobalFlag(cmajor::symbols::GlobalFlags::release) && !noDebugInfo)
273 {
274 cmajor::symbols::SetGlobalFlag(cmajor::symbols::GlobalFlags::generateDebugInfo);
275 }
276 if (Path::GetExtension(filePath) == ".cms")
277 {
278 cmajor::build::BuildSolution(GetFullPath(filePath), rootModules);
279 }
280 else if (Path::GetExtension(filePath) == ".cmp")
281 {
282 module = rootModule.get();
283 cmajor::build::BuildProject(GetFullPath(filePath), rootModule, builtProjects);
284 }
285 else
286 {
287 throw std::runtime_error("invalid 'filePath' parameter: not .cms or .cmp");
288 }
289 compileResultElement->SetAttribute(U"success", U"true");
290 if (time)
291 {
292 std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
293 auto dur = end - start;
294 long long totalSecs = std::chrono::duration_cast<std::chrono::seconds>(dur).count() + 1;
295 int hours = static_cast<int>(totalSecs / 3600);
296 int mins = static_cast<int>((totalSecs / 60) % 60);
297 int secs = static_cast<int>(totalSecs % 60);
298 std::stringstream timeStream;
299 timeStream <<
300 (hours > 0 ? std::to_string(hours) + " hour" + ((hours != 1) ? "s " : " ") : "") <<
301 (mins > 0 ? std::to_string(mins) + " minute" + ((mins != 1) ? "s " : " ") : "") <<
302 secs << " second" << ((secs != 1) ? "s" : "");
303 LogMessage(-1, timeStream.str());
304 }
305 }
306 catch (const soulng::lexer::ParsingException& ex)
307 {
308 LogMessage(-1, ex.what());
309 module = static_cast<cmajor::symbols::Module*>(ex.Module());
310 compileResultElement->SetAttribute(U"success", U"false");
311 std::unique_ptr<sngxml::dom::Element> diagnosticElement(new sngxml::dom::Element(U"diagnostic"));
312 diagnosticElement->SetAttribute(U"category", U"error");
313 diagnosticElement->SetAttribute(U"message", ToUtf32(ex.Message()));
314 diagnosticElement->SetAttribute(U"tool", U"cmc");
315 diagnosticElement->SetAttribute(U"project", ToUtf32(ex.Project()));
316 std::unique_ptr<sngxml::dom::Element> spanElement = SpanElement(module, ex.GetSpan());
317 if (spanElement)
318 {
319 diagnosticElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(spanElement.release()));
320 }
321 diagnosticsElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(diagnosticElement.release()));
322 }
323 catch (const cmajor::symbols::Exception& ex)
324 {
325 LogMessage(-1, ex.What());
326 cmajor::symbols::Module* module = cmajor::symbols::GetModuleById(ex.DefinedModuleId());
327 compileResultElement->SetAttribute(U"success", U"false");
328 std::unique_ptr<sngxml::dom::Element> diagnosticElement(new sngxml::dom::Element(U"diagnostic"));
329 diagnosticElement->SetAttribute(U"category", U"error");
330 diagnosticElement->SetAttribute(U"message", ToUtf32(ex.Message()));
331 diagnosticElement->SetAttribute(U"tool", module->GetCurrentToolName());
332 diagnosticElement->SetAttribute(U"project", module->GetCurrentProjectName());
333 std::unique_ptr<sngxml::dom::Element> spanElement = SpanElement(module, ex.Defined());
334 if (spanElement)
335 {
336 diagnosticElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(spanElement.release()));
337 }
338 diagnosticsElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(diagnosticElement.release()));
339 for (const std::pair<soulng::lexer::Span, boost::uuids::uuid>& spanModuleId : ex.References())
340 {
341 if (!spanModuleId.first.Valid()) continue;
342 std::unique_ptr<sngxml::dom::Element> diagnosticElement(new sngxml::dom::Element(U"diagnostic"));
343 diagnosticElement->SetAttribute(U"category", U"info");
344 diagnosticElement->SetAttribute(U"message", ToUtf32("see reference to"));
345 cmajor::symbols::Module* mod = cmajor::symbols::GetModuleById(spanModuleId.second);
346 std::unique_ptr<sngxml::dom::Element> spanElement = SpanElement(mod, spanModuleId.first);
347 if (spanElement)
348 {
349 diagnosticElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(spanElement.release()));
350 diagnosticsElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(diagnosticElement.release()));
351 }
352 }
353 }
354 catch (const std::exception& ex)
355 {
356 LogMessage(-1, ex.what());
357 compileResultElement->SetAttribute(U"success", U"false");
358 std::unique_ptr<sngxml::dom::Element> diagnosticElement(new sngxml::dom::Element(U"diagnostic"));
359 diagnosticElement->SetAttribute(U"category", U"error");
360 diagnosticElement->SetAttribute(U"message", ToUtf32(ex.what()));
361 diagnosticsElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(diagnosticElement.release()));
362 }
363 if (!module)
364 {
365 if (rootModule)
366 {
367 module = rootModule.get();
368 }
369 else
370 {
371 for (const auto& m : rootModules)
372 {
373 if (m)
374 {
375 module = m.get();
376 }
377 }
378 }
379 }
380 AddWarningsTo(diagnosticsElement.get(), module);
381 compileResultElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(diagnosticsElement.release()));
382 compileResultDoc.AppendChild(std::unique_ptr<sngxml::dom::Node>(compileResultElement.release()));
383 std::ostringstream strStream;
384 CodeFormatter formatter(strStream);
385 formatter.SetIndentSize(1);
386 compileResultDoc.Write(formatter);
387 return CompileData::Instance().SetCompileResult(ToUtf16(strStream.str()));
388 }
389
390 extern "C" int GetCompileResultLength(int compileResultHandle)
391 {
392 if (!initialized) return -1;
393 return CompileData::Instance().GetCompileResultLength(compileResultHandle);
394 }
395
396 extern "C" int GetCompileResult(int compileResultHandle, char16_t* buf, int size)
397 {
398 if (!initialized) return -1;
399 return CompileData::Instance().GetCompileResult(compileResultHandle, buf, size);
400 }
401
402 extern "C" void StopBuild()
403 {
404 cmajor::build::StopBuild();
405 }
406
407 extern "C" int WaitForLogMessage()
408 {
409 if (!initialized) return -1;
410 return soulng::util::WaitForLogMessage();
411 }
412
413 extern "C" int FetchLogMessage(char16_t* buf, int size)
414 {
415 if (!initialized) return -1;
416 return soulng::util::FetchLogMessage(buf, size);
417 }
418
419 extern "C" void StartLog()
420 {
421 soulng::util::StartLog();
422 }
423
424 extern "C" void EndLog()
425 {
426 soulng::util::EndLog();
427 }
428
429 extern "C" void ResetModuleCache()
430 {
431 cmajor::symbols::ResetModuleCache();
432 }
433
434 extern "C" void SetUseModuleCache(bool useModuleCache_)
435 {
436 cmajor::symbols::SetUseModuleCache(useModuleCache_);
437 }