comparison dmd2/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 0749c0757a43
children 123812e02bc8
comparison
equal deleted inserted replaced
987:73ff89728d85 988:2667e3a145be
1 // Compiler implementation of the D programming language 1 // Compiler implementation of the D programming language
2 // Copyright (c) 1999-2008 by Digital Mars 2 // Copyright (c) 1999-2009 by Digital Mars
3 // All Rights Reserved 3 // All Rights Reserved
4 // written by Walter Bright 4 // written by Walter Bright
5 // http://www.digitalmars.com 5 // http://www.digitalmars.com
6 // License for redistribution is by either the Artistic License 6 // License for redistribution is by either the Artistic License
7 // in artistic.txt, or the GNU General Public License in gnu.txt. 7 // in artistic.txt, or the GNU General Public License in gnu.txt.
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
42 #include "revisions.h" 39 #include "revisions.h"
43
44 void getenv_setargv(const char *envvar, int *pargc, char** *pargv);
45 40
46 Global global; 41 Global global;
47 42
48 Global::Global() 43 Global::Global()
49 { 44 {
60 obj_ext = "o"; 55 obj_ext = "o";
61 #if _WIN32 56 #if _WIN32
62 obj_ext_alt = "obj"; 57 obj_ext_alt = "obj";
63 #endif 58 #endif
64 59
65 copyright = "Copyright (c) 1999-2008 by Digital Mars and Tomas Lindquist Olsen"; 60 copyright = "Copyright (c) 1999-2009 by Digital Mars and Tomas Lindquist Olsen";
66 written = "written by Walter Bright and Tomas Lindquist Olsen"; 61 written = "written by Walter Bright and Tomas Lindquist Olsen";
67 version = "v2.021"; 62 version = "v2.021";
68 ldc_version = "0.1"; 63 ldc_version = LDC_REV;
64 llvm_version = LLVM_REV;
69 global.structalign = 8; 65 global.structalign = 8;
70 66
71 memset(&params, 0, sizeof(Param)); 67 // This should only be used as a global, so the other fields are
68 // automatically initialized to zero when the program is loaded.
69 // In particular, DO NOT zero-initialize .params here (like DMD
70 // does) because command-line options initialize some of those
71 // fields to non-zero defaults, and do so from constructors that
72 // may run before this one.
72 } 73 }
73 74
74 char *Loc::toChars() const 75 char *Loc::toChars() const
75 { 76 {
76 OutBuffer buf; 77 OutBuffer buf;
77 char *p;
78 78
79 if (filename) 79 if (filename)
80 { 80 {
81 buf.printf("%s", filename); 81 buf.printf("%s", filename);
82 } 82 }
83 83
84 if (linnum) 84 if (linnum)
85 buf.printf("(%d)", linnum); 85 buf.printf("(%d)", linnum);
86 buf.writeByte(0); 86 buf.writeByte(0);
87 return (char *)buf.extractData(); 87 return (char *)buf.extractData();
88 } 88 }
89 89
90 Loc::Loc(Module *mod, unsigned linnum) 90 Loc::Loc(Module *mod, unsigned linnum)
107 107
108 void verror(Loc loc, const char *format, va_list ap) 108 void verror(Loc loc, const char *format, va_list ap)
109 { 109 {
110 if (!global.gag) 110 if (!global.gag)
111 { 111 {
112 char *p = loc.toChars(); 112 char *p = loc.toChars();
113 113
114 if (*p) 114 if (*p)
115 fprintf(stdmsg, "%s: ", p); 115 fprintf(stdmsg, "%s: ", p);
116 mem.free(p); 116 mem.free(p);
117 117
118 fprintf(stdmsg, "Error: "); 118 fprintf(stdmsg, "Error: ");
119 vfprintf(stdmsg, format, ap); 119 vfprintf(stdmsg, format, ap);
120 fprintf(stdmsg, "\n"); 120 fprintf(stdmsg, "\n");
121 fflush(stdmsg); 121 fflush(stdmsg);
122 } 122 }
123 global.errors++; 123 global.errors++;
124 } 124 }
125 125
126 /*************************************** 126 /***************************************
144 { 144 {
145 #ifdef DEBUG 145 #ifdef DEBUG
146 *(char*)0=0; 146 *(char*)0=0;
147 #endif 147 #endif
148 } 148 }
149
150 extern void backend_init();
151 extern void backend_term();
152
153 void usage()
154 {
155 printf("LLVM D Compiler %s\nbased on DMD %s and %s\n%s\n%s\n",
156 global.ldc_version, global.version, global.llvm_version, global.copyright, global.written);
157 printf("\
158 D Language Documentation: http://www.digitalmars.com/d/2.0/index.html\n\
159 LDC Homepage: http://www.dsource.org/projects/ldc\n\
160 Usage:\n\
161 ldc files.d ... { -switch }\n\
162 \n\
163 files.d D source files\n%s\
164 -o- do not write object file\n\
165 -od<objdir> write object files to directory <objdir>\n\
166 -op do not strip paths from source file\n\
167 -oq write object files with fully qualified names\n\
168 -of<filename> name output file to <filename>\n\
169 if -c and extension of <filename> is known, it determines the output type\n\
170 \n\
171 -output-ll write LLVM IR\n\
172 -output-bc write LLVM bitcode\n\
173 -output-s write native assembly\n\
174 -output-o write native object (default if no -output switch passed)\n\
175 \n\
176 -c do not link\n\
177 -L<linkerflag> pass <linkerflag> to linker\n\
178 \n\
179 -w enable warnings\n\
180 \n\
181 -H generate 'header' file\n\
182 -Hd<hdrdir> write 'header' file to <hdrdir> directory\n\
183 -Hf<filename> write 'header' file to <filename>\n\
184 \n\
185 -D generate documentation\n\
186 -Dd<docdir> write documentation file to <docdir> directory\n\
187 -Df<filename> write documentation file to <filename>\n\
188 \n\
189 Codegen control:\n\
190 -m<arch> emit code specific to <arch> being one of:\n\
191 x86 x86-64 ppc32 ppc64 arm thumb\n\
192 -t<os> emit code specific to <os> being one of:\n\
193 Linux, Windows, MacOSX, FreeBSD, Solaris\n\
194 \n\
195 -g, -gc add symbolic debug info\n\
196 \n\
197 -O optimize, same as -O2\n\
198 -O<n> optimize at level <n> (0-5)\n\
199 -inline do function inlining\n\
200 \n\
201 -debug enables asserts, invariants, contracts, boundscheck\n\
202 and sets debug=1\n\
203 -release disables asserts, invariants, contracts, boundscheck\n\
204 \n\
205 -enable-<feature> and\n\
206 -disable-<feature> where <feature> is one of\n\
207 asserts assert statements (default: on)\n\
208 invariants class and struct invariants (default: on)\n\
209 contracts function contracts (default: on)\n\
210 boundscheck array bounds checking (default: on)\n\
211 -debug=level compile in debug stmts <= level (default: 0)\n\
212 -debug=ident compile in debug stmts identified by ident\n\
213 -version=level compile in version code >= level\n\
214 -version=ident compile in version code identified by ident\n\
215 \n\
216 -noasm do not allow use of inline asm\n\
217 -noruntime do not allow code that generates implicit runtime calls\n\
218 -noverify do not run the validation pass before writing bitcode\n\
219 -unittest compile in unit tests\n\
220 -d allow deprecated features\n\
221 \n\
222 -annotate annotate the bitcode with human readable source code\n\
223 -ignore ignore unsupported pragmas\n\
224 \n\
225 Path options:\n\
226 -I<path> where to look for imports\n\
227 -J<path> where to look for string imports\n\
228 -defaultlib=name set default library for non-debug build\n\
229 -debuglib=name set default library for debug build\n\
230 -nodefaultlib don't add a default library for linking implicitly\n\
231 \n\
232 Misc options:\n\
233 -v verbose\n\
234 -vv very verbose (does not include -v)\n\
235 -quiet suppress unnecessary messages\n\
236 -run srcfile args... run resulting program, passing args\n\
237 --help print help\n\
238 ",
239 #if WIN32
240 " @cmdfile read arguments from cmdfile\n"
241 #else
242 ""
243 #endif
244 );
245 }
246
247 int main(int argc, char *argv[])
248 {
249 int i;
250 Array files;
251 char *p, *ext;
252 Module *m;
253 int status = EXIT_SUCCESS;
254 int argcstart = argc;
255 bool very_verbose = false;
256
257 // Check for malformed input
258 if (argc < 1 || !argv)
259 {
260 Largs:
261 error("missing or null command line arguments");
262 fatal();
263 }
264 for (i = 0; i < argc; i++)
265 {
266 if (!argv[i])
267 goto Largs;
268 }
269
270 #if __DMC__ // DMC unique support for response files
271 if (response_expand(&argc,&argv)) // expand response files
272 error("can't open response file");
273 #endif
274
275 files.reserve(argc - 1);
276
277 // Set default values
278 #if _WIN32
279 char buf[MAX_PATH];
280 GetModuleFileName(NULL, buf, MAX_PATH);
281 global.params.argv0 = buf;
282 #else
283 global.params.argv0 = argv[0];
284 #endif
285 global.params.link = 1;
286 global.params.useAssert = 1;
287 global.params.useInvariants = 1;
288 global.params.useIn = 1;
289 global.params.useOut = 1;
290 global.params.useArrayBounds = 1;
291 global.params.useSwitchError = 1;
292 global.params.useInline = 0; // this one messes things up to a point where codegen breaks
293 global.params.llvmInline = 0; // use this one instead to know if inline passes should be run
294 global.params.obj = 1;
295 global.params.Dversion = 2;
296 global.params.quiet = 1;
297
298 global.params.output_o = OUTPUTFLAGdefault;
299
300 global.params.linkswitches = new Array();
301 global.params.libfiles = new Array();
302 global.params.objfiles = new Array();
303 global.params.ddocfiles = new Array();
304
305 global.params.is64bit = sizeof(void*) == 8 ? 1 : 0;
306
307 uint16_t endiantest = 0xFF00;
308 uint8_t endianres = ((uint8_t*)&endiantest)[0];
309 if (endianres == 0x00)
310 global.params.isLE = true;
311 else if (endianres == 0xFF)
312 global.params.isLE = false;
313 else {
314 error("Endian test is broken");
315 fatal();
316 }
317
318 global.params.llvmArch = 0;
319 global.params.forceBE = 0;
320 global.params.noruntime = 0;
321 global.params.novalidate = 0;
322 global.params.optimizeLevel = -1;
323 global.params.runtimeImppath = 0;
324 global.params.useInlineAsm = 1;
325
326 // Predefine version identifiers
327 #if IN_LLVM
328 VersionCondition::addPredefinedGlobalIdent("LLVM");
329 VersionCondition::addPredefinedGlobalIdent("LDC");
330 #endif
331
332 // D2
333 #if DMDV2
334 VersionCondition::addPredefinedGlobalIdent("D_Version2");
335 #endif
336
337 // setup default target os to be build os
338 #if _WIN32
339 global.params.os = OSWindows;
340 #elif linux
341 global.params.os = OSLinux;
342 #elif __APPLE__
343 global.params.os = OSMacOSX;
344 #elif __FreeBSD__
345 global.params.os = OSFreeBSD;
346 #elif defined (__SVR4) && defined (__sun)
347 global.params.os = OSSolaris;
348 #else
349 #error Unsupported OS
350 #endif /* linux */
351
352 assert(global.params.os != OSinvalid);
353
354 //VersionCondition::addPredefinedGlobalIdent("D_Bits");
355 VersionCondition::addPredefinedGlobalIdent("all");
356
357 //#if _WIN32
358
359 //#if DMDV2
360 // inifile(global.params.argv0, "ldc2.ini");
361 //#else
362 // inifile(global.params.argv0, "ldc.ini");
363 //#endif
364
365 //#elif POSIX
366
367 #if DMDV2
368 inifile(global.params.argv0, "ldc2.conf");
369 #else
370 inifile(global.params.argv0, "ldc.conf");
371 #endif
372
373 //#else
374 //#error
375 //#endif
376 getenv_setargv("DFLAGS", &argc, &argv);
377
378 #if 0
379 for (i = 0; i < argc; i++)
380 {
381 printf("argv[%d] = '%s'\n", i, argv[i]);
382 }
383 #endif
384
385 for (i = 1; i < argc; i++)
386 {
387 p = argv[i];
388 if (*p == '-')
389 {
390 if (strcmp(p + 1, "d") == 0)
391 global.params.useDeprecated = 1;
392 else if (strcmp(p + 1, "c") == 0)
393 global.params.link = 0;
394 else if (strcmp(p + 1, "fPIC") == 0)
395 global.params.pic = 1;
396 else if (strcmp(p + 1, "g") == 0)
397 global.params.symdebug = 1;
398 else if (strcmp(p + 1, "gc") == 0)
399 global.params.symdebug = 2;
400 else if (strcmp(p + 1, "v") == 0)
401 global.params.verbose = 1;
402 else if (strcmp(p + 1, "vv") == 0) {
403 Logger::enable();
404 very_verbose = true;
405 }
406 else if (strcmp(p + 1, "v1") == 0)
407 global.params.Dversion = 1;
408 else if (strcmp(p + 1, "w") == 0)
409 global.params.warnings = 1;
410 else if (p[1] == 'O')
411 {
412 global.params.optimize = 1;
413 global.params.optimizeLevel = 2;
414 if (p[2] != 0) {
415 int optlevel = atoi(p+2);
416 if (optlevel < 0 || optlevel > 5) {
417 error("Optimization level must be between 0 and 5. Using default (%d)",
418 global.params.optimizeLevel);
419 }
420 else {
421 global.params.optimizeLevel = optlevel;
422 }
423 }
424 }
425 else if (strcmp(p + 1, "forcebe") == 0)
426 global.params.forceBE = 1;
427 else if (strcmp(p + 1, "noruntime") == 0)
428 global.params.noruntime = 1;
429 else if (strcmp(p + 1, "noverify") == 0)
430 global.params.novalidate = 1;
431 else if (strcmp(p + 1, "annotate") == 0)
432 global.params.llvmAnnotate = 1;
433 else if (strncmp(p + 1, "enable-", 7) == 0 ||
434 strncmp(p + 1, "disable-", 8) == 0)
435 {
436 bool enable = (p[1] == 'e');
437 char* feature = p + 1 + (enable ? 7 : 8);
438 if (strcmp(feature, "asserts") == 0)
439 global.params.useAssert = enable;
440 else if (strcmp(feature, "boundscheck") == 0)
441 global.params.useArrayBounds = enable;
442 else if (strcmp(feature, "contracts") == 0)
443 {
444 global.params.useIn = enable;
445 global.params.useOut = enable;
446 }
447 else if (strcmp(feature, "invariants") == 0)
448 global.params.useInvariants = enable;
449 else
450 error("unrecognized feature '%s'", feature);
451 }
452 else if (strcmp(p + 1, "noasm") == 0)
453 global.params.useInlineAsm = 0;
454 else if (strcmp(p + 1, "nodefaultlib") == 0)
455 global.params.noDefaultLib = 1;
456 else if (p[1] == 'o')
457 {
458 switch (p[2])
459 {
460 case '-':
461 global.params.obj = 0;
462 break;
463
464 case 'd':
465 if (!p[3])
466 goto Lnoarg;
467 global.params.objdir = p + 3;
468 break;
469
470 case 'f':
471 if (!p[3])
472 goto Lnoarg;
473 global.params.objname = p + 3;
474 break;
475
476 case 'p':
477 if (p[3])
478 goto Lerror;
479 global.params.preservePaths = 1;
480 break;
481
482 case 'q':
483 if (p[3])
484 goto Lerror;
485 global.params.fqnNames = 1;
486 break;
487
488 case 'u':
489 if (strncmp(p+1, "output-", 7) != 0)
490 goto Lerror;
491
492 // remove default output
493 if (global.params.output_o == OUTPUTFLAGdefault)
494 global.params.output_o = OUTPUTFLAGno;
495
496 if (strcmp(p+8, global.ll_ext) == 0)
497 global.params.output_ll = OUTPUTFLAGset;
498 else if (strcmp(p+8, global.bc_ext) == 0)
499 global.params.output_bc = OUTPUTFLAGset;
500 else if (strcmp(p+8, global.s_ext) == 0)
501 global.params.output_s = OUTPUTFLAGset;
502 else if (strcmp(p+8, global.obj_ext) == 0)
503 global.params.output_o = OUTPUTFLAGset;
504 else
505 goto Lerror;
506
507 break;
508
509 case 0:
510 error("-o no longer supported, use -of or -od");
511 break;
512
513 default:
514 goto Lerror;
515 }
516 }
517 else if (p[1] == 'D')
518 { global.params.doDocComments = 1;
519 switch (p[2])
520 {
521 case 'd':
522 if (!p[3])
523 goto Lnoarg;
524 global.params.docdir = p + 3;
525 break;
526 case 'f':
527 if (!p[3])
528 goto Lnoarg;
529 global.params.docname = p + 3;
530 break;
531
532 case 0:
533 break;
534
535 default:
536 goto Lerror;
537 }
538 }
539 #ifdef _DH
540 else if (p[1] == 'H')
541 { global.params.doHdrGeneration = 1;
542 switch (p[2])
543 {
544 case 'd':
545 if (!p[3])
546 goto Lnoarg;
547 global.params.hdrdir = p + 3;
548 break;
549
550 case 'f':
551 if (!p[3])
552 goto Lnoarg;
553 global.params.hdrname = p + 3;
554 break;
555
556 case 0:
557 break;
558
559 default:
560 goto Lerror;
561 }
562 }
563 #endif
564 else if (strcmp(p + 1, "ignore") == 0)
565 global.params.ignoreUnsupportedPragmas = 1;
566 else if (strcmp(p + 1, "inline") == 0) {
567 // TODO
568 // the ast rewrites dmd does for inlining messes up the ast.
569 // someday maybe we can support it, for now llvm does an excellent job at inlining
570 global.params.useInline = 0; //1
571 global.params.llvmInline = 1;
572 }
573 else if (strcmp(p + 1, "quiet") == 0)
574 global.params.quiet = 1;
575 else if (strcmp(p + 1, "release") == 0)
576 {
577 global.params.useInvariants = 0;
578 global.params.useIn = 0;
579 global.params.useOut = 0;
580 global.params.useAssert = 0;
581 global.params.useArrayBounds = 0;
582 }
583 else if (strcmp(p + 1, "unittest") == 0)
584 global.params.useUnitTests = 1;
585 else if (p[1] == 'I')
586 {
587 if (!global.params.imppath)
588 global.params.imppath = new Array();
589 global.params.imppath->push(p + 2);
590 }
591 else if (p[1] == 'J')
592 {
593 if (!global.params.fileImppath)
594 global.params.fileImppath = new Array();
595 global.params.fileImppath->push(p + 2);
596 }
597 else if (memcmp(p + 1, "debug", 5) == 0 && p[6] != 'l')
598 {
599 // Parse:
600 // -debug
601 // -debug=number
602 // -debug=identifier
603 if (p[6] == '=')
604 {
605 if (isdigit(p[7]))
606 { long level;
607
608 errno = 0;
609 level = strtol(p + 7, &p, 10);
610 if (*p || errno || level > INT_MAX)
611 goto Lerror;
612 DebugCondition::setGlobalLevel((int)level);
613 }
614 else if (Lexer::isValidIdentifier(p + 7))
615 DebugCondition::addGlobalIdent(p + 7);
616 else
617 goto Lerror;
618 }
619 else if (p[6])
620 goto Lerror;
621 else
622 {
623 global.params.useInvariants = 1;
624 global.params.useIn = 1;
625 global.params.useOut = 1;
626 global.params.useAssert = 1;
627 global.params.useArrayBounds = 1;
628 global.params.debuglevel = 1;
629 }
630 }
631 else if (memcmp(p + 1, "version", 5) == 0)
632 {
633 // Parse:
634 // -version=number
635 // -version=identifier
636 if (p[8] == '=')
637 {
638 if (isdigit(p[9]))
639 { long level;
640
641 errno = 0;
642 level = strtol(p + 9, &p, 10);
643 if (*p || errno || level > INT_MAX)
644 goto Lerror;
645 VersionCondition::setGlobalLevel((int)level);
646 }
647 else if (Lexer::isValidIdentifier(p + 9))
648 VersionCondition::addGlobalIdent(p + 9);
649 else
650 goto Lerror;
651 }
652 else
653 goto Lerror;
654 }
655 else if (strcmp(p + 1, "-b") == 0)
656 global.params.debugb = 1;
657 else if (strcmp(p + 1, "-c") == 0)
658 global.params.debugc = 1;
659 else if (strcmp(p + 1, "-f") == 0)
660 global.params.debugf = 1;
661 else if (strcmp(p + 1, "-help") == 0)
662 { usage();
663 exit(EXIT_SUCCESS);
664 }
665 else if (strcmp(p + 1, "-r") == 0)
666 global.params.debugr = 1;
667 else if (strcmp(p + 1, "-x") == 0)
668 global.params.debugx = 1;
669 else if (strcmp(p + 1, "-y") == 0)
670 global.params.debugy = 1;
671 else if (p[1] == 'L')
672 {
673 global.params.linkswitches->push(p + 2);
674 }
675 else if (memcmp(p + 1, "defaultlib=", 11) == 0)
676 {
677 if(!global.params.defaultlibnames)
678 global.params.defaultlibnames = new Array();
679 global.params.defaultlibnames->push(p + 1 + 11);
680 }
681 else if (memcmp(p + 1, "debuglib=", 9) == 0)
682 {
683 if(!global.params.debuglibnames)
684 global.params.debuglibnames = new Array();
685 global.params.debuglibnames->push(p + 1 + 9);
686 }
687 else if (strcmp(p + 1, "run") == 0)
688 { global.params.run = 1;
689 global.params.runargs_length = ((i >= argcstart) ? argc : argcstart) - i - 1;
690 if (global.params.runargs_length)
691 {
692 files.push(argv[i + 1]);
693 global.params.runargs = &argv[i + 2];
694 i += global.params.runargs_length;
695 global.params.runargs_length--;
696 }
697 else
698 { global.params.run = 0;
699 goto Lnoarg;
700 }
701 }
702 else if (p[1] == 'm')
703 {
704 global.params.llvmArch = p+2;
705 }
706 else if (p[1] == 't')
707 {
708 if(strcmp(p + 2, "Linux") == 0)
709 global.params.os = OSLinux;
710 else if(strcmp(p + 2, "Windows") == 0)
711 global.params.os = OSWindows;
712 else if(strcmp(p + 2, "MacOSX") == 0)
713 global.params.os = OSMacOSX;
714 else if(strcmp(p + 2, "FreeBSD") == 0)
715 global.params.os = OSFreeBSD;
716 else if(strcmp(p + 2, "Solaris") == 0)
717 global.params.os = OSSolaris;
718 else
719 error("unrecognized target os '%s'", p + 2);
720 }
721 else
722 {
723 Lerror:
724 error("unrecognized switch '%s'", argv[i]);
725 continue;
726
727 Lnoarg:
728 error("argument expected for switch '%s'", argv[i]);
729 continue;
730 }
731 }
732 else
733 files.push(p);
734 }
735 if (global.errors)
736 {
737 fatal();
738 }
739 if (files.dim == 0)
740 { usage();
741 return EXIT_FAILURE;
742 }
743
744 Array* libs;
745 if (global.params.symdebug)
746 libs = global.params.debuglibnames;
747 else
748 libs = global.params.defaultlibnames;
749
750 if (libs)
751 {
752 for (int i = 0; i < libs->dim; i++)
753 {
754 char *arg = (char *)mem.malloc(64);
755 strcpy(arg, "-l");
756 strncat(arg, (char *)libs->data[i], 64);
757 global.params.linkswitches->push(arg);
758 }
759 }
760 else if (!global.params.noDefaultLib)
761 {
762 #if DMDV2
763 char *arg;
764 arg = (char *)mem.malloc(64);
765 strcpy(arg, "-ldruntime-ldc");
766 global.params.linkswitches->push(arg);
767 #else
768 char *arg;
769 arg = (char *)mem.malloc(64);
770 strcpy(arg, "-lldc-runtime");
771 global.params.linkswitches->push(arg);
772 arg = (char *)mem.malloc(64);
773 strcpy(arg, "-ltango-cc-tango");
774 global.params.linkswitches->push(arg);
775 arg = (char *)mem.malloc(64);
776 strcpy(arg, "-ltango-gc-basic");
777 global.params.linkswitches->push(arg);
778 // pass the runtime again to resolve issues
779 // with linking order
780 arg = (char *)mem.malloc(64);
781 strcpy(arg, "-lldc-runtime");
782 global.params.linkswitches->push(arg);
783 #endif
784 }
785
786 if (global.params.run)
787 global.params.quiet = 1;
788
789 if (global.params.useUnitTests)
790 global.params.useAssert = 1;
791
792 // LDC output determination
793
794 // if we don't link, autodetect target from extension
795 if(!global.params.link && global.params.objname) {
796 ext = FileName::ext(global.params.objname);
797 bool autofound = false;
798 if (!ext) {
799 // keep things as they are
800 } else if (strcmp(ext, global.ll_ext) == 0) {
801 global.params.output_ll = OUTPUTFLAGset;
802 autofound = true;
803 } else if (strcmp(ext, global.bc_ext) == 0) {
804 global.params.output_bc = OUTPUTFLAGset;
805 autofound = true;
806 } else if (strcmp(ext, global.s_ext) == 0) {
807 global.params.output_s = OUTPUTFLAGset;
808 autofound = true;
809 } else if (strcmp(ext, global.obj_ext) == 0) {
810 global.params.output_o = OUTPUTFLAGset;
811 autofound = true;
812 } else {
813 // append dot, so forceExt won't change existing name even if it contains dots
814 size_t len = strlen(global.params.objname);
815 size_t extlen = strlen(".");
816 char* s = (char *)mem.malloc(len + 1 + extlen + 1);
817 memcpy(s, global.params.objname, len);
818 s[len] = '.';
819 s[len+1+extlen] = 0;
820 global.params.objname = s;
821
822 }
823 if(autofound && global.params.output_o == OUTPUTFLAGdefault)
824 global.params.output_o = OUTPUTFLAGno;
825 }
826
827 // only link if possible
828 if (!global.params.obj || !global.params.output_o)
829 global.params.link = 0;
830
831 if (global.params.link)
832 {
833 global.params.exefile = global.params.objname;
834 if (files.dim > 1)
835 global.params.objname = NULL;
836 }
837 else if (global.params.run)
838 {
839 error("flags conflict with -run");
840 fatal();
841 }
842 else
843 {
844 if (global.params.objname && files.dim > 1)
845 {
846 error("multiple source files, but only one .obj name");
847 fatal();
848 }
849 }
850
851 bool allowForceEndianness = false;
852
853 if (global.params.llvmArch == 0) {
854 #if defined(__x86_64__) || defined(_M_X64)
855 global.params.llvmArch = "x86-64";
856 #elif defined(__i386__) || defined(_M_IX86)
857 global.params.llvmArch = "x86";
858 #elif defined(__ppc__) || defined(_M_PPC)
859 if (global.params.is64bit)
860 global.params.llvmArch = "ppc64";
861 else
862 global.params.llvmArch = "ppc32";
863 #elif defined(__arm__)
864 global.params.llvmArch = "arm";
865 #elif defined(__thumb__)
866 global.params.llvmArch = "thumb";
867 #else
868 #error
869 #endif
870 }
871
872 if (strcmp(global.params.llvmArch,"x86")==0) {
873 VersionCondition::addPredefinedGlobalIdent("X86");
874 global.params.isLE = true;
875 global.params.is64bit = false;
876 global.params.cpu = ARCHx86;
877 if (global.params.useInlineAsm) {
878 VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86");
879 }
880 }
881 else if (strcmp(global.params.llvmArch,"x86-64")==0) {
882 VersionCondition::addPredefinedGlobalIdent("X86_64");
883 global.params.isLE = true;
884 global.params.is64bit = true;
885 global.params.cpu = ARCHx86_64;
886 if (global.params.useInlineAsm) {
887 VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86_64");
888 }
889 }
890 else if (strcmp(global.params.llvmArch,"ppc32")==0) {
891 VersionCondition::addPredefinedGlobalIdent("PPC");
892 global.params.isLE = false;
893 global.params.is64bit = false;
894 global.params.cpu = ARCHppc;
895 }
896 else if (strcmp(global.params.llvmArch,"ppc64")==0) {
897 VersionCondition::addPredefinedGlobalIdent("PPC64");
898 global.params.isLE = false;
899 global.params.is64bit = true;
900 global.params.cpu = ARCHppc_64;
901 }
902 else if (strcmp(global.params.llvmArch,"arm")==0) {
903 VersionCondition::addPredefinedGlobalIdent("ARM");
904 global.params.isLE = true;
905 global.params.is64bit = false;
906 global.params.cpu = ARCHarm;
907 }
908 else if (strcmp(global.params.llvmArch,"thumb")==0) {
909 VersionCondition::addPredefinedGlobalIdent("Thumb");
910 global.params.isLE = true;
911 global.params.is64bit = false;
912 global.params.cpu = ARCHthumb;
913 }
914 else {
915 error("invalid cpu architecture specified: %s", global.params.llvmArch);
916 }
917
918 assert(global.params.cpu != ARCHinvalid);
919
920 if (allowForceEndianness && global.params.forceBE) {
921 VersionCondition::addPredefinedGlobalIdent("BigEndian");
922 global.params.isLE = false;
923 }
924 else if (global.params.isLE) {
925 VersionCondition::addPredefinedGlobalIdent("LittleEndian");
926 }
927 else {
928 VersionCondition::addPredefinedGlobalIdent("BigEndian");
929 }
930
931 if (global.params.is64bit) {
932 VersionCondition::addPredefinedGlobalIdent("LLVM64");
933 }
934
935
936 // setup version idents and tt_os for chosen target os
937 switch(global.params.os)
938 {
939 case OSWindows:
940 VersionCondition::addPredefinedGlobalIdent("Windows");
941 VersionCondition::addPredefinedGlobalIdent("Win32");
942 VersionCondition::addPredefinedGlobalIdent("mingw32");
943 break;
944
945 case OSLinux:
946 VersionCondition::addPredefinedGlobalIdent("linux");
947 VersionCondition::addPredefinedGlobalIdent("Posix");
948 break;
949
950 case OSMacOSX:
951 VersionCondition::addPredefinedGlobalIdent("darwin");
952 VersionCondition::addPredefinedGlobalIdent("Posix");
953 break;
954
955 case OSFreeBSD:
956 VersionCondition::addPredefinedGlobalIdent("freebsd");
957 VersionCondition::addPredefinedGlobalIdent("Posix");
958 break;
959
960 case OSSolaris:
961 VersionCondition::addPredefinedGlobalIdent("solaris");
962 VersionCondition::addPredefinedGlobalIdent("Posix");
963 break;
964
965 default:
966 assert(false && "Target OS not supported");
967 }
968
969 if (!global.params.targetTriple)
970 global.params.targetTriple = DEFAULT_TARGET_TRIPLE;
971
972 Logger::println("Target triple: %s", global.params.targetTriple);
973
974 // build a minimal data layout so llvm can find the target
975 global.params.dataLayout = global.params.isLE
976 ? (char*)(global.params.is64bit ? "e-p:64:64" : "e-p:32:32")
977 : (char*)(global.params.is64bit ? "E-p:64:64" : "E-p:32:32");
978 Logger::println("Layout: %s", global.params.dataLayout);
979
980 // Initialization
981 Type::init();
982 Id::initialize();
983 Module::init();
984 initPrecedence();
985
986 backend_init();
987
988 //printf("%d source files\n",files.dim);
989
990 // Build import search path
991 if (global.params.imppath)
992 {
993 for (i = 0; i < global.params.imppath->dim; i++)
994 {
995 char *path = (char *)global.params.imppath->data[i];
996 Array *a = FileName::splitPath(path);
997
998 if (a)
999 {
1000 if (!global.path)
1001 global.path = new Array();
1002 global.path->append(a);
1003 }
1004 }
1005 }
1006
1007 // Build string import search path
1008 if (global.params.fileImppath)
1009 {
1010 for (i = 0; i < global.params.fileImppath->dim; i++)
1011 {
1012 char *path = (char *)global.params.fileImppath->data[i];
1013 Array *a = FileName::splitPath(path);
1014
1015 if (a)
1016 {
1017 if (!global.filePath)
1018 global.filePath = new Array();
1019 global.filePath->append(a);
1020 }
1021 }
1022 }
1023
1024 // Create Modules
1025 Array modules;
1026 modules.reserve(files.dim);
1027 for (i = 0; i < files.dim; i++)
1028 { Identifier *id;
1029 char *ext;
1030 char *name;
1031
1032 p = (char *) files.data[i];
1033
1034 p = FileName::name(p); // strip path
1035 ext = FileName::ext(p);
1036 if (ext)
1037 {
1038 #if POSIX
1039 if (strcmp(ext, global.obj_ext) == 0 ||
1040 strcmp(ext, global.bc_ext) == 0)
1041 #else
1042 if (stricmp(ext, global.obj_ext) == 0 ||
1043 stricmp(ext, global.bc_ext) == 0)
1044 #endif
1045 {
1046 global.params.objfiles->push(files.data[i]);
1047 continue;
1048 }
1049
1050 #if POSIX
1051 if (strcmp(ext, "a") == 0)
1052 #elif __MINGW32__
1053 if (stricmp(ext, "a") == 0)
1054 #else
1055 if (stricmp(ext, "lib") == 0)
1056 #endif
1057 {
1058 global.params.libfiles->push(files.data[i]);
1059 continue;
1060 }
1061
1062 if (strcmp(ext, global.ddoc_ext) == 0)
1063 {
1064 global.params.ddocfiles->push(files.data[i]);
1065 continue;
1066 }
1067
1068 #if !POSIX
1069 if (stricmp(ext, "res") == 0)
1070 {
1071 global.params.resfile = (char *)files.data[i];
1072 continue;
1073 }
1074
1075 if (stricmp(ext, "def") == 0)
1076 {
1077 global.params.deffile = (char *)files.data[i];
1078 continue;
1079 }
1080
1081 if (stricmp(ext, "exe") == 0)
1082 {
1083 global.params.exefile = (char *)files.data[i];
1084 continue;
1085 }
1086 #endif
1087
1088 if (stricmp(ext, global.mars_ext) == 0 ||
1089 stricmp(ext, global.hdr_ext) == 0 ||
1090 stricmp(ext, "htm") == 0 ||
1091 stricmp(ext, "html") == 0 ||
1092 stricmp(ext, "xhtml") == 0)
1093 {
1094 ext--; // skip onto '.'
1095 assert(*ext == '.');
1096 name = (char *)mem.malloc((ext - p) + 1);
1097 memcpy(name, p, ext - p);
1098 name[ext - p] = 0; // strip extension
1099
1100 if (name[0] == 0 ||
1101 strcmp(name, "..") == 0 ||
1102 strcmp(name, ".") == 0)
1103 {
1104 Linvalid:
1105 error("invalid file name '%s'", (char *)files.data[i]);
1106 fatal();
1107 }
1108 }
1109 else
1110 { error("unrecognized file extension %s\n", ext);
1111 fatal();
1112 }
1113 }
1114 else
1115 { name = p;
1116 if (!*name)
1117 goto Linvalid;
1118 }
1119
1120 id = new Identifier(name, 0);
1121 m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration);
1122 modules.push(m);
1123 }
1124
1125 // Read files, parse them
1126 for (i = 0; i < modules.dim; i++)
1127 {
1128 m = (Module *)modules.data[i];
1129 if (global.params.verbose)
1130 printf("parse %s\n", m->toChars());
1131 if (!Module::rootModule)
1132 Module::rootModule = m;
1133 m->importedFrom = m;
1134 m->read(0);
1135 m->parse();
1136 m->buildTargetFiles();
1137 m->deleteObjFile();
1138 if (m->isDocFile)
1139 {
1140 m->gendocfile();
1141
1142 // Remove m from list of modules
1143 modules.remove(i);
1144 i--;
1145 }
1146 }
1147 if (global.errors)
1148 fatal();
1149 #ifdef _DH
1150 if (global.params.doHdrGeneration)
1151 {
1152 /* Generate 'header' import files.
1153 * Since 'header' import files must be independent of command
1154 * line switches and what else is imported, they are generated
1155 * before any semantic analysis.
1156 */
1157 for (i = 0; i < modules.dim; i++)
1158 {
1159 m = (Module *)modules.data[i];
1160 if (global.params.verbose)
1161 printf("import %s\n", m->toChars());
1162 m->genhdrfile();
1163 }
1164 }
1165 if (global.errors)
1166 fatal();
1167 #endif
1168
1169 // Do semantic analysis
1170 for (i = 0; i < modules.dim; i++)
1171 {
1172 m = (Module *)modules.data[i];
1173 if (global.params.verbose)
1174 printf("semantic %s\n", m->toChars());
1175 m->semantic();
1176 }
1177 if (global.errors)
1178 fatal();
1179
1180 // Do pass 2 semantic analysis
1181 for (i = 0; i < modules.dim; i++)
1182 {
1183 m = (Module *)modules.data[i];
1184 if (global.params.verbose)
1185 printf("semantic2 %s\n", m->toChars());
1186 m->semantic2();
1187 }
1188 if (global.errors)
1189 fatal();
1190
1191 // Do pass 3 semantic analysis
1192 for (i = 0; i < modules.dim; i++)
1193 {
1194 m = (Module *)modules.data[i];
1195 if (global.params.verbose)
1196 printf("semantic3 %s\n", m->toChars());
1197 m->semantic3();
1198 }
1199 if (global.errors)
1200 fatal();
1201
1202 #if !IN_LLVM
1203 // Scan for functions to inline
1204 if (global.params.useInline)
1205 {
1206 /* The problem with useArrayBounds and useAssert is that the
1207 * module being linked to may not have generated them, so if
1208 * we inline functions from those modules, the symbols for them will
1209 * not be found at link time.
1210 */
1211 if (!global.params.useArrayBounds && !global.params.useAssert)
1212 {
1213 #endif
1214 // Do pass 3 semantic analysis on all imported modules,
1215 // since otherwise functions in them cannot be inlined
1216 for (i = 0; i < Module::amodules.dim; i++)
1217 {
1218 m = (Module *)Module::amodules.data[i];
1219 if (global.params.verbose)
1220 printf("semantic3 %s\n", m->toChars());
1221 m->semantic3();
1222 }
1223 if (global.errors)
1224 fatal();
1225 #if !IN_LLVM
1226 }
1227
1228 for (i = 0; i < modules.dim; i++)
1229 {
1230 m = (Module *)modules.data[i];
1231 if (global.params.verbose)
1232 printf("inline scan %s\n", m->toChars());
1233 m->inlineScan();
1234 }
1235 }
1236 #endif
1237 if (global.errors)
1238 fatal();
1239
1240 // Generate output files
1241 for (i = 0; i < modules.dim; i++)
1242 {
1243 m = (Module *)modules.data[i];
1244 if (global.params.verbose)
1245 printf("code %s\n", m->toChars());
1246 if (global.params.obj)
1247 {
1248 m->genobjfile(0);
1249 global.params.objfiles->push(m->objfile->name->str);
1250 }
1251 if (global.errors)
1252 m->deleteObjFile();
1253 else
1254 {
1255 if (global.params.doDocComments)
1256 m->gendocfile();
1257 }
1258 }
1259
1260 backend_term();
1261 if (global.errors)
1262 fatal();
1263
1264 if (!global.params.objfiles->dim)
1265 {
1266 if (global.params.link)
1267 error("no object files to link");
1268 }
1269 else
1270 {
1271 if (global.params.link)
1272 //status = runLINK();
1273 linkObjToExecutable(global.params.argv0);
1274
1275 if (global.params.run)
1276 {
1277 if (!status)
1278 {
1279 status = runExectuable();
1280
1281 /* Delete .obj files and .exe file
1282 */
1283 for (i = 0; i < modules.dim; i++)
1284 {
1285 m = (Module *)modules.data[i];
1286 m->deleteObjFile();
1287 }
1288 deleteExecutable();
1289 }
1290 }
1291 }
1292
1293 return status;
1294 }
1295
1296
1297 149
1298 /*********************************** 150 /***********************************
1299 * Parse and append contents of environment variable envvar 151 * Parse and append contents of environment variable envvar
1300 * to argc and argv[]. 152 * to argc and argv[].
1301 * The string is separated into arguments, processing \ and ". 153 * The string is separated into arguments, processing \ and ".
1306 char *env; 158 char *env;
1307 char *p; 159 char *p;
1308 Array *argv; 160 Array *argv;
1309 int argc; 161 int argc;
1310 162
1311 int wildcard; // do wildcard expansion 163 int wildcard; // do wildcard expansion
1312 int instring; 164 int instring;
1313 int slash; 165 int slash;
1314 char c; 166 char c;
1315 int j; 167 int j;
1316 168
1317 env = getenv(envvar); 169 env = getenv(envvar);
1318 if (!env) 170 if (!env)
1319 return; 171 return;
1320 172
1321 env = mem.strdup(env); // create our own writable copy 173 env = mem.strdup(env); // create our own writable copy
1322 174
1323 argc = *pargc; 175 argc = *pargc;
1324 argv = new Array(); 176 argv = new Array();
1325 argv->setDim(argc); 177 argv->setDim(argc);
1326 178
1327 for (int i = 0; i < argc; i++) 179 int argc_left = 0;
1328 argv->data[i] = (void *)(*pargv)[i]; 180 for (int i = 0; i < argc; i++) {
1329 181 if (!strcmp((*pargv)[i], "-run") || !strcmp((*pargv)[i], "--run")) {
1330 j = 1; // leave argv[0] alone 182 // HACK: set flag to indicate we saw '-run' here
183 global.params.run = true;
184 // Don't eat -run yet so the program arguments don't get changed
185 argc_left = argc - i;
186 argc = i;
187 *pargv = &(*pargv)[i];
188 argv->setDim(i);
189 break;
190 } else {
191 argv->data[i] = (void *)(*pargv)[i];
192 }
193 }
194 // HACK to stop required values from command line being drawn from DFLAGS
195 argv->push((char*)"");
196 argc++;
197
198 j = 1; // leave argv[0] alone
1331 while (1) 199 while (1)
1332 { 200 {
1333 wildcard = 1; 201 wildcard = 1;
1334 switch (*env) 202 switch (*env)
1335 { 203 {
1336 case ' ': 204 case ' ':
1337 case '\t': 205 case '\t':
1338 env++; 206 env++;
1339 break; 207 break;
1340 208
1341 case 0: 209 case 0:
1342 goto Ldone; 210 goto Ldone;
1343 211
1344 case '"': 212 case '"':
1345 wildcard = 0; 213 wildcard = 0;
1346 default: 214 default:
1347 argv->push(env); // append 215 argv->push(env); // append
1348 //argv->insert(j, env); // insert at position j 216 //argv->insert(j, env); // insert at position j
1349 j++; 217 j++;
1350 argc++; 218 argc++;
1351 p = env; 219 p = env;
1352 slash = 0; 220 slash = 0;
1353 instring = 0; 221 instring = 0;
1354 c = 0; 222 c = 0;
1355 223
1356 while (1) 224 while (1)
1357 { 225 {
1358 c = *env++; 226 c = *env++;
1359 switch (c) 227 switch (c)
1360 { 228 {
1361 case '"': 229 case '"':
1362 p -= (slash >> 1); 230 p -= (slash >> 1);
1363 if (slash & 1) 231 if (slash & 1)
1364 { p--; 232 { p--;
1365 goto Laddc; 233 goto Laddc;
1366 } 234 }
1367 instring ^= 1; 235 instring ^= 1;
1368 slash = 0; 236 slash = 0;
1369 continue; 237 continue;
1370 238
1371 case ' ': 239 case ' ':
1372 case '\t': 240 case '\t':
1373 if (instring) 241 if (instring)
1374 goto Laddc; 242 goto Laddc;
1375 *p = 0; 243 *p = 0;
1376 //if (wildcard) 244 //if (wildcard)
1377 //wildcardexpand(); // not implemented 245 //wildcardexpand(); // not implemented
1378 break; 246 break;
1379 247
1380 case '\\': 248 case '\\':
1381 slash++; 249 slash++;
1382 *p++ = c; 250 *p++ = c;
1383 continue; 251 continue;
1384 252
1385 case 0: 253 case 0:
1386 *p = 0; 254 *p = 0;
1387 //if (wildcard) 255 //if (wildcard)
1388 //wildcardexpand(); // not implemented 256 //wildcardexpand(); // not implemented
1389 goto Ldone; 257 goto Ldone;
1390 258
1391 default: 259 default:
1392 Laddc: 260 Laddc:
1393 slash = 0; 261 slash = 0;
1394 *p++ = c; 262 *p++ = c;
1395 continue; 263 continue;
1396 } 264 }
1397 break; 265 break;
1398 } 266 }
1399 } 267 }
1400 } 268 }
1401 269
1402 Ldone: 270 Ldone:
271 assert(argc == argv->dim);
272 argv->reserve(argc_left);
273 for (int i = 0; i < argc_left; i++)
274 argv->data[argc++] = (void *)(*pargv)[i];
275
1403 *pargc = argc; 276 *pargc = argc;
1404 *pargv = (char **)argv->data; 277 *pargv = (char **)argv->data;
1405 } 278 }