comparison dmd2/mars.c @ 758:f04dde6e882c

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