Mercurial > projects > ldc
comparison dmd/mars.c @ 988:2667e3a145be
- Fixed LLVM style CL args for D2.
- Moved main() into its own file gen/main.cpp
- Fixed basic cross compilation
- removed the option for setting OS
- added support for llc's mattr, mcpu and mtriple switches
- added basic ABI abstraction for return value rewrites, it's not perfect and will probably be completely rewritten once I get to handling parameter rewrites as well.
- x86-64 extern(C) abi for cfloat returns now match (llvm-)gcc.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Thu, 26 Feb 2009 14:11:49 +0100 |
parents | a8cb25d478c4 |
children | f0b6549055ab |
comparison
equal
deleted
inserted
replaced
987:73ff89728d85 | 988:2667e3a145be |
---|---|
34 #include "id.h" | 34 #include "id.h" |
35 #include "cond.h" | 35 #include "cond.h" |
36 #include "expression.h" | 36 #include "expression.h" |
37 #include "lexer.h" | 37 #include "lexer.h" |
38 | 38 |
39 #include "gen/logger.h" | |
40 #include "gen/linker.h" | |
41 #include "revisions.h" | 39 #include "revisions.h" |
42 | |
43 #include "gen/cl_options.h" | |
44 #include "gen/cl_helpers.h" | |
45 using namespace opts; | |
46 | |
47 | |
48 static cl::opt<bool> forceBE("forcebe", | |
49 cl::desc("Force big-endian"), | |
50 cl::Hidden, | |
51 cl::ZeroOrMore); | |
52 | |
53 static cl::opt<bool> noDefaultLib("nodefaultlib", | |
54 cl::desc("Don't add a default library for linking implicitly"), | |
55 cl::ZeroOrMore); | |
56 | |
57 static ArrayAdapter impPathsStore("I", global.params.imppath); | |
58 static cl::list<std::string, ArrayAdapter> importPaths("I", | |
59 cl::desc("Where to look for imports"), | |
60 cl::value_desc("path"), | |
61 cl::location(impPathsStore), | |
62 cl::Prefix); | |
63 | |
64 static ArrayAdapter defaultLibStore("defaultlib", global.params.defaultlibnames); | |
65 static cl::list<std::string, ArrayAdapter> defaultlibs("defaultlib", | |
66 cl::desc("Set default libraries for non-debug build"), | |
67 cl::value_desc("lib,..."), | |
68 cl::location(defaultLibStore), | |
69 cl::CommaSeparated); | |
70 | |
71 static ArrayAdapter debugLibStore("debuglib", global.params.debuglibnames); | |
72 static cl::list<std::string, ArrayAdapter> debuglibs("debuglib", | |
73 cl::desc("Set default libraries for debug build"), | |
74 cl::value_desc("lib,..."), | |
75 cl::location(debugLibStore), | |
76 cl::CommaSeparated); | |
77 | |
78 | |
79 void getenv_setargv(const char *envvar, int *pargc, char** *pargv); | |
80 | 40 |
81 Global global; | 41 Global global; |
82 | 42 |
83 Global::Global() | 43 Global::Global() |
84 { | 44 { |
184 { | 144 { |
185 #ifdef DEBUG | 145 #ifdef DEBUG |
186 *(char*)0=0; | 146 *(char*)0=0; |
187 #endif | 147 #endif |
188 } | 148 } |
189 | |
190 extern void backend_init(); | |
191 extern void backend_term(); | |
192 | |
193 void printVersion() { | |
194 printf("LLVM D Compiler %s\nbased on DMD %s and %s\n%s\n%s\n", | |
195 global.ldc_version, global.version, global.llvm_version, global.copyright, global.written); | |
196 printf("D Language Documentation: http://www.digitalmars.com/d/1.0/index.html\n" | |
197 "LDC Homepage: http://www.dsource.org/projects/ldc\n"); | |
198 } | |
199 | |
200 // Helper function to handle -d-debug=* and -d-version=* | |
201 static void processVersions(std::vector<std::string>& list, char* type, | |
202 void (*setLevel)(unsigned), void (*addIdent)(char*)) { | |
203 typedef std::vector<std::string>::iterator It; | |
204 | |
205 for(It I = list.begin(), E = list.end(); I != E; ++I) { | |
206 const char* value = I->c_str(); | |
207 if (isdigit(value[0])) { | |
208 errno = 0; | |
209 char* end; | |
210 long level = strtol(value, &end, 10); | |
211 if (*end || errno || level > INT_MAX) { | |
212 error("Invalid %s level: %s", type, I->c_str()); | |
213 } else { | |
214 setLevel((unsigned)level); | |
215 } | |
216 } else { | |
217 char* cstr = mem.strdup(value); | |
218 if (Lexer::isValidIdentifier(cstr)) { | |
219 addIdent(cstr); | |
220 continue; | |
221 } else { | |
222 error("Invalid %s identifier or level: '%s'", type, I->c_str()); | |
223 } | |
224 } | |
225 } | |
226 } | |
227 | |
228 // Helper function to handle -of, -od, etc. | |
229 static void initFromString(char*& dest, const cl::opt<std::string>& src) { | |
230 dest = 0; | |
231 if (src.getNumOccurrences() != 0) { | |
232 if (src.empty()) | |
233 error("Expected argument to '-%s'", src.ArgStr); | |
234 dest = mem.strdup(src.c_str()); | |
235 } | |
236 } | |
237 | |
238 int main(int argc, char *argv[]) | |
239 { | |
240 int i; | |
241 Array files; | |
242 char *p, *ext; | |
243 Module *m; | |
244 int status = EXIT_SUCCESS; | |
245 | |
246 // Set default values | |
247 #if _WIN32 | |
248 char buf[MAX_PATH]; | |
249 GetModuleFileName(NULL, buf, MAX_PATH); | |
250 global.params.argv0 = buf; | |
251 #else | |
252 global.params.argv0 = argv[0]; | |
253 #endif | |
254 global.params.useSwitchError = 1; | |
255 | |
256 global.params.linkswitches = new Array(); | |
257 global.params.libfiles = new Array(); | |
258 global.params.objfiles = new Array(); | |
259 global.params.ddocfiles = new Array(); | |
260 | |
261 global.params.is64bit = sizeof(void*) == 8 ? 1 : 0; | |
262 | |
263 uint16_t endiantest = 0xFF00; | |
264 uint8_t endianres = ((uint8_t*)&endiantest)[0]; | |
265 if (endianres == 0x00) | |
266 global.params.isLE = true; | |
267 else if (endianres == 0xFF) | |
268 global.params.isLE = false; | |
269 else { | |
270 error("Endian test is broken"); | |
271 fatal(); | |
272 } | |
273 | |
274 // Predefine version identifiers | |
275 #if IN_LLVM | |
276 VersionCondition::addPredefinedGlobalIdent("LLVM"); | |
277 VersionCondition::addPredefinedGlobalIdent("LDC"); | |
278 #endif | |
279 | |
280 // setup default target os to be build os | |
281 #if _WIN32 | |
282 global.params.os = OSWindows; | |
283 #elif linux | |
284 global.params.os = OSLinux; | |
285 #elif __APPLE__ | |
286 global.params.os = OSMacOSX; | |
287 #elif __FreeBSD__ | |
288 global.params.os = OSFreeBSD; | |
289 #elif defined (__SVR4) && defined (__sun) | |
290 global.params.os = OSSolaris; | |
291 #else | |
292 #error Unsupported OS | |
293 #endif /* linux */ | |
294 | |
295 assert(global.params.os != OSinvalid); | |
296 | |
297 //VersionCondition::addPredefinedGlobalIdent("D_Bits"); | |
298 VersionCondition::addPredefinedGlobalIdent("all"); | |
299 | |
300 //#if _WIN32 | |
301 // inifile(global.params.argv0, "ldc.ini"); | |
302 //#elif POSIX | |
303 inifile(global.params.argv0, "ldc.conf"); | |
304 //#else | |
305 //#error | |
306 //#endif | |
307 getenv_setargv("DFLAGS", &argc, &argv); | |
308 | |
309 #if 0 | |
310 for (i = 0; i < argc; i++) | |
311 { | |
312 printf("argv[%d] = '%s'\n", i, argv[i]); | |
313 } | |
314 #endif | |
315 | |
316 cl::SetVersionPrinter(&printVersion); | |
317 cl::ParseCommandLineOptions(argc, argv, "LLVM-based D Compiler\n"); | |
318 | |
319 global.params.optimize = (global.params.optimizeLevel >= 0); | |
320 | |
321 // Negated options | |
322 global.params.link = !compileOnly; | |
323 global.params.obj = !dontWriteObj; | |
324 global.params.useInlineAsm = !noAsm; | |
325 | |
326 // String options: std::string --> char* | |
327 initFromString(global.params.objname, objectFile); | |
328 initFromString(global.params.objdir, objectDir); | |
329 | |
330 initFromString(global.params.docdir, ddocDir); | |
331 initFromString(global.params.docname, ddocFile); | |
332 global.params.doDocComments |= | |
333 global.params.docdir || global.params.docname; | |
334 | |
335 #ifdef _DH | |
336 initFromString(global.params.hdrdir, hdrDir); | |
337 initFromString(global.params.hdrname, hdrFile); | |
338 global.params.doHdrGeneration |= | |
339 global.params.hdrdir || global.params.hdrname; | |
340 #endif | |
341 | |
342 processVersions(debugArgs, "debug", | |
343 DebugCondition::setGlobalLevel, | |
344 DebugCondition::addGlobalIdent); | |
345 processVersions(versions, "version", | |
346 VersionCondition::setGlobalLevel, | |
347 VersionCondition::addGlobalIdent); | |
348 | |
349 global.params.output_o = | |
350 opts::output_o == cl::BOU_UNSET | |
351 ? OUTPUTFLAGdefault | |
352 : opts::output_o == cl::BOU_TRUE | |
353 ? OUTPUTFLAGset | |
354 : OUTPUTFLAGno; | |
355 global.params.output_bc = opts::output_bc ? OUTPUTFLAGset : OUTPUTFLAGno; | |
356 global.params.output_ll = opts::output_ll ? OUTPUTFLAGset : OUTPUTFLAGno; | |
357 global.params.output_s = opts::output_s ? OUTPUTFLAGset : OUTPUTFLAGno; | |
358 | |
359 if (global.params.run || !runargs.empty()) { | |
360 // FIXME: how to properly detect the presence of a PositionalEatsArgs | |
361 // option without parameters? We want to emit an error in that case... | |
362 // You'd think getNumOccurrences would do it, but it just returns the | |
363 // number of parameters) | |
364 // NOTE: Hacked around it by detecting -run in getenv_setargv(), where | |
365 // we're looking for it anyway, and pre-setting the flag... | |
366 global.params.run = true; | |
367 if (!runargs.empty()) { | |
368 files.push(mem.strdup(runargs[0].c_str())); | |
369 } else { | |
370 global.params.run = false; | |
371 error("Expected at least one argument to '-run'\n"); | |
372 } | |
373 } | |
374 | |
375 if (mArch) | |
376 global.params.llvmArch = mArch->Name; | |
377 | |
378 files.reserve(fileList.size()); | |
379 typedef std::vector<std::string>::iterator It; | |
380 for(It I = fileList.begin(), E = fileList.end(); I != E; ++I) | |
381 if (!I->empty()) | |
382 files.push(mem.strdup(I->c_str())); | |
383 | |
384 if (global.errors) | |
385 { | |
386 fatal(); | |
387 } | |
388 if (files.dim == 0) | |
389 { | |
390 cl::PrintHelpMessage(); | |
391 return EXIT_FAILURE; | |
392 } | |
393 | |
394 Array* libs; | |
395 if (global.params.symdebug) | |
396 libs = global.params.debuglibnames; | |
397 else | |
398 libs = global.params.defaultlibnames; | |
399 | |
400 if (libs) | |
401 { | |
402 for (int i = 0; i < libs->dim; i++) | |
403 { | |
404 char *arg = (char *)mem.malloc(64); | |
405 strcpy(arg, "-l"); | |
406 strncat(arg, (char *)libs->data[i], 64); | |
407 global.params.linkswitches->push(arg); | |
408 } | |
409 } | |
410 else if (!noDefaultLib) | |
411 { | |
412 char *arg; | |
413 arg = (char *)mem.malloc(64); | |
414 strcpy(arg, "-lldc-runtime"); | |
415 global.params.linkswitches->push(arg); | |
416 arg = (char *)mem.malloc(64); | |
417 strcpy(arg, "-ltango-cc-tango"); | |
418 global.params.linkswitches->push(arg); | |
419 arg = (char *)mem.malloc(64); | |
420 strcpy(arg, "-ltango-gc-basic"); | |
421 global.params.linkswitches->push(arg); | |
422 // pass the runtime again to resolve issues | |
423 // with linking order | |
424 arg = (char *)mem.malloc(64); | |
425 strcpy(arg, "-lldc-runtime"); | |
426 global.params.linkswitches->push(arg); | |
427 } | |
428 | |
429 if (global.params.run) | |
430 quiet = 1; | |
431 | |
432 if (global.params.useUnitTests) | |
433 global.params.useAssert = 1; | |
434 | |
435 // LDC output determination | |
436 | |
437 // if we don't link, autodetect target from extension | |
438 if(!global.params.link && global.params.objname) { | |
439 ext = FileName::ext(global.params.objname); | |
440 bool autofound = false; | |
441 if (!ext) { | |
442 // keep things as they are | |
443 } else if (strcmp(ext, global.ll_ext) == 0) { | |
444 global.params.output_ll = OUTPUTFLAGset; | |
445 autofound = true; | |
446 } else if (strcmp(ext, global.bc_ext) == 0) { | |
447 global.params.output_bc = OUTPUTFLAGset; | |
448 autofound = true; | |
449 } else if (strcmp(ext, global.s_ext) == 0) { | |
450 global.params.output_s = OUTPUTFLAGset; | |
451 autofound = true; | |
452 } else if (strcmp(ext, global.obj_ext) == 0) { | |
453 global.params.output_o = OUTPUTFLAGset; | |
454 autofound = true; | |
455 } else { | |
456 // append dot, so forceExt won't change existing name even if it contains dots | |
457 size_t len = strlen(global.params.objname); | |
458 size_t extlen = strlen("."); | |
459 char* s = (char *)mem.malloc(len + 1 + extlen + 1); | |
460 memcpy(s, global.params.objname, len); | |
461 s[len] = '.'; | |
462 s[len+1+extlen] = 0; | |
463 global.params.objname = s; | |
464 | |
465 } | |
466 if(autofound && global.params.output_o == OUTPUTFLAGdefault) | |
467 global.params.output_o = OUTPUTFLAGno; | |
468 } | |
469 | |
470 // only link if possible | |
471 if (!global.params.obj || !global.params.output_o) | |
472 global.params.link = 0; | |
473 | |
474 if (global.params.link) | |
475 { | |
476 global.params.exefile = global.params.objname; | |
477 if (files.dim > 1) | |
478 global.params.objname = NULL; | |
479 } | |
480 else if (global.params.run) | |
481 { | |
482 error("flags conflict with -run"); | |
483 fatal(); | |
484 } | |
485 else | |
486 { | |
487 if (global.params.objname && files.dim > 1) | |
488 { | |
489 error("multiple source files, but only one .obj name"); | |
490 fatal(); | |
491 } | |
492 } | |
493 | |
494 bool allowForceEndianness = false; | |
495 | |
496 if (global.params.llvmArch == 0) { | |
497 #if defined(__x86_64__) || defined(_M_X64) | |
498 global.params.llvmArch = "x86-64"; | |
499 #elif defined(__i386__) || defined(_M_IX86) | |
500 global.params.llvmArch = "x86"; | |
501 #elif defined(__ppc__) || defined(_M_PPC) | |
502 if (global.params.is64bit) | |
503 global.params.llvmArch = "ppc64"; | |
504 else | |
505 global.params.llvmArch = "ppc32"; | |
506 #elif defined(__arm__) | |
507 global.params.llvmArch = "arm"; | |
508 #elif defined(__thumb__) | |
509 global.params.llvmArch = "thumb"; | |
510 #else | |
511 #error | |
512 #endif | |
513 } | |
514 | |
515 if (strcmp(global.params.llvmArch,"x86")==0) { | |
516 VersionCondition::addPredefinedGlobalIdent("X86"); | |
517 global.params.isLE = true; | |
518 global.params.is64bit = false; | |
519 global.params.cpu = ARCHx86; | |
520 if (global.params.useInlineAsm) { | |
521 VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86"); | |
522 } | |
523 } | |
524 else if (strcmp(global.params.llvmArch,"x86-64")==0) { | |
525 VersionCondition::addPredefinedGlobalIdent("X86_64"); | |
526 global.params.isLE = true; | |
527 global.params.is64bit = true; | |
528 global.params.cpu = ARCHx86_64; | |
529 if (global.params.useInlineAsm) { | |
530 VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86_64"); | |
531 } | |
532 } | |
533 else if (strcmp(global.params.llvmArch,"ppc32")==0) { | |
534 VersionCondition::addPredefinedGlobalIdent("PPC"); | |
535 global.params.isLE = false; | |
536 global.params.is64bit = false; | |
537 global.params.cpu = ARCHppc; | |
538 } | |
539 else if (strcmp(global.params.llvmArch,"ppc64")==0) { | |
540 VersionCondition::addPredefinedGlobalIdent("PPC64"); | |
541 global.params.isLE = false; | |
542 global.params.is64bit = true; | |
543 global.params.cpu = ARCHppc_64; | |
544 } | |
545 else if (strcmp(global.params.llvmArch,"arm")==0) { | |
546 VersionCondition::addPredefinedGlobalIdent("ARM"); | |
547 global.params.isLE = true; | |
548 global.params.is64bit = false; | |
549 global.params.cpu = ARCHarm; | |
550 } | |
551 else if (strcmp(global.params.llvmArch,"thumb")==0) { | |
552 VersionCondition::addPredefinedGlobalIdent("Thumb"); | |
553 global.params.isLE = true; | |
554 global.params.is64bit = false; | |
555 global.params.cpu = ARCHthumb; | |
556 } | |
557 else { | |
558 error("invalid cpu architecture specified: %s", global.params.llvmArch); | |
559 } | |
560 | |
561 assert(global.params.cpu != ARCHinvalid); | |
562 | |
563 if (allowForceEndianness && forceBE) { | |
564 VersionCondition::addPredefinedGlobalIdent("BigEndian"); | |
565 global.params.isLE = false; | |
566 } | |
567 else if (global.params.isLE) { | |
568 VersionCondition::addPredefinedGlobalIdent("LittleEndian"); | |
569 } | |
570 else { | |
571 VersionCondition::addPredefinedGlobalIdent("BigEndian"); | |
572 } | |
573 | |
574 if (global.params.is64bit) { | |
575 VersionCondition::addPredefinedGlobalIdent("LLVM64"); | |
576 } | |
577 | |
578 | |
579 // setup version idents and tt_os for chosen target os | |
580 switch(global.params.os) | |
581 { | |
582 case OSWindows: | |
583 // TODO Win64 stuff! | |
584 VersionCondition::addPredefinedGlobalIdent("Windows"); | |
585 VersionCondition::addPredefinedGlobalIdent("Win32"); | |
586 VersionCondition::addPredefinedGlobalIdent("mingw32"); | |
587 break; | |
588 | |
589 case OSLinux: | |
590 VersionCondition::addPredefinedGlobalIdent("linux"); | |
591 VersionCondition::addPredefinedGlobalIdent("Posix"); | |
592 break; | |
593 | |
594 case OSMacOSX: | |
595 VersionCondition::addPredefinedGlobalIdent("OSX"); | |
596 VersionCondition::addPredefinedGlobalIdent("darwin"); | |
597 VersionCondition::addPredefinedGlobalIdent("Posix"); | |
598 break; | |
599 | |
600 case OSFreeBSD: | |
601 VersionCondition::addPredefinedGlobalIdent("freebsd"); | |
602 VersionCondition::addPredefinedGlobalIdent("Posix"); | |
603 break; | |
604 | |
605 case OSSolaris: | |
606 VersionCondition::addPredefinedGlobalIdent("solaris"); | |
607 VersionCondition::addPredefinedGlobalIdent("Posix"); | |
608 break; | |
609 | |
610 default: | |
611 assert(false && "Target OS not supported"); | |
612 } | |
613 | |
614 if (!global.params.targetTriple) | |
615 global.params.targetTriple = DEFAULT_TARGET_TRIPLE; | |
616 | |
617 Logger::println("Target triple: %s", global.params.targetTriple); | |
618 | |
619 // build a minimal data layout so llvm can find the target | |
620 global.params.dataLayout = global.params.isLE | |
621 ? (char*)(global.params.is64bit ? "e-p:64:64" : "e-p:32:32") | |
622 : (char*)(global.params.is64bit ? "E-p:64:64" : "E-p:32:32"); | |
623 Logger::println("Layout: %s", global.params.dataLayout); | |
624 | |
625 // added in 1.039 | |
626 if (global.params.doDocComments) | |
627 VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); | |
628 | |
629 // Initialization | |
630 Type::init(); | |
631 Id::initialize(); | |
632 Module::init(); | |
633 initPrecedence(); | |
634 | |
635 backend_init(); | |
636 | |
637 //printf("%d source files\n",files.dim); | |
638 | |
639 // Build import search path | |
640 if (global.params.imppath) | |
641 { | |
642 for (i = 0; i < global.params.imppath->dim; i++) | |
643 { | |
644 char *path = (char *)global.params.imppath->data[i]; | |
645 Array *a = FileName::splitPath(path); | |
646 | |
647 if (a) | |
648 { | |
649 if (!global.path) | |
650 global.path = new Array(); | |
651 global.path->append(a); | |
652 } | |
653 } | |
654 } | |
655 | |
656 // Build string import search path | |
657 if (global.params.fileImppath) | |
658 { | |
659 for (i = 0; i < global.params.fileImppath->dim; i++) | |
660 { | |
661 char *path = (char *)global.params.fileImppath->data[i]; | |
662 Array *a = FileName::splitPath(path); | |
663 | |
664 if (a) | |
665 { | |
666 if (!global.filePath) | |
667 global.filePath = new Array(); | |
668 global.filePath->append(a); | |
669 } | |
670 } | |
671 } | |
672 | |
673 // Create Modules | |
674 Array modules; | |
675 modules.reserve(files.dim); | |
676 for (i = 0; i < files.dim; i++) | |
677 { Identifier *id; | |
678 char *ext; | |
679 char *name; | |
680 | |
681 p = (char *) files.data[i]; | |
682 | |
683 p = FileName::name(p); // strip path | |
684 ext = FileName::ext(p); | |
685 if (ext) | |
686 { | |
687 #if POSIX | |
688 if (strcmp(ext, global.obj_ext) == 0 || | |
689 strcmp(ext, global.bc_ext) == 0) | |
690 #else | |
691 if (stricmp(ext, global.obj_ext) == 0 || | |
692 stricmp(ext, global.bc_ext) == 0) | |
693 #endif | |
694 { | |
695 global.params.objfiles->push(files.data[i]); | |
696 continue; | |
697 } | |
698 | |
699 #if POSIX | |
700 if (strcmp(ext, "a") == 0) | |
701 #elif __MINGW32__ | |
702 if (stricmp(ext, "a") == 0) | |
703 #else | |
704 if (stricmp(ext, "lib") == 0) | |
705 #endif | |
706 { | |
707 global.params.libfiles->push(files.data[i]); | |
708 continue; | |
709 } | |
710 | |
711 if (strcmp(ext, global.ddoc_ext) == 0) | |
712 { | |
713 global.params.ddocfiles->push(files.data[i]); | |
714 continue; | |
715 } | |
716 | |
717 #if !POSIX | |
718 if (stricmp(ext, "res") == 0) | |
719 { | |
720 global.params.resfile = (char *)files.data[i]; | |
721 continue; | |
722 } | |
723 | |
724 if (stricmp(ext, "def") == 0) | |
725 { | |
726 global.params.deffile = (char *)files.data[i]; | |
727 continue; | |
728 } | |
729 | |
730 if (stricmp(ext, "exe") == 0) | |
731 { | |
732 global.params.exefile = (char *)files.data[i]; | |
733 continue; | |
734 } | |
735 #endif | |
736 | |
737 if (stricmp(ext, global.mars_ext) == 0 || | |
738 stricmp(ext, global.hdr_ext) == 0 || | |
739 stricmp(ext, "htm") == 0 || | |
740 stricmp(ext, "html") == 0 || | |
741 stricmp(ext, "xhtml") == 0) | |
742 { | |
743 ext--; // skip onto '.' | |
744 assert(*ext == '.'); | |
745 name = (char *)mem.malloc((ext - p) + 1); | |
746 memcpy(name, p, ext - p); | |
747 name[ext - p] = 0; // strip extension | |
748 | |
749 if (name[0] == 0 || | |
750 strcmp(name, "..") == 0 || | |
751 strcmp(name, ".") == 0) | |
752 { | |
753 Linvalid: | |
754 error("invalid file name '%s'", (char *)files.data[i]); | |
755 fatal(); | |
756 } | |
757 } | |
758 else | |
759 { error("unrecognized file extension %s\n", ext); | |
760 fatal(); | |
761 } | |
762 } | |
763 else | |
764 { name = p; | |
765 if (!*name) | |
766 goto Linvalid; | |
767 } | |
768 | |
769 id = new Identifier(name, 0); | |
770 m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration); | |
771 modules.push(m); | |
772 } | |
773 | |
774 // Read files, parse them | |
775 for (i = 0; i < modules.dim; i++) | |
776 { | |
777 m = (Module *)modules.data[i]; | |
778 if (global.params.verbose) | |
779 printf("parse %s\n", m->toChars()); | |
780 if (!Module::rootModule) | |
781 Module::rootModule = m; | |
782 m->importedFrom = m; | |
783 m->read(0); | |
784 m->parse(); | |
785 m->buildTargetFiles(); | |
786 m->deleteObjFile(); | |
787 if (m->isDocFile) | |
788 { | |
789 m->gendocfile(); | |
790 | |
791 // Remove m from list of modules | |
792 modules.remove(i); | |
793 i--; | |
794 } | |
795 } | |
796 if (global.errors) | |
797 fatal(); | |
798 #ifdef _DH | |
799 if (global.params.doHdrGeneration) | |
800 { | |
801 /* Generate 'header' import files. | |
802 * Since 'header' import files must be independent of command | |
803 * line switches and what else is imported, they are generated | |
804 * before any semantic analysis. | |
805 */ | |
806 for (i = 0; i < modules.dim; i++) | |
807 { | |
808 m = (Module *)modules.data[i]; | |
809 if (global.params.verbose) | |
810 printf("import %s\n", m->toChars()); | |
811 m->genhdrfile(); | |
812 } | |
813 } | |
814 if (global.errors) | |
815 fatal(); | |
816 #endif | |
817 | |
818 // Do semantic analysis | |
819 for (i = 0; i < modules.dim; i++) | |
820 { | |
821 m = (Module *)modules.data[i]; | |
822 if (global.params.verbose) | |
823 printf("semantic %s\n", m->toChars()); | |
824 m->semantic(); | |
825 } | |
826 if (global.errors) | |
827 fatal(); | |
828 | |
829 // Do pass 2 semantic analysis | |
830 for (i = 0; i < modules.dim; i++) | |
831 { | |
832 m = (Module *)modules.data[i]; | |
833 if (global.params.verbose) | |
834 printf("semantic2 %s\n", m->toChars()); | |
835 m->semantic2(); | |
836 } | |
837 if (global.errors) | |
838 fatal(); | |
839 | |
840 // Do pass 3 semantic analysis | |
841 for (i = 0; i < modules.dim; i++) | |
842 { | |
843 m = (Module *)modules.data[i]; | |
844 if (global.params.verbose) | |
845 printf("semantic3 %s\n", m->toChars()); | |
846 m->semantic3(); | |
847 } | |
848 if (global.errors) | |
849 fatal(); | |
850 | |
851 #if !IN_LLVM | |
852 // Scan for functions to inline | |
853 if (global.params.useInline) | |
854 { | |
855 /* The problem with useArrayBounds and useAssert is that the | |
856 * module being linked to may not have generated them, so if | |
857 * we inline functions from those modules, the symbols for them will | |
858 * not be found at link time. | |
859 */ | |
860 if (!global.params.useArrayBounds && !global.params.useAssert) | |
861 { | |
862 #endif | |
863 // Do pass 3 semantic analysis on all imported modules, | |
864 // since otherwise functions in them cannot be inlined | |
865 for (i = 0; i < Module::amodules.dim; i++) | |
866 { | |
867 m = (Module *)Module::amodules.data[i]; | |
868 if (global.params.verbose) | |
869 printf("semantic3 %s\n", m->toChars()); | |
870 m->semantic3(); | |
871 } | |
872 if (global.errors) | |
873 fatal(); | |
874 #if !IN_LLVM | |
875 } | |
876 | |
877 for (i = 0; i < modules.dim; i++) | |
878 { | |
879 m = (Module *)modules.data[i]; | |
880 if (global.params.verbose) | |
881 printf("inline scan %s\n", m->toChars()); | |
882 m->inlineScan(); | |
883 } | |
884 } | |
885 #endif | |
886 if (global.errors) | |
887 fatal(); | |
888 | |
889 // Generate output files | |
890 for (i = 0; i < modules.dim; i++) | |
891 { | |
892 m = (Module *)modules.data[i]; | |
893 if (global.params.verbose) | |
894 printf("code %s\n", m->toChars()); | |
895 if (global.params.obj) | |
896 { | |
897 m->genobjfile(0); | |
898 global.params.objfiles->push(m->objfile->name->str); | |
899 } | |
900 if (global.errors) | |
901 m->deleteObjFile(); | |
902 else | |
903 { | |
904 if (global.params.doDocComments) | |
905 m->gendocfile(); | |
906 } | |
907 } | |
908 | |
909 backend_term(); | |
910 if (global.errors) | |
911 fatal(); | |
912 | |
913 if (!global.params.objfiles->dim) | |
914 { | |
915 if (global.params.link) | |
916 error("no object files to link"); | |
917 } | |
918 else | |
919 { | |
920 if (global.params.link) | |
921 //status = runLINK(); | |
922 linkObjToExecutable(global.params.argv0); | |
923 | |
924 if (global.params.run) | |
925 { | |
926 if (!status) | |
927 { | |
928 status = runExectuable(); | |
929 | |
930 /* Delete .obj files and .exe file | |
931 */ | |
932 for (i = 0; i < modules.dim; i++) | |
933 { | |
934 m = (Module *)modules.data[i]; | |
935 m->deleteObjFile(); | |
936 } | |
937 deleteExecutable(); | |
938 } | |
939 } | |
940 } | |
941 | |
942 return status; | |
943 } | |
944 | |
945 | |
946 | 149 |
947 /*********************************** | 150 /*********************************** |
948 * Parse and append contents of environment variable envvar | 151 * Parse and append contents of environment variable envvar |
949 * to argc and argv[]. | 152 * to argc and argv[]. |
950 * The string is separated into arguments, processing \ and ". | 153 * The string is separated into arguments, processing \ and ". |