1
2
3
4
5
6 #include <sngcm/ast/InitDone.hpp>
7 #include <soulng/util/InitDone.hpp>
8 #include <cmajor/build/Build.hpp>
9 #include <cmajor/cmmid/InitDone.hpp>
10 #include <cmajor/symbols/Exception.hpp>
11 #include <cmajor/symbols/InitDone.hpp>
12 #include <cmajor/symbols/GlobalFlags.hpp>
13 #include <cmajor/symbols/ModuleCache.hpp>
14 #include <cmajor/symbols/Warning.hpp>
15 #include <sngxml/dom/Document.hpp>
16 #include <sngxml/dom/Element.hpp>
17 #include <sngxml/dom/CharacterData.hpp>
18 #include <soulng/lexer/ParsingException.hpp>
19 #include <soulng/util/Util.hpp>
20 #include <soulng/util/Path.hpp>
21 #include <soulng/util/Json.hpp>
22 #include <soulng/util/Unicode.hpp>
23 #include <boost/filesystem.hpp>
24 #include <boost/lexical_cast.hpp>
25 #include <iostream>
26 #include <string>
27 #include <stdexcept>
28 #include <chrono>
29
30 struct InitDone
31 {
32 InitDone()
33 {
34 soulng::util::Init();
35 sngcm::ast::Init();
36 cmajor::symbols::Init();
37 }
38 ~InitDone()
39 {
40 cmajor::symbols::Done();
41 sngcm::ast::Done();
42 soulng::util::Done();
43 }
44 };
45
46 struct BackendInit
47 {
48 BackendInit()
49 {
50 CmmInit(cmajor::mid::BackEndKind::cmsxBackEnd);
51 }
52 ~BackendInit()
53 {
54 CmmDone();
55 }
56 };
57
58 const char* version = "0.2.0";
59
60 void PrintHelp()
61 {
62 #ifdef _WIN32
63
64 #else
65 std::cout << "Cmajor System X compiler version " << version << std::endl;
66 #endif
67 std::cout << "Usage: sxcmc [options] { project.cmp | solution.cms }" << std::endl;
68 std::cout << "Compiles given Cmajor solutions and projects to System X libraries or executables." << std::endl;
69 std::cout << "Options:\n" <<
70 "--help (-h)\n" <<
71 " print this help message\n" <<
72 "--config=CONFIG (-c=CONFIG)\n" <<
73 " set configuration to CONFIG (debug | release)\n" <<
74 " default is debug\n" <<
75 "--optimization-level=LEVEL (-O=LEVEL)\n" <<
76 " set optimization level to LEVEL=0-3\n" <<
77 " defaults: debug=0, release=3\n" <<
78 "--verbose (-v)\n" <<
79 " print verbose messages\n" <<
80 "--quiet (-q)\n" <<
81 " print no messages\n" <<
82 "--strict-nothrow (-s)\n" <<
83 " treat nothrow violation as an error\n" <<
84 "--time (-t)\n" <<
85 " print duration of compilation\n" <<
86 "--outdir=OUTDIR (-o=OUTDIR)\n" <<
87 " set output directory root to OUTDIR\n" <<
88 "--rebuild (-u)\n" <<
89 " build although sources not changed\n" <<
90 "--clean (-e)\n" <<
91 " clean given solutions and projects\n" <<
92 "--debug-parse (-p)\n" <<
93 " debug parsing to stdout\n" <<
94 "--define SYMBOL (-D SYMBOL)\n" <<
95 " define a conditional compilation symbol SYMBOL.\n" <<
96 "--gen-debug-info (-g)\n" <<
97 " generate debug info (on by default in debug configuration)\n" <<
98 "--no-debug-info (-n)\n" <<
99 " don't generate debug info even for debug build\n" <<
100 "--build-threads=N (-bt=N)\n" <<
101 " set number of build threads to N\n" <<
102 "--disable-module-cache (-dm)\n" <<
103 " do not cache recently built modules\n" <<
104 "--single-threaded-compile (-st)\n" <<
105 " compile source files in a project using a single thread\n" <<
106 "--debug-compile (-dc)\n" <<
107 " show debug messages from multithreaded compilation\n" <<
108 std::endl;
109 }
110
111 using namespace soulng::util;
112 using namespace soulng::unicode;
113 using namespace cmajor::symbols;
114 using namespace cmajor::build;
115
116 int main(int argc, const char** argv)
117 {
118 SetBackEnd(cmajor::symbols::BackEnd::cmsx);
119
120
121 std::set<std::string> builtProjects;
122 std::unique_ptr<Module> rootModule;
123 std::vector<std::std::unique_ptr<Module>>rootModules;
124 try
125 {
126 std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
127 InitDone initDone;
128 std::string projectName;
129 std::string projectDirectory;
130 std::string target = "program";
131 std::vector<std::string> files;
132 std::vector<std::string> sourceFiles;
133 std::vector<std::string> referenceFiles;
134 if (argc < 2)
135 {
136 PrintHelp();
137 }
138 else
139 {
140 SetCompilerVersion(version);
141 bool prevWasDefine = false;
142 bool noDebugInfo = false;
143 bool useModuleCache = true;
144 for (int i = 1; i < argc; ++i)
145 {
146 std::string arg = argv[i];
147 if (!arg.empty() && arg[0] == '-')
148 {
149 if (arg == "--help" || arg == "-h")
150 {
151 PrintHelp();
152 return 0;
153 }
154 else if (arg == "--verbose" || arg == "-v")
155 {
156 SetGlobalFlag(GlobalFlags::verbose);
157 }
158 else if (arg == "--quiet" || arg == "-q")
159 {
160 SetGlobalFlag(GlobalFlags::quiet);
161 }
162 else if (arg == "--clean" || arg == "-e")
163 {
164 SetGlobalFlag(GlobalFlags::clean);
165 }
166 else if (arg == "--debug-parse" || arg == "-p")
167 {
168 SetGlobalFlag(GlobalFlags::debugParsing);
169 }
170 else if (arg == "--strict-nothrow" || arg == "-s")
171 {
172 SetGlobalFlag(GlobalFlags::strictNothrow);
173 }
174 else if (arg == "--time" || arg == "-t")
175 {
176 SetGlobalFlag(GlobalFlags::time);
177 }
178 else if (arg == "--rebuild" || arg == "-u")
179 {
180 SetGlobalFlag(GlobalFlags::rebuild);
181 }
182 else if (arg == "--define" || arg == "-D")
183 {
184 prevWasDefine = true;
185 }
186 else if (arg == "--gen-debug-info" || arg == "-g")
187 {
188 SetGlobalFlag(GlobalFlags::generateDebugInfo);
189 }
190 else if (arg == "--no-debug-info" || arg == "-n")
191 {
192 noDebugInfo = true;
193 }
194 else if (arg == "--disable-module-cache" || arg == "-dm")
195 {
196 useModuleCache = false;
197 }
198 else if (arg == "--single-threaded-compile" || arg == "-st")
199 {
200 SetGlobalFlag(GlobalFlags::singleThreadedCompile);
201 }
202 else if (arg == "--debug-compile" || arg == "-dc")
203 {
204 SetGlobalFlag(GlobalFlags::debugCompile);
205 }
206 else if (arg.find('=') != std::string::npos)
207 {
208 std::vector<std::string> components = Split(arg, '=');
209 if (components.size() == 2)
210 {
211 if (components[0] == "--config" || components[0] == "-c")
212 {
213 if (components[1] == "release")
214 {
215 SetGlobalFlag(GlobalFlags::release);
216 }
217 else if (components[1] != "debug")
218 {
219 throw std::runtime_error("unknown configuration '" + components[1] + "'");
220 }
221 }
222 else if (components[0] == "--optimization-level" || components[0] == "-O")
223 {
224 int optimizationLevel = boost::lexical_cast<int>(components[1]);
225 if (optimizationLevel >= 0 && optimizationLevel <= 3)
226 {
227 SetOptimizationLevel(optimizationLevel);
228 }
229 else
230 {
231 throw std::runtime_error("unknown optimization level '" + components[1] + "'");
232 }
233 }
234 else if (components[0] == "--reference" || components[0] == "-r")
235 {
236 std::string file = components[1];
237 boost::filesystem::path fp(file);
238 if (!boost::filesystem::exists(fp))
239 {
240 throw std::runtime_error("referenced project file '" + fp.generic_string() + "' not found");
241 }
242 referenceFiles.push_back(file);
243 }
244 else if (components[0] == "--target" || components[0] == "-a")
245 {
246 target = components[1];
247 if (target != "program" && target != "library" && target != "unitTest")
248 {
249 throw std::runtime_error("unknown target '" + target + "': not 'program', 'library', or 'unitTest'");
250 }
251 }
252 else if (components[0] == "--name" || components[0] == "-N")
253 {
254 projectName = components[1];
255 }
256 else if (components[0] == "--dir" || components[0] == "-pd")
257 {
258 projectDirectory = components[1];
259 }
260 else if (components[0] == "--build-threads" || components[0] == "-bt")
261 {
262 int numBuildThreads = boost::lexical_cast<int>(components[1]);
263 SetNumBuildThreads(numBuildThreads);
264 }
265 else if (components[0] == "--outdir" || components[0] == "-o")
266 {
267 std::string outdir = components[1];
268 SetOutDir(outdir);
269 }
270 else
271 {
272 throw std::runtime_error("unknown option '" + arg + "'");
273 }
274 }
275 else
276 {
277 throw std::runtime_error("invalid argument '" + arg + "'");
278 }
279 }
280 else
281 {
282 throw std::runtime_error("unknown option '" + arg + "'");
283 }
284 }
285 else if (prevWasDefine)
286 {
287 prevWasDefine = false;
288 DefineCommandLineConditionalSymbol(ToUtf32(arg));
289 }
290 else
291 {
292 files.push_back(arg);
293 }
294 }
295 if (files.empty())
296 {
297 PrintHelp();
298 return 0;
299 }
300 if (GetGlobalFlag(GlobalFlags::verbose))
301 {
302 #ifdef _WIN32
303
304 #else
305 std::cout << "Cmajor System X compiler version " << version << std::endl;
306 #endif
307 }
308 #ifndef _WIN32
309 noDebugInfo = true;
310 #endif
311 SetUseModuleCache(useModuleCache);
312 BackendInit backend;
313 if (!GetGlobalFlag(GlobalFlags::release) && !noDebugInfo)
314 {
315 SetGlobalFlag(GlobalFlags::generateDebugInfo);
316 }
317 #ifndef _WIN32
318 SetNumBuildThreads(1);
319 SetGlobalFlag(GlobalFlags::singleThreadedCompile);
320 #endif
321 for (const std::string& file : files)
322 {
323 boost::filesystem::path fp(file);
324 if (fp.extension() == ".cms")
325 {
326 if (GetGlobalFlag(GlobalFlags::msbuild))
327 {
328 throw std::runtime_error("solution file '" + fp.generic_string() + "' cannot be given in --msbuild mode");
329 }
330 else if (!boost::filesystem::exists(fp))
331 {
332 throw std::runtime_error("solution file '" + fp.generic_string() + "' not found");
333 }
334 else
335 {
336 BuildSolution(GetFullPath(fp.generic_string()), rootModules);
337 }
338 }
339 else if (fp.extension() == ".cmp")
340 {
341 if (GetGlobalFlag(GlobalFlags::msbuild))
342 {
343 throw std::runtime_error("project file '" + fp.generic_string() + "' cannot be given in --msbuild mode");
344 }
345 else if (!boost::filesystem::exists(fp))
346 {
347 throw std::runtime_error("project file '" + fp.generic_string() + "' not found");
348 }
349 else
350 {
351 BuildProject(GetFullPath(fp.generic_string()), rootModule, builtProjects);
352 }
353 }
354 else if (fp.extension() == ".cm")
355 {
356 if (GetGlobalFlag(GlobalFlags::msbuild))
357 {
358 boost::filesystem::path f(projectDirectory);
359 f /= fp;
360 if (!boost::filesystem::exists(f))
361 {
362 throw std::runtime_error("source file '" + f.generic_string() + "' not found");
363 }
364 else
365 {
366 sourceFiles.push_back(GetFullPath(f.generic_string()));
367 }
368 }
369 else
370 {
371 throw std::runtime_error("single .cm source file '" + fp.generic_string() + "' cannot be given if not in --msbuild mode");
372 }
373 }
374 else
375 {
376 if (GetGlobalFlag(GlobalFlags::msbuild))
377 {
378 throw std::runtime_error("Argument '" + fp.generic_string() + "' has invalid extension. Not Cmajor source (.cm) file.");
379 }
380 else
381 {
382 throw std::runtime_error("Argument '" + fp.generic_string() + "' has invalid extension. Not Cmajor solution (.cms) or project (.cmp) file.");
383 }
384 }
385 }
386 if (rootModule && !rootModule->WarningCollection().Warnings().empty())
387 {
388 if (!GetGlobalFlag(GlobalFlags::quiet) && !GetGlobalFlag(GlobalFlags::ide) && !GetGlobalFlag(GlobalFlags::msbuild))
389 {
390 }
391 if (GetGlobalFlag(GlobalFlags::ide))
392 {
393 std::unique_ptr<JsonObject> compileResult(new JsonObject());
394 compileResult->AddField(U"success", std::unique_ptr<JsonValue>(new JsonBool(true)));
395 std::cerr << compileResult->ToString() << std::endl;
396 }
397 }
398 else if (GetGlobalFlag(GlobalFlags::ide))
399 {
400 std::unique_ptr<JsonObject> compileResult(new JsonObject());
401 compileResult->AddField(U"success", std::unique_ptr<JsonValue>(new JsonBool(true)));
402 std::cerr << compileResult->ToString() << std::endl;
403 }
404 if (GetGlobalFlag(GlobalFlags::time))
405 {
406 std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
407 auto dur = end - start;
408 long long totalSecs = std::chrono::duration_cast<std::chrono::seconds>(dur).count() + 1;
409 int hours = static_cast<int>(totalSecs / 3600);
410 int mins = static_cast<int>((totalSecs / 60) % 60);
411 int secs = static_cast<int>(totalSecs % 60);
412 std::cout <<
413 (hours > 0 ? std::to_string(hours) + " hour" + ((hours != 1) ? "s " : " ") : "") <<
414 (mins > 0 ? std::to_string(mins) + " minute" + ((mins != 1) ? "s " : " ") : "") <<
415 secs << " second" << ((secs != 1) ? "s" : "") << std::endl;
416 }
417 }
418 }
419 catch (const soulng::lexer::ParsingException& ex;)
420 {
421 if (!GetGlobalFlag(GlobalFlags::quiet))
422 {
423 std::cerr << ex.what() << std::endl;
424 }
425 return 1;
426 }
427 catch (const Exception& ex;)
428 {
429 if (!GetGlobalFlag(GlobalFlags::quiet))
430 {
431 std::cerr << ex.What() << std::endl;
432 }
433 return 1;
434 }
435 catch (const std::exception& ex;)
436 {
437 if (!GetGlobalFlag(GlobalFlags::quiet))
438 {
439 std::cerr << ex.what() << std::endl;
440 }
441 return 1;
442 }
443 return 0;
444 }