Mercurial > projects > ldc
comparison gen/main.cpp @ 989:420ef073448d
Forgot new files that were supposed to be in last commit.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Thu, 26 Feb 2009 14:13:27 +0100 |
parents | |
children | 4f12ec3216cf |
comparison
equal
deleted
inserted
replaced
988:2667e3a145be | 989:420ef073448d |
---|---|
1 // Pulled out of dmd/mars.c | |
2 | |
3 // some things are taken from llvm's llc tool | |
4 // which uses the llvm license | |
5 | |
6 #include "gen/llvm.h" | |
7 #include "llvm/Target/SubtargetFeature.h" | |
8 #include "llvm/Target/TargetMachine.h" | |
9 #include "llvm/Target/TargetMachineRegistry.h" | |
10 #include "llvm/LinkAllVMCore.h" | |
11 | |
12 #include <stdio.h> | |
13 #include <stdlib.h> | |
14 #include <assert.h> | |
15 #include <limits.h> | |
16 | |
17 #if POSIX | |
18 #include <errno.h> | |
19 #elif _WIN32 | |
20 #include <windows.h> | |
21 #endif | |
22 | |
23 #include "mem.h" | |
24 #include "root.h" | |
25 | |
26 #include "mars.h" | |
27 #include "module.h" | |
28 #include "mtype.h" | |
29 #include "id.h" | |
30 #include "cond.h" | |
31 | |
32 #include "gen/logger.h" | |
33 #include "gen/linker.h" | |
34 #include "gen/irstate.h" | |
35 | |
36 #include "gen/cl_options.h" | |
37 #include "gen/cl_helpers.h" | |
38 using namespace opts; | |
39 | |
40 extern void getenv_setargv(const char *envvar, int *pargc, char** *pargv); | |
41 extern void backend_init(); | |
42 extern void backend_term(); | |
43 | |
44 static cl::opt<bool> noDefaultLib("nodefaultlib", | |
45 cl::desc("Don't add a default library for linking implicitly"), | |
46 cl::ZeroOrMore); | |
47 | |
48 static ArrayAdapter impPathsStore("I", global.params.imppath); | |
49 static cl::list<std::string, ArrayAdapter> importPaths("I", | |
50 cl::desc("Where to look for imports"), | |
51 cl::value_desc("path"), | |
52 cl::location(impPathsStore), | |
53 cl::Prefix); | |
54 | |
55 static ArrayAdapter defaultLibStore("defaultlib", global.params.defaultlibnames); | |
56 static cl::list<std::string, ArrayAdapter> defaultlibs("defaultlib", | |
57 cl::desc("Set default libraries for non-debug build"), | |
58 cl::value_desc("lib,..."), | |
59 cl::location(defaultLibStore), | |
60 cl::CommaSeparated); | |
61 | |
62 static ArrayAdapter debugLibStore("debuglib", global.params.debuglibnames); | |
63 static cl::list<std::string, ArrayAdapter> debuglibs("debuglib", | |
64 cl::desc("Set default libraries for debug build"), | |
65 cl::value_desc("lib,..."), | |
66 cl::location(debugLibStore), | |
67 cl::CommaSeparated); | |
68 | |
69 void printVersion() { | |
70 printf("LLVM D Compiler %s\nbased on DMD %s and %s\n%s\n%s\n", | |
71 global.ldc_version, global.version, global.llvm_version, global.copyright, global.written); | |
72 printf("D Language Documentation: http://www.digitalmars.com/d/1.0/index.html\n" | |
73 "LDC Homepage: http://www.dsource.org/projects/ldc\n"); | |
74 } | |
75 | |
76 // Helper function to handle -d-debug=* and -d-version=* | |
77 static void processVersions(std::vector<std::string>& list, char* type, | |
78 void (*setLevel)(unsigned), void (*addIdent)(const char*)) { | |
79 typedef std::vector<std::string>::iterator It; | |
80 | |
81 for(It I = list.begin(), E = list.end(); I != E; ++I) { | |
82 const char* value = I->c_str(); | |
83 if (isdigit(value[0])) { | |
84 errno = 0; | |
85 char* end; | |
86 long level = strtol(value, &end, 10); | |
87 if (*end || errno || level > INT_MAX) { | |
88 error("Invalid %s level: %s", type, I->c_str()); | |
89 } else { | |
90 setLevel((unsigned)level); | |
91 } | |
92 } else { | |
93 char* cstr = mem.strdup(value); | |
94 if (Lexer::isValidIdentifier(cstr)) { | |
95 addIdent(cstr); | |
96 continue; | |
97 } else { | |
98 error("Invalid %s identifier or level: '%s'", type, I->c_str()); | |
99 } | |
100 } | |
101 } | |
102 } | |
103 | |
104 // Helper function to handle -of, -od, etc. | |
105 static void initFromString(char*& dest, const cl::opt<std::string>& src) { | |
106 dest = 0; | |
107 if (src.getNumOccurrences() != 0) { | |
108 if (src.empty()) | |
109 error("Expected argument to '-%s'", src.ArgStr); | |
110 dest = mem.strdup(src.c_str()); | |
111 } | |
112 } | |
113 | |
114 int main(int argc, char** argv) | |
115 { | |
116 Array files; | |
117 char *p, *ext; | |
118 Module *m; | |
119 int status = EXIT_SUCCESS; | |
120 | |
121 // Set some default values | |
122 #if _WIN32 | |
123 char buf[MAX_PATH]; | |
124 GetModuleFileName(NULL, buf, MAX_PATH); | |
125 global.params.argv0 = buf; | |
126 #else | |
127 global.params.argv0 = argv[0]; | |
128 #endif | |
129 global.params.useSwitchError = 1; | |
130 | |
131 global.params.linkswitches = new Array(); | |
132 global.params.libfiles = new Array(); | |
133 global.params.objfiles = new Array(); | |
134 global.params.ddocfiles = new Array(); | |
135 | |
136 // Set predefined version identifiers | |
137 VersionCondition::addPredefinedGlobalIdent("LLVM"); | |
138 VersionCondition::addPredefinedGlobalIdent("LDC"); | |
139 VersionCondition::addPredefinedGlobalIdent("all"); | |
140 | |
141 // read the inifile | |
142 #if DMDV2 | |
143 inifile(global.params.argv0, "ldc2.conf"); | |
144 #else | |
145 inifile(global.params.argv0, "ldc.conf"); | |
146 #endif | |
147 | |
148 // merge DFLAGS into argc/argv | |
149 getenv_setargv("DFLAGS", &argc, &argv); | |
150 #if 0 | |
151 for (int i = 0; i < argc; i++) | |
152 { | |
153 printf("argv[%d] = '%s'\n", i, argv[i]); | |
154 } | |
155 #endif | |
156 | |
157 // Handle fixed-up arguments! | |
158 cl::SetVersionPrinter(&printVersion); | |
159 cl::ParseCommandLineOptions(argc, argv, "LLVM-based D Compiler\n"); | |
160 | |
161 global.params.optimize = (global.params.optimizeLevel >= 0); | |
162 | |
163 // Negated options | |
164 global.params.link = !compileOnly; | |
165 global.params.obj = !dontWriteObj; | |
166 global.params.useInlineAsm = !noAsm; | |
167 | |
168 // String options: std::string --> char* | |
169 initFromString(global.params.objname, objectFile); | |
170 initFromString(global.params.objdir, objectDir); | |
171 | |
172 initFromString(global.params.docdir, ddocDir); | |
173 initFromString(global.params.docname, ddocFile); | |
174 global.params.doDocComments |= | |
175 global.params.docdir || global.params.docname; | |
176 | |
177 #ifdef _DH | |
178 initFromString(global.params.hdrdir, hdrDir); | |
179 initFromString(global.params.hdrname, hdrFile); | |
180 global.params.doHdrGeneration |= | |
181 global.params.hdrdir || global.params.hdrname; | |
182 #endif | |
183 | |
184 processVersions(debugArgs, "debug", | |
185 DebugCondition::setGlobalLevel, | |
186 DebugCondition::addGlobalIdent); | |
187 processVersions(versions, "version", | |
188 VersionCondition::setGlobalLevel, | |
189 VersionCondition::addGlobalIdent); | |
190 | |
191 global.params.output_o = | |
192 opts::output_o == cl::BOU_UNSET | |
193 ? OUTPUTFLAGdefault | |
194 : opts::output_o == cl::BOU_TRUE | |
195 ? OUTPUTFLAGset | |
196 : OUTPUTFLAGno; | |
197 global.params.output_bc = opts::output_bc ? OUTPUTFLAGset : OUTPUTFLAGno; | |
198 global.params.output_ll = opts::output_ll ? OUTPUTFLAGset : OUTPUTFLAGno; | |
199 global.params.output_s = opts::output_s ? OUTPUTFLAGset : OUTPUTFLAGno; | |
200 | |
201 if (global.params.run || !runargs.empty()) { | |
202 // FIXME: how to properly detect the presence of a PositionalEatsArgs | |
203 // option without parameters? We want to emit an error in that case... | |
204 // You'd think getNumOccurrences would do it, but it just returns the | |
205 // number of parameters) | |
206 // NOTE: Hacked around it by detecting -run in getenv_setargv(), where | |
207 // we're looking for it anyway, and pre-setting the flag... | |
208 global.params.run = true; | |
209 if (!runargs.empty()) { | |
210 files.push(mem.strdup(runargs[0].c_str())); | |
211 } else { | |
212 global.params.run = false; | |
213 error("Expected at least one argument to '-run'\n"); | |
214 } | |
215 } | |
216 | |
217 | |
218 files.reserve(fileList.size()); | |
219 typedef std::vector<std::string>::iterator It; | |
220 for(It I = fileList.begin(), E = fileList.end(); I != E; ++I) | |
221 if (!I->empty()) | |
222 files.push(mem.strdup(I->c_str())); | |
223 | |
224 if (global.errors) | |
225 { | |
226 fatal(); | |
227 } | |
228 if (files.dim == 0) | |
229 { | |
230 cl::PrintHelpMessage(); | |
231 return EXIT_FAILURE; | |
232 } | |
233 | |
234 Array* libs; | |
235 if (global.params.symdebug) | |
236 libs = global.params.debuglibnames; | |
237 else | |
238 libs = global.params.defaultlibnames; | |
239 | |
240 if (libs) | |
241 { | |
242 for (int i = 0; i < libs->dim; i++) | |
243 { | |
244 char *arg = (char *)mem.malloc(64); | |
245 strcpy(arg, "-l"); | |
246 strncat(arg, (char *)libs->data[i], 64); | |
247 global.params.linkswitches->push(arg); | |
248 } | |
249 } | |
250 else if (!noDefaultLib) | |
251 { | |
252 char *arg; | |
253 arg = (char *)mem.malloc(64); | |
254 strcpy(arg, "-lldc-runtime"); | |
255 global.params.linkswitches->push(arg); | |
256 arg = (char *)mem.malloc(64); | |
257 strcpy(arg, "-ltango-cc-tango"); | |
258 global.params.linkswitches->push(arg); | |
259 arg = (char *)mem.malloc(64); | |
260 strcpy(arg, "-ltango-gc-basic"); | |
261 global.params.linkswitches->push(arg); | |
262 // pass the runtime again to resolve issues | |
263 // with linking order | |
264 arg = (char *)mem.malloc(64); | |
265 strcpy(arg, "-lldc-runtime"); | |
266 global.params.linkswitches->push(arg); | |
267 } | |
268 | |
269 if (global.params.run) | |
270 quiet = 1; | |
271 | |
272 if (global.params.useUnitTests) | |
273 global.params.useAssert = 1; | |
274 | |
275 // LDC output determination | |
276 | |
277 // if we don't link, autodetect target from extension | |
278 if(!global.params.link && global.params.objname) { | |
279 ext = FileName::ext(global.params.objname); | |
280 bool autofound = false; | |
281 if (!ext) { | |
282 // keep things as they are | |
283 } else if (strcmp(ext, global.ll_ext) == 0) { | |
284 global.params.output_ll = OUTPUTFLAGset; | |
285 autofound = true; | |
286 } else if (strcmp(ext, global.bc_ext) == 0) { | |
287 global.params.output_bc = OUTPUTFLAGset; | |
288 autofound = true; | |
289 } else if (strcmp(ext, global.s_ext) == 0) { | |
290 global.params.output_s = OUTPUTFLAGset; | |
291 autofound = true; | |
292 } else if (strcmp(ext, global.obj_ext) == 0) { | |
293 global.params.output_o = OUTPUTFLAGset; | |
294 autofound = true; | |
295 } else { | |
296 // append dot, so forceExt won't change existing name even if it contains dots | |
297 size_t len = strlen(global.params.objname); | |
298 size_t extlen = strlen("."); | |
299 char* s = (char *)mem.malloc(len + 1 + extlen + 1); | |
300 memcpy(s, global.params.objname, len); | |
301 s[len] = '.'; | |
302 s[len+1+extlen] = 0; | |
303 global.params.objname = s; | |
304 | |
305 } | |
306 if(autofound && global.params.output_o == OUTPUTFLAGdefault) | |
307 global.params.output_o = OUTPUTFLAGno; | |
308 } | |
309 | |
310 // only link if possible | |
311 if (!global.params.obj || !global.params.output_o) | |
312 global.params.link = 0; | |
313 | |
314 if (global.params.link) | |
315 { | |
316 global.params.exefile = global.params.objname; | |
317 if (files.dim > 1) | |
318 global.params.objname = NULL; | |
319 } | |
320 else if (global.params.run) | |
321 { | |
322 error("flags conflict with -run"); | |
323 fatal(); | |
324 } | |
325 else | |
326 { | |
327 if (global.params.objname && files.dim > 1) | |
328 { | |
329 error("multiple source files, but only one .obj name"); | |
330 fatal(); | |
331 } | |
332 } | |
333 | |
334 // create a proper target | |
335 llvm::Module mod("dummy"); | |
336 | |
337 // did the user override the target triple? | |
338 if (mTargetTriple.empty()) | |
339 { | |
340 if (mArch != 0) | |
341 { | |
342 error("you must specify a target triple as well with -mtriple when using the -march option"); | |
343 fatal(); | |
344 } | |
345 global.params.targetTriple = DEFAULT_TARGET_TRIPLE; | |
346 } | |
347 else | |
348 { | |
349 global.params.targetTriple = mTargetTriple.c_str(); | |
350 } | |
351 | |
352 mod.setTargetTriple(global.params.targetTriple); | |
353 | |
354 // Allocate target machine. First, check whether the user has | |
355 // explicitly specified an architecture to compile for. | |
356 if (mArch == 0) | |
357 { | |
358 std::string Err; | |
359 mArch = llvm::TargetMachineRegistry::getClosestStaticTargetForModule(mod, Err); | |
360 if (mArch == 0) | |
361 { | |
362 error("failed to auto-select target '%s', please use the -march option"); | |
363 fatal(); | |
364 } | |
365 } | |
366 | |
367 // Package up features to be passed to target/subtarget | |
368 std::string FeaturesStr; | |
369 if (mCPU.size() || mAttrs.size()) | |
370 { | |
371 llvm::SubtargetFeatures Features; | |
372 Features.setCPU(mCPU); | |
373 for (unsigned i = 0; i != mAttrs.size(); ++i) | |
374 Features.AddFeature(mAttrs[i]); | |
375 FeaturesStr = Features.getString(); | |
376 } | |
377 | |
378 std::auto_ptr<llvm::TargetMachine> target(mArch->CtorFn(mod, FeaturesStr)); | |
379 assert(target.get() && "Could not allocate target machine!"); | |
380 gTargetMachine = target.get(); | |
381 gTargetData = gTargetMachine->getTargetData(); | |
382 | |
383 // get final data layout | |
384 std::string datalayout = gTargetData->getStringRepresentation(); | |
385 global.params.dataLayout = datalayout.c_str(); | |
386 | |
387 global.params.llvmArch = mArch->Name; | |
388 | |
389 if (strcmp(global.params.llvmArch,"x86")==0) { | |
390 VersionCondition::addPredefinedGlobalIdent("X86"); | |
391 global.params.isLE = true; | |
392 global.params.is64bit = false; | |
393 global.params.cpu = ARCHx86; | |
394 if (global.params.useInlineAsm) { | |
395 VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86"); | |
396 } | |
397 } | |
398 else if (strcmp(global.params.llvmArch,"x86-64")==0) { | |
399 VersionCondition::addPredefinedGlobalIdent("X86_64"); | |
400 global.params.isLE = true; | |
401 global.params.is64bit = true; | |
402 global.params.cpu = ARCHx86_64; | |
403 if (global.params.useInlineAsm) { | |
404 VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86_64"); | |
405 } | |
406 } | |
407 else if (strcmp(global.params.llvmArch,"ppc32")==0) { | |
408 VersionCondition::addPredefinedGlobalIdent("PPC"); | |
409 global.params.isLE = false; | |
410 global.params.is64bit = false; | |
411 global.params.cpu = ARCHppc; | |
412 } | |
413 else if (strcmp(global.params.llvmArch,"ppc64")==0) { | |
414 VersionCondition::addPredefinedGlobalIdent("PPC64"); | |
415 global.params.isLE = false; | |
416 global.params.is64bit = true; | |
417 global.params.cpu = ARCHppc_64; | |
418 } | |
419 else if (strcmp(global.params.llvmArch,"arm")==0) { | |
420 VersionCondition::addPredefinedGlobalIdent("ARM"); | |
421 global.params.isLE = true; | |
422 global.params.is64bit = false; | |
423 global.params.cpu = ARCHarm; | |
424 } | |
425 else if (strcmp(global.params.llvmArch,"thumb")==0) { | |
426 VersionCondition::addPredefinedGlobalIdent("Thumb"); | |
427 global.params.isLE = true; | |
428 global.params.is64bit = false; | |
429 global.params.cpu = ARCHthumb; | |
430 } | |
431 else { | |
432 error("invalid cpu architecture specified: %s", global.params.llvmArch); | |
433 fatal(); | |
434 } | |
435 | |
436 // endianness | |
437 if (global.params.isLE) { | |
438 VersionCondition::addPredefinedGlobalIdent("LittleEndian"); | |
439 } | |
440 else { | |
441 VersionCondition::addPredefinedGlobalIdent("BigEndian"); | |
442 } | |
443 | |
444 // a generic 64bit version | |
445 // why isn't this in D to begin with ? | |
446 if (global.params.is64bit) { | |
447 VersionCondition::addPredefinedGlobalIdent("LLVM64"); | |
448 } | |
449 | |
450 // parse the OS out of the target triple | |
451 // see http://gcc.gnu.org/install/specific.html for details | |
452 // also llvm's different SubTargets have useful information | |
453 std::string triple = global.params.targetTriple; | |
454 size_t npos = std::string::npos; | |
455 | |
456 // windows | |
457 // FIXME: win64 | |
458 if (triple.find("windows") != npos || triple.find("win32") != npos || triple.find("mingw") != npos) | |
459 { | |
460 global.params.os = OSWindows; | |
461 VersionCondition::addPredefinedGlobalIdent("Windows"); | |
462 VersionCondition::addPredefinedGlobalIdent("Win32"); | |
463 VersionCondition::addPredefinedGlobalIdent("mingw32"); | |
464 } | |
465 // FIXME: cygwin | |
466 else if (triple.find("cygwin") != npos) | |
467 { | |
468 error("CygWin is not yet supported"); | |
469 fatal(); | |
470 } | |
471 // linux | |
472 else if (triple.find("linux") != npos) | |
473 { | |
474 global.params.os = OSLinux; | |
475 VersionCondition::addPredefinedGlobalIdent("linux"); | |
476 VersionCondition::addPredefinedGlobalIdent("Posix"); | |
477 } | |
478 // darwin | |
479 else if (triple.find("-darwin") != npos) | |
480 { | |
481 global.params.os = OSMacOSX; | |
482 VersionCondition::addPredefinedGlobalIdent("OSX"); | |
483 VersionCondition::addPredefinedGlobalIdent("darwin"); | |
484 VersionCondition::addPredefinedGlobalIdent("Posix"); | |
485 } | |
486 // freebsd | |
487 else if (triple.find("-freebsd") != npos) | |
488 { | |
489 global.params.os = OSFreeBSD; | |
490 VersionCondition::addPredefinedGlobalIdent("freebsd"); | |
491 VersionCondition::addPredefinedGlobalIdent("Posix"); | |
492 } | |
493 // solaris | |
494 else if (triple.find("-solaris") != npos) | |
495 { | |
496 global.params.os = OSSolaris; | |
497 VersionCondition::addPredefinedGlobalIdent("solaris"); | |
498 VersionCondition::addPredefinedGlobalIdent("Posix"); | |
499 } | |
500 // unsupported | |
501 else | |
502 { | |
503 error("target triple '%s' is not supported", global.params.targetTriple); | |
504 fatal(); | |
505 } | |
506 | |
507 // added in 1.039 | |
508 if (global.params.doDocComments) | |
509 VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); | |
510 | |
511 // Initialization | |
512 Type::init(); | |
513 Id::initialize(); | |
514 Module::init(); | |
515 initPrecedence(); | |
516 | |
517 backend_init(); | |
518 | |
519 //printf("%d source files\n",files.dim); | |
520 | |
521 // Build import search path | |
522 if (global.params.imppath) | |
523 { | |
524 for (int i = 0; i < global.params.imppath->dim; i++) | |
525 { | |
526 char *path = (char *)global.params.imppath->data[i]; | |
527 Array *a = FileName::splitPath(path); | |
528 | |
529 if (a) | |
530 { | |
531 if (!global.path) | |
532 global.path = new Array(); | |
533 global.path->append(a); | |
534 } | |
535 } | |
536 } | |
537 | |
538 // Build string import search path | |
539 if (global.params.fileImppath) | |
540 { | |
541 for (int i = 0; i < global.params.fileImppath->dim; i++) | |
542 { | |
543 char *path = (char *)global.params.fileImppath->data[i]; | |
544 Array *a = FileName::splitPath(path); | |
545 | |
546 if (a) | |
547 { | |
548 if (!global.filePath) | |
549 global.filePath = new Array(); | |
550 global.filePath->append(a); | |
551 } | |
552 } | |
553 } | |
554 | |
555 // Create Modules | |
556 Array modules; | |
557 modules.reserve(files.dim); | |
558 for (int i = 0; i < files.dim; i++) | |
559 { Identifier *id; | |
560 char *ext; | |
561 char *name; | |
562 | |
563 p = (char *) files.data[i]; | |
564 | |
565 p = FileName::name(p); // strip path | |
566 ext = FileName::ext(p); | |
567 if (ext) | |
568 { | |
569 #if POSIX | |
570 if (strcmp(ext, global.obj_ext) == 0 || | |
571 strcmp(ext, global.bc_ext) == 0) | |
572 #else | |
573 if (stricmp(ext, global.obj_ext) == 0 || | |
574 stricmp(ext, global.bc_ext) == 0) | |
575 #endif | |
576 { | |
577 global.params.objfiles->push(files.data[i]); | |
578 continue; | |
579 } | |
580 | |
581 #if POSIX | |
582 if (strcmp(ext, "a") == 0) | |
583 #elif __MINGW32__ | |
584 if (stricmp(ext, "a") == 0) | |
585 #else | |
586 if (stricmp(ext, "lib") == 0) | |
587 #endif | |
588 { | |
589 global.params.libfiles->push(files.data[i]); | |
590 continue; | |
591 } | |
592 | |
593 if (strcmp(ext, global.ddoc_ext) == 0) | |
594 { | |
595 global.params.ddocfiles->push(files.data[i]); | |
596 continue; | |
597 } | |
598 | |
599 #if !POSIX | |
600 if (stricmp(ext, "res") == 0) | |
601 { | |
602 global.params.resfile = (char *)files.data[i]; | |
603 continue; | |
604 } | |
605 | |
606 if (stricmp(ext, "def") == 0) | |
607 { | |
608 global.params.deffile = (char *)files.data[i]; | |
609 continue; | |
610 } | |
611 | |
612 if (stricmp(ext, "exe") == 0) | |
613 { | |
614 global.params.exefile = (char *)files.data[i]; | |
615 continue; | |
616 } | |
617 #endif | |
618 | |
619 if (stricmp(ext, global.mars_ext) == 0 || | |
620 stricmp(ext, global.hdr_ext) == 0 || | |
621 stricmp(ext, "htm") == 0 || | |
622 stricmp(ext, "html") == 0 || | |
623 stricmp(ext, "xhtml") == 0) | |
624 { | |
625 ext--; // skip onto '.' | |
626 assert(*ext == '.'); | |
627 name = (char *)mem.malloc((ext - p) + 1); | |
628 memcpy(name, p, ext - p); | |
629 name[ext - p] = 0; // strip extension | |
630 | |
631 if (name[0] == 0 || | |
632 strcmp(name, "..") == 0 || | |
633 strcmp(name, ".") == 0) | |
634 { | |
635 Linvalid: | |
636 error("invalid file name '%s'", (char *)files.data[i]); | |
637 fatal(); | |
638 } | |
639 } | |
640 else | |
641 { error("unrecognized file extension %s\n", ext); | |
642 fatal(); | |
643 } | |
644 } | |
645 else | |
646 { name = p; | |
647 if (!*name) | |
648 goto Linvalid; | |
649 } | |
650 | |
651 id = new Identifier(name, 0); | |
652 m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration); | |
653 modules.push(m); | |
654 } | |
655 | |
656 // Read files, parse them | |
657 for (int i = 0; i < modules.dim; i++) | |
658 { | |
659 m = (Module *)modules.data[i]; | |
660 if (global.params.verbose) | |
661 printf("parse %s\n", m->toChars()); | |
662 if (!Module::rootModule) | |
663 Module::rootModule = m; | |
664 m->importedFrom = m; | |
665 m->read(0); | |
666 m->parse(); | |
667 m->buildTargetFiles(); | |
668 m->deleteObjFile(); | |
669 if (m->isDocFile) | |
670 { | |
671 m->gendocfile(); | |
672 | |
673 // Remove m from list of modules | |
674 modules.remove(i); | |
675 i--; | |
676 } | |
677 } | |
678 if (global.errors) | |
679 fatal(); | |
680 #ifdef _DH | |
681 if (global.params.doHdrGeneration) | |
682 { | |
683 /* Generate 'header' import files. | |
684 * Since 'header' import files must be independent of command | |
685 * line switches and what else is imported, they are generated | |
686 * before any semantic analysis. | |
687 */ | |
688 for (int i = 0; i < modules.dim; i++) | |
689 { | |
690 m = (Module *)modules.data[i]; | |
691 if (global.params.verbose) | |
692 printf("import %s\n", m->toChars()); | |
693 m->genhdrfile(); | |
694 } | |
695 } | |
696 if (global.errors) | |
697 fatal(); | |
698 #endif | |
699 | |
700 // Do semantic analysis | |
701 for (int i = 0; i < modules.dim; i++) | |
702 { | |
703 m = (Module *)modules.data[i]; | |
704 if (global.params.verbose) | |
705 printf("semantic %s\n", m->toChars()); | |
706 m->semantic(); | |
707 } | |
708 if (global.errors) | |
709 fatal(); | |
710 | |
711 // Do pass 2 semantic analysis | |
712 for (int i = 0; i < modules.dim; i++) | |
713 { | |
714 m = (Module *)modules.data[i]; | |
715 if (global.params.verbose) | |
716 printf("semantic2 %s\n", m->toChars()); | |
717 m->semantic2(); | |
718 } | |
719 if (global.errors) | |
720 fatal(); | |
721 | |
722 // Do pass 3 semantic analysis | |
723 for (int i = 0; i < modules.dim; i++) | |
724 { | |
725 m = (Module *)modules.data[i]; | |
726 if (global.params.verbose) | |
727 printf("semantic3 %s\n", m->toChars()); | |
728 m->semantic3(); | |
729 } | |
730 if (global.errors) | |
731 fatal(); | |
732 | |
733 #if !IN_LLVM | |
734 // Scan for functions to inline | |
735 if (global.params.useInline) | |
736 { | |
737 /* The problem with useArrayBounds and useAssert is that the | |
738 * module being linked to may not have generated them, so if | |
739 * we inline functions from those modules, the symbols for them will | |
740 * not be found at link time. | |
741 */ | |
742 if (!global.params.useArrayBounds && !global.params.useAssert) | |
743 { | |
744 #endif | |
745 // Do pass 3 semantic analysis on all imported modules, | |
746 // since otherwise functions in them cannot be inlined | |
747 for (int i = 0; i < Module::amodules.dim; i++) | |
748 { | |
749 m = (Module *)Module::amodules.data[i]; | |
750 if (global.params.verbose) | |
751 printf("semantic3 %s\n", m->toChars()); | |
752 m->semantic3(); | |
753 } | |
754 if (global.errors) | |
755 fatal(); | |
756 #if !IN_LLVM | |
757 } | |
758 | |
759 for (int i = 0; i < modules.dim; i++) | |
760 { | |
761 m = (Module *)modules.data[i]; | |
762 if (global.params.verbose) | |
763 printf("inline scan %s\n", m->toChars()); | |
764 m->inlineScan(); | |
765 } | |
766 } | |
767 #endif | |
768 if (global.errors) | |
769 fatal(); | |
770 | |
771 // Generate output files | |
772 for (int i = 0; i < modules.dim; i++) | |
773 { | |
774 m = (Module *)modules.data[i]; | |
775 if (global.params.verbose) | |
776 printf("code %s\n", m->toChars()); | |
777 if (global.params.obj) | |
778 { | |
779 m->genobjfile(0); | |
780 global.params.objfiles->push(m->objfile->name->str); | |
781 } | |
782 if (global.errors) | |
783 m->deleteObjFile(); | |
784 else | |
785 { | |
786 if (global.params.doDocComments) | |
787 m->gendocfile(); | |
788 } | |
789 } | |
790 | |
791 backend_term(); | |
792 if (global.errors) | |
793 fatal(); | |
794 | |
795 if (!global.params.objfiles->dim) | |
796 { | |
797 if (global.params.link) | |
798 error("no object files to link"); | |
799 } | |
800 else | |
801 { | |
802 if (global.params.link) | |
803 //status = runLINK(); | |
804 linkObjToExecutable(global.params.argv0); | |
805 | |
806 if (global.params.run) | |
807 { | |
808 if (!status) | |
809 { | |
810 status = runExectuable(); | |
811 | |
812 /* Delete .obj files and .exe file | |
813 */ | |
814 for (int i = 0; i < modules.dim; i++) | |
815 { | |
816 m = (Module *)modules.data[i]; | |
817 m->deleteObjFile(); | |
818 } | |
819 deleteExecutable(); | |
820 } | |
821 } | |
822 } | |
823 | |
824 return status; | |
825 } |