1 module driver.sdc;
2 
3 import source.context;
4 
5 int main(string[] args) {
6 	version (DigitalMars) {
7 		version (linux) {
8 			import etc.linux.memoryerror;
9 			// druntime not containe the necessary symbol.
10 			// registerMemoryErrorHandler();
11 		}
12 	}
13 
14 	auto context = new Context();
15 
16 	import std.getopt, source.exception;
17 	try {
18 		return context.run(args);
19 	} catch (GetOptException ex) {
20 		import std.stdio;
21 		writefln("%s", ex.msg);
22 		writeln("Please use -h to get a list of valid options.");
23 		return 1;
24 	} catch (CompileException e) {
25 		import util.terminal;
26 		outputCaretDiagnostics(e.getFullLocation(context), e.msg);
27 
28 		// Rethrow in debug, so we have the stack trace.
29 		debug {
30 			throw e;
31 		} else {
32 			return 1;
33 		}
34 	}
35 
36 	// This is unreachable, but dmd can't figure this out.
37 	assert(0);
38 }
39 
40 int run(Context context, string[] args) {
41 	import sdc.config;
42 	Config conf;
43 
44 	import config.build;
45 	conf.buildGlobalConfig("sdconfig", context);
46 
47 	string[] includePaths, linkerPaths;
48 	bool dontLink, generateMain;
49 	string outputFile;
50 	bool outputLLVM, outputAsm;
51 
52 	import std.getopt;
53 	auto help_info = getopt(
54 		// sdfmt off
55 		args, std.getopt.config.caseSensitive,
56 		"I",         "Include path",        &includePaths,
57 		"L",         "Library path",        &linkerPaths,
58 		"O",         "Optimization level",  &conf.optLevel,
59 		"c",         "Stop before linking", &dontLink,
60 		"o",         "Output file",         &outputFile,
61 		"S",         "Stop before assembling and output assembly file", &outputAsm,
62 		"emit-llvm", "Output LLVM bitcode (-c) or LLVM assembly (-S)",  &outputLLVM,
63 		"main",      "Generate the main function", &generateMain,
64 		// sdfmt on
65 	);
66 
67 	if (help_info.helpWanted || args.length == 1) {
68 		import std.stdio;
69 		writeln("The Snazzy D Compiler");
70 		writeln("Usage: sdc [options] file.d");
71 		writeln("Options:");
72 
73 		foreach (option; help_info.options) {
74 			writefln("  %-16s %s",
75 			         // bug : optShort is empty if there is no long version
76 			         option.optShort.length
77 				         ? option.optShort
78 				         : (option.optLong.length == 3)
79 					         ? option.optLong[1 .. $]
80 					         : option.optLong,
81 			         option.help);
82 		}
83 
84 		return 0;
85 	}
86 
87 	conf.includePaths = includePaths ~ conf.includePaths;
88 	conf.linkerPaths = linkerPaths ~ conf.linkerPaths;
89 
90 	auto files = args[1 .. $];
91 
92 	if (outputAsm) {
93 		dontLink = true;
94 	}
95 
96 	auto executable = "a.out";
97 	auto defaultExtension = ".o";
98 	if (outputAsm) {
99 		defaultExtension = outputLLVM ? ".ll" : ".s";
100 	} else if (dontLink) {
101 		defaultExtension = outputLLVM ? ".bc" : ".o";
102 	}
103 
104 	auto objFile = files[0][0 .. $ - 2] ~ defaultExtension;
105 	if (outputFile.length) {
106 		if (dontLink || outputAsm) {
107 			objFile = outputFile;
108 		} else {
109 			executable = outputFile;
110 		}
111 	}
112 
113 	// If we are generating an executable, we want a main function.
114 	generateMain = generateMain || !dontLink;
115 
116 	// Cannot call the variable "sdc" or DMD complains about name clash
117 	// with the sdc package from the import.
118 	import sdc.sdc;
119 	auto c = new SDC(context, files[0], conf);
120 
121 	foreach (file; files) {
122 		c.compile(file);
123 	}
124 
125 	if (generateMain) {
126 		c.buildMain();
127 	}
128 
129 	if (outputAsm) {
130 		if (outputLLVM) {
131 			c.outputLLVMAsm(objFile);
132 		} else {
133 			c.outputAsm(objFile);
134 		}
135 	} else if (dontLink) {
136 		if (outputLLVM) {
137 			c.outputLLVMBitcode(objFile);
138 		} else {
139 			c.outputObj(objFile);
140 		}
141 	} else {
142 		c.outputObj(objFile);
143 		c.linkExecutable(objFile, executable);
144 	}
145 
146 	return 0;
147 }