root/trunk/src/mars.c

Revision 811, 41.0 kB (checked in by walter, 1 year ago)

better fix for the recursive template constraint issue

  • Property svn:eol-style set to native
Line 
1 // Compiler implementation of the D programming language
2 // Copyright (c) 1999-2010 by Digital Mars
3 // All Rights Reserved
4 // written by Walter Bright
5 // http://www.digitalmars.com
6 // http://www.dsource.org/projects/dmd/browser/trunk/src/mars.c
7 // License for redistribution is by either the Artistic License
8 // in artistic.txt, or the GNU General Public License in gnu.txt.
9 // See the included readme.txt for details.
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <ctype.h>
14 #include <assert.h>
15 #include <limits.h>
16
17 #if linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4
18 #include <errno.h>
19 #endif
20
21 #include "rmem.h"
22 #include "root.h"
23 #include "async.h"
24
25 #include "mars.h"
26 #include "module.h"
27 #include "mtype.h"
28 #include "id.h"
29 #include "cond.h"
30 #include "expression.h"
31 #include "lexer.h"
32 #include "lib.h"
33 #include "json.h"
34
35 #if WINDOWS_SEH
36 #include <windows.h>
37 long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep);
38 #endif
39
40
41 int response_expand(int *pargc, char ***pargv);
42 void browse(const char *url);
43 void getenv_setargv(const char *envvar, int *pargc, char** *pargv);
44
45 void obj_start(char *srcfile);
46 void obj_end(Library *library, File *objfile);
47
48 Global global;
49
50 Global::Global()
51 {
52     mars_ext = "d";
53     sym_ext  = "d";
54     hdr_ext  = "di";
55     doc_ext  = "html";
56     ddoc_ext = "ddoc";
57     json_ext = "json";
58     map_ext  = "map";
59
60 #if TARGET_WINDOS
61     obj_ext  = "obj";
62 #elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
63     obj_ext  = "o";
64 #elif TARGET_NET
65 #else
66 #error "fix this"
67 #endif
68
69 #if TARGET_WINDOS
70     lib_ext  = "lib";
71 #elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
72     lib_ext  = "a";
73 #elif TARGET_NET
74 #else
75 #error "fix this"
76 #endif
77
78 #if TARGET_WINDOS
79     dll_ext  = "dll";
80 #elif TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS
81     dll_ext  = "so";
82 #elif TARGET_OSX
83     dll_ext = "dylib";
84 #else
85 #error "fix this"
86 #endif
87
88     copyright = "Copyright (c) 1999-2010 by Digital Mars";
89     written = "written by Walter Bright"
90 #if TARGET_NET
91     "\nMSIL back-end (alpha release) by Cristian L. Vlasceanu and associates.";
92 #endif
93     ;
94     version = "v2.052";
95     global.structalign = 8;
96
97     memset(&params, 0, sizeof(Param));
98 }
99
100 char *Loc::toChars()
101 {
102     OutBuffer buf;
103     char *p;
104
105     if (filename)
106     {
107         buf.printf("%s", filename);
108     }
109
110     if (linnum)
111         buf.printf("(%d)", linnum);
112     buf.writeByte(0);
113     return (char *)buf.extractData();
114 }
115
116 Loc::Loc(Module *mod, unsigned linnum)
117 {
118     this->linnum = linnum;
119     this->filename = mod ? mod->srcfile->toChars() : NULL;
120 }
121
122 bool Loc::equals(const Loc& loc)
123 {
124     return linnum == loc.linnum && FileName::equals(filename, loc.filename);
125 }
126
127 /**************************************
128  * Print error message and exit.
129  */
130
131 void error(Loc loc, const char *format, ...)
132 {
133     va_list ap;
134     va_start(ap, format);
135     verror(loc, format, ap);
136     va_end( ap );
137 }
138
139 void error(const char *filename, unsigned linnum, const char *format, ...)
140 {   Loc loc;
141     loc.filename = (char *)filename;
142     loc.linnum = linnum;
143     va_list ap;
144     va_start(ap, format);
145     verror(loc, format, ap);
146     va_end( ap );
147 }
148
149 void warning(Loc loc, const char *format, ...)
150 {
151     va_list ap;
152     va_start(ap, format);
153     vwarning(loc, format, ap);
154     va_end( ap );
155 }
156
157 void verror(Loc loc, const char *format, va_list ap)
158 {
159     if (!global.gag)
160     {
161         char *p = loc.toChars();
162
163         if (*p)
164             fprintf(stdmsg, "%s: ", p);
165         mem.free(p);
166
167         fprintf(stdmsg, "Error: ");
168 #if _MSC_VER
169         // MS doesn't recognize %zu format
170         OutBuffer tmp;
171         tmp.vprintf(format, ap);
172         fprintf(stdmsg, "%s", tmp.toChars());
173 #else
174         vfprintf(stdmsg, format, ap);
175 #endif
176         fprintf(stdmsg, "\n");
177         fflush(stdmsg);
178 //halt();
179     }
180     global.errors++;
181 }
182
183 void vwarning(Loc loc, const char *format, va_list ap)
184 {
185     if (global.params.warnings && !global.gag)
186     {
187         char *p = loc.toChars();
188
189         if (*p)
190             fprintf(stdmsg, "%s: ", p);
191         mem.free(p);
192
193         fprintf(stdmsg, "Warning: ");
194 #if _MSC_VER
195         // MS doesn't recognize %zu format
196         OutBuffer tmp;
197         tmp.vprintf(format, ap);
198         fprintf(stdmsg, "%s", tmp.toChars());
199 #else
200         vfprintf(stdmsg, format, ap);
201 #endif
202         fprintf(stdmsg, "\n");
203         fflush(stdmsg);
204 //halt();
205         if (global.params.warnings == 1)
206             global.warnings++;  // warnings don't count if gagged
207     }
208 }
209
210 /***************************************
211  * Call this after printing out fatal error messages to clean up and exit
212  * the compiler.
213  */
214
215 void fatal()
216 {
217 #if 0
218     halt();
219 #endif
220     exit(EXIT_FAILURE);
221 }
222
223 /**************************************
224  * Try to stop forgetting to remove the breakpoints from
225  * release builds.
226  */
227 void halt()
228 {
229 #ifdef DEBUG
230     *(char*)0=0;
231 #endif
232 }
233
234 extern void backend_init();
235 extern void backend_term();
236
237 void usage()
238 {
239 #if TARGET_LINUX
240     const char fpic[] ="\
241   -fPIC          generate position independent code\n\
242 ";
243 #else
244     const char fpic[] = "";
245 #endif
246     printf("Digital Mars D Compiler %s\n%s %s\n",
247         global.version, global.copyright, global.written);
248     printf("\
249 Documentation: http://www.digitalmars.com/d/2.0/index.html\n\
250 Usage:\n\
251   dmd files.d ... { -switch }\n\
252 \n\
253   files.d        D source files\n\
254   @cmdfile       read arguments from cmdfile\n\
255   -c             do not link\n\
256   -cov           do code coverage analysis\n\
257   -D             generate documentation\n\
258   -Dddocdir      write documentation file to docdir directory\n\
259   -Dffilename    write documentation file to filename\n\
260   -d             allow deprecated features\n\
261   -debug         compile in debug code\n\
262   -debug=level   compile in debug code <= level\n\
263   -debug=ident   compile in debug code identified by ident\n\
264   -debuglib=name    set symbolic debug library to name\n\
265   -defaultlib=name  set default library to name\n\
266   -deps=filename write module dependencies to filename\n%s"
267 #if TARGET_OSX
268 "  -dylib         generate dylib\n"
269 #endif
270 "  -g             add symbolic debug info\n\
271   -gc            add symbolic debug info, pretend to be C\n\
272   -H             generate 'header' file\n\
273   -Hddirectory   write 'header' file to directory\n\
274   -Hffilename    write 'header' file to filename\n\
275   --help         print help\n\
276   -Ipath         where to look for imports\n\
277   -ignore        ignore unsupported pragmas\n\
278   -inline        do function inlining\n\
279   -Jpath         where to look for string imports\n\
280   -Llinkerflag   pass linkerflag to link\n\
281   -lib           generate library rather than object files\n\
282   -man           open web browser on manual page\n\
283   -map           generate linker .map file\n\
284   -noboundscheck turns off array bounds checking for all functions\n\
285   -nofloat       do not emit reference to floating point\n\
286   -O             optimize\n\
287   -o-            do not write object file\n\
288   -odobjdir      write object & library files to directory objdir\n\
289   -offilename    name output file to filename\n\
290   -op            do not strip paths from source file\n\
291   -profile       profile runtime performance of generated code\n\
292   -quiet         suppress unnecessary messages\n\
293   -release       compile release version\n\
294   -run srcfile args...   run resulting program, passing args\n\
295   -unittest      compile in unit tests\n\
296   -v             verbose\n\
297   -version=level compile in version code >= level\n\
298   -version=ident compile in version code identified by ident\n\
299   -vtls          list all variables going into thread local storage\n\
300   -w             enable warnings\n\
301   -wi            enable informational warnings\n\
302   -X             generate JSON file\n\
303   -Xffilename    write JSON file to filename\n\
304 ", fpic);
305 }
306
307 extern signed char tyalignsize[];
308
309 int main(int argc, char *argv[])
310 {
311     int i;
312     Array files;
313     Array libmodules;
314     char *p;
315     Module *m;
316     int status = EXIT_SUCCESS;
317     int argcstart = argc;
318     int setdebuglib = 0;
319     char noboundscheck = 0;
320     const char *inifilename = NULL;
321
322     unittests();
323
324     // Check for malformed input
325     if (argc < 1 || !argv)
326     {
327       Largs:
328         error("missing or null command line arguments");
329         fatal();
330     }
331     for (i = 0; i < argc; i++)
332     {
333         if (!argv[i])
334             goto Largs;
335     }
336
337     if (response_expand(&argc,&argv))   // expand response files
338         error("can't open response file");
339
340     files.reserve(argc - 1);
341
342     // Set default values
343     global.params.argv0 = argv[0];
344     global.params.link = 1;
345     global.params.useAssert = 1;
346     global.params.useInvariants = 1;
347     global.params.useIn = 1;
348     global.params.useOut = 1;
349     global.params.useArrayBounds = 2;   // default to all functions
350     global.params.useSwitchError = 1;
351     global.params.useInline = 0;
352     global.params.obj = 1;
353     global.params.Dversion = 2;
354     global.params.quiet = 1;
355
356     global.params.linkswitches = new Array();
357     global.params.libfiles = new Array();
358     global.params.objfiles = new Array();
359     global.params.ddocfiles = new Array();
360
361 #if TARGET_WINDOS
362     global.params.defaultlibname = "phobos";
363 #elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
364     global.params.defaultlibname = "phobos2";
365 #elif TARGET_NET
366 #else
367 #error "fix this"
368 #endif
369
370     // Predefine version identifiers
371     VersionCondition::addPredefinedGlobalIdent("DigitalMars");
372
373 #if TARGET_WINDOS
374     VersionCondition::addPredefinedGlobalIdent("Windows");
375     global.params.isWindows = 1;
376 #if TARGET_NET
377     // TARGET_NET macro is NOT mutually-exclusive with TARGET_WINDOS
378     VersionCondition::addPredefinedGlobalIdent("D_NET");
379 #endif
380 #elif TARGET_LINUX
381     VersionCondition::addPredefinedGlobalIdent("Posix");
382     VersionCondition::addPredefinedGlobalIdent("linux");
383     global.params.isLinux = 1;
384 #elif TARGET_OSX
385     VersionCondition::addPredefinedGlobalIdent("Posix");
386     VersionCondition::addPredefinedGlobalIdent("OSX");
387     global.params.isOSX = 1;
388
389     // For legacy compatibility
390     VersionCondition::addPredefinedGlobalIdent("darwin");
391 #elif TARGET_FREEBSD
392     VersionCondition::addPredefinedGlobalIdent("Posix");
393     VersionCondition::addPredefinedGlobalIdent("FreeBSD");
394     global.params.isFreeBSD = 1;
395 #elif TARGET_SOLARIS
396     VersionCondition::addPredefinedGlobalIdent("Posix");
397     VersionCondition::addPredefinedGlobalIdent("Solaris");
398     global.params.isSolaris = 1;
399 #else
400 #error "fix this"
401 #endif
402
403     VersionCondition::addPredefinedGlobalIdent("LittleEndian");
404     //VersionCondition::addPredefinedGlobalIdent("D_Bits");
405 #if DMDV2
406     VersionCondition::addPredefinedGlobalIdent("D_Version2");
407 #endif
408     VersionCondition::addPredefinedGlobalIdent("all");
409
410 #if _WIN32
411     inifilename = inifile(argv[0], "sc.ini");
412 #elif linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4
413     inifilename = inifile(argv[0], "dmd.conf");
414 #else
415 #error "fix this"
416 #endif
417     getenv_setargv("DFLAGS", &argc, &argv);
418
419 #if 0
420     for (i = 0; i < argc; i++)
421     {
422         printf("argv[%d] = '%s'\n", i, argv[i]);
423     }
424 #endif
425
426     for (i = 1; i < argc; i++)
427     {
428         p = argv[i];
429         if (*p == '-')
430         {
431             if (strcmp(p + 1, "d") == 0)
432                 global.params.useDeprecated = 1;
433             else if (strcmp(p + 1, "c") == 0)
434                 global.params.link = 0;
435             else if (strcmp(p + 1, "cov") == 0)
436                 global.params.cov = 1;
437 #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
438             else if (strcmp(p + 1, "fPIC") == 0)
439                 global.params.pic = 1;
440 #endif
441 #if TARGET_OSX
442             else if (strcmp(p + 1, "dylib") == 0)
443                 global.params.dll = 1;
444 #endif
445             else if (strcmp(p + 1, "map") == 0)
446                 global.params.map = 1;
447             else if (strcmp(p + 1, "multiobj") == 0)
448                 global.params.multiobj = 1;
449             else if (strcmp(p + 1, "g") == 0)
450                 global.params.symdebug = 1;
451             else if (strcmp(p + 1, "gc") == 0)
452                 global.params.symdebug = 2;
453             else if (strcmp(p + 1, "gt") == 0)
454             {   error("use -profile instead of -gt\n");
455                 global.params.trace = 1;
456             }
457             else if (strcmp(p + 1, "m32") == 0)
458                 global.params.isX86_64 = 0;
459             else if (strcmp(p + 1, "m64") == 0)
460                 global.params.isX86_64 = 1;
461             else if (strcmp(p + 1, "profile") == 0)
462                 global.params.trace = 1;
463             else if (strcmp(p + 1, "v") == 0)
464                 global.params.verbose = 1;
465 #if DMDV2
466             else if (strcmp(p + 1, "vtls") == 0)
467                 global.params.vtls = 1;
468 #endif
469             else if (strcmp(p + 1, "v1") == 0)
470             {
471 #if DMDV1
472                 global.params.Dversion = 1;
473 #else
474                 error("use DMD 1.0 series compilers for -v1 switch");
475                 break;
476 #endif
477             }
478             else if (strcmp(p + 1, "w") == 0)
479                 global.params.warnings = 1;
480             else if (strcmp(p + 1, "wi") == 0)
481                 global.params.warnings = 2;
482             else if (strcmp(p + 1, "O") == 0)
483                 global.params.optimize = 1;
484             else if (p[1] == 'o')
485             {
486                 switch (p[2])
487                 {
488                     case '-':
489                         global.params.obj = 0;
490                         break;
491
492                     case 'd':
493                         if (!p[3])
494                             goto Lnoarg;
495                         global.params.objdir = p + 3;
496                         break;
497
498                     case 'f':
499                         if (!p[3])
500                             goto Lnoarg;
501                         global.params.objname = p + 3;
502                         break;
503
504                     case 'p':
505                         if (p[3])
506                             goto Lerror;
507                         global.params.preservePaths = 1;
508                         break;
509
510                     case 0:
511                         error("-o no longer supported, use -of or -od");
512                         break;
513
514                     default:
515                         goto Lerror;
516                 }
517             }
518             else if (p[1] == 'D')
519             {   global.params.doDocComments = 1;
520                 switch (p[2])
521                 {
522                     case 'd':
523                         if (!p[3])
524                             goto Lnoarg;
525                         global.params.docdir = p + 3;
526                         break;
527                     case 'f':
528                         if (!p[3])
529                             goto Lnoarg;
530                         global.params.docname = p + 3;
531                         break;
532
533                     case 0:
534                         break;
535
536                     default:
537                         goto Lerror;
538                 }
539             }
540 #ifdef _DH
541             else if (p[1] == 'H')
542             {   global.params.doHdrGeneration = 1;
543                 switch (p[2])
544                 {
545                     case 'd':
546                         if (!p[3])
547                             goto Lnoarg;
548                         global.params.hdrdir = p + 3;
549                         break;
550
551                     case 'f':
552                         if (!p[3])
553                             goto Lnoarg;
554                         global.params.hdrname = p + 3;
555                         break;
556
557                     case 0:
558                         break;
559
560                     default:
561                         goto Lerror;
562                 }
563             }
564 #endif
565             else if (p[1] == 'X')
566             {   global.params.doXGeneration = 1;
567                 switch (p[2])
568                 {
569                     case 'f':
570                         if (!p[3])
571                             goto Lnoarg;
572                         global.params.xfilename = p + 3;
573                         break;
574
575                     case 0:
576                         break;
577
578                     default:
579                         goto Lerror;
580                 }
581             }
582             else if (strcmp(p + 1, "ignore") == 0)
583                 global.params.ignoreUnsupportedPragmas = 1;
584             else if (strcmp(p + 1, "inline") == 0)
585                 global.params.useInline = 1;
586             else if (strcmp(p + 1, "lib") == 0)
587                 global.params.lib = 1;
588             else if (strcmp(p + 1, "nofloat") == 0)
589                 global.params.nofloat = 1;
590             else if (strcmp(p + 1, "quiet") == 0)
591                 global.params.quiet = 1;
592             else if (strcmp(p + 1, "release") == 0)
593                 global.params.release = 1;
594 #if DMDV2
595             else if (strcmp(p + 1, "noboundscheck") == 0)
596                 noboundscheck = 1;
597 #endif
598             else if (strcmp(p + 1, "unittest") == 0)
599                 global.params.useUnitTests = 1;
600             else if (p[1] == 'I')
601             {
602                 if (!global.params.imppath)
603                     global.params.imppath = new Array();
604                 global.params.imppath->push(p + 2);
605             }
606             else if (p[1] == 'J')
607             {
608                 if (!global.params.fileImppath)
609                     global.params.fileImppath = new Array();
610                 global.params.fileImppath->push(p + 2);
611             }
612             else if (memcmp(p + 1, "debug", 5) == 0 && p[6] != 'l')
613             {
614                 // Parse:
615                 //      -debug
616                 //      -debug=number
617                 //      -debug=identifier
618                 if (p[6] == '=')
619                 {
620                     if (isdigit(p[7]))
621                     {   long level;
622
623                         errno = 0;
624                         level = strtol(p + 7, &p, 10);
625                         if (*p || errno || level > INT_MAX)
626                             goto Lerror;
627                         DebugCondition::setGlobalLevel((int)level);
628                     }
629                     else if (Lexer::isValidIdentifier(p + 7))
630                         DebugCondition::addGlobalIdent(p + 7);
631                     else
632                         goto Lerror;
633                 }
634                 else if (p[6])
635                     goto Lerror;
636                 else
637                     global.params.debuglevel = 1;
638             }
639             else if (memcmp(p + 1, "version", 5) == 0)
640             {
641                 // Parse:
642                 //      -version=number
643                 //      -version=identifier
644                 if (p[8] == '=')
645                 {
646                     if (isdigit(p[9]))
647                     {   long level;
648
649                         errno = 0;
650                         level = strtol(p + 9, &p, 10);
651                         if (*p || errno || level > INT_MAX)
652                             goto Lerror;
653                         VersionCondition::setGlobalLevel((int)level);
654                     }
655                     else if (Lexer::isValidIdentifier(p + 9))
656                         VersionCondition::addGlobalIdent(p + 9);
657                     else
658                         goto Lerror;
659                 }
660                 else
661                     goto Lerror;
662             }
663             else if (strcmp(p + 1, "-b") == 0)
664                 global.params.debugb = 1;
665             else if (strcmp(p + 1, "-c") == 0)
666                 global.params.debugc = 1;
667             else if (strcmp(p + 1, "-f") == 0)
668                 global.params.debugf = 1;
669             else if (strcmp(p + 1, "-help") == 0)
670             {   usage();
671                 exit(EXIT_SUCCESS);
672             }
673             else if (strcmp(p + 1, "-r") == 0)
674                 global.params.debugr = 1;
675             else if (strcmp(p + 1, "-x") == 0)
676                 global.params.debugx = 1;
677             else if (strcmp(p + 1, "-y") == 0)
678                 global.params.debugy = 1;
679             else if (p[1] == 'L')
680             {
681                 global.params.linkswitches->push(p + 2);
682             }
683             else if (memcmp(p + 1, "defaultlib=", 11) == 0)
684             {
685                 global.params.defaultlibname = p + 1 + 11;
686             }
687             else if (memcmp(p + 1, "debuglib=", 9) == 0)
688             {
689                 setdebuglib = 1;
690                 global.params.debuglibname = p + 1 + 9;
691             }
692             else if (memcmp(p + 1, "deps=", 5) == 0)
693             {
694                 global.params.moduleDepsFile = p + 1 + 5;
695                 if (!global.params.moduleDepsFile[0])
696                     goto Lnoarg;
697                 global.params.moduleDeps = new OutBuffer;
698             }
699             else if (memcmp(p + 1, "man", 3) == 0)
700             {
701 #if _WIN32
702 #if DMDV1
703                 browse("http://www.digitalmars.com/d/1.0/dmd-windows.html");
704 #else
705                 browse("http://www.digitalmars.com/d/2.0/dmd-windows.html");
706 #endif
707 #endif
708 #if linux
709 #if DMDV1
710                 browse("http://www.digitalmars.com/d/1.0/dmd-linux.html");
711 #else
712                 browse("http://www.digitalmars.com/d/2.0/dmd-linux.html");
713 #endif
714 #endif
715 #if __APPLE__
716 #if DMDV1
717                 browse("http://www.digitalmars.com/d/1.0/dmd-osx.html");
718 #else
719                 browse("http://www.digitalmars.com/d/2.0/dmd-osx.html");
720 #endif
721 #endif
722 #if __FreeBSD__
723 #if DMDV1
724                 browse("http://www.digitalmars.com/d/1.0/dmd-freebsd.html");
725 #else
726                 browse("http://www.digitalmars.com/d/2.0/dmd-freebsd.html");
727 #endif
728 #endif
729                 exit(EXIT_SUCCESS);
730             }
731             else if (strcmp(p + 1, "run") == 0)
732             {   global.params.run = 1;
733                 global.params.runargs_length = ((i >= argcstart) ? argc : argcstart) - i - 1;
734                 if (global.params.runargs_length)
735                 {
736                     files.push(argv[i + 1]);
737                     global.params.runargs = &argv[i + 2];
738                     i += global.params.runargs_length;
739                     global.params.runargs_length--;
740                 }
741                 else
742                 {   global.params.run = 0;
743                     goto Lnoarg;
744                 }
745             }
746             else
747             {
748              Lerror:
749                 error("unrecognized switch '%s'", argv[i]);
750                 continue;
751
752              Lnoarg:
753                 error("argument expected for switch '%s'", argv[i]);
754                 continue;
755             }
756         }
757         else
758         {
759 #if TARGET_WINDOS
760             char *ext = FileName::ext(p);
761             if (ext && FileName::compare(ext, "exe") == 0)
762             {
763                 global.params.objname = p;
764                 continue;
765             }
766 #endif
767             files.push(p);
768         }
769     }
770     if (global.errors)
771     {
772         fatal();
773     }
774     if (files.dim == 0)
775     {   usage();
776         return EXIT_FAILURE;
777     }
778
779     if (!setdebuglib)
780         global.params.debuglibname = global.params.defaultlibname;
781
782 #if TARGET_OSX
783     global.params.pic = 1;
784 #endif
785
786     if (global.params.release)
787     {   global.params.useInvariants = 0;
788         global.params.useIn = 0;
789         global.params.useOut = 0;
790         global.params.useAssert = 0;
791         global.params.useArrayBounds = 1;
792         global.params.useSwitchError = 0;
793     }
794     if (noboundscheck)
795         global.params.useArrayBounds = 0;
796
797     if (global.params.run)
798         global.params.quiet = 1;
799
800     if (global.params.useUnitTests)
801         global.params.useAssert = 1;
802
803     if (!global.params.obj || global.params.lib)
804         global.params.link = 0;
805
806     if (global.params.link)
807     {
808         global.params.exefile = global.params.objname;
809         global.params.oneobj = 1;
810         if (global.params.objname)
811         {
812             /* Use this to name the one object file with the same
813              * name as the exe file.
814              */
815             global.params.objname = FileName::forceExt(global.params.objname, global.obj_ext)->toChars();
816
817             /* If output directory is given, use that path rather than
818              * the exe file path.
819              */
820             if (global.params.objdir)
821             {   char *name = FileName::name(global.params.objname);
822                 global.params.objname = FileName::combine(global.params.objdir, name);
823             }
824         }
825     }
826     else if (global.params.lib)
827     {
828         global.params.libname = global.params.objname;
829         global.params.objname = NULL;
830
831         // Haven't investigated handling these options with multiobj
832         if (!global.params.cov && !global.params.trace)
833             global.params.multiobj = 1;
834     }
835     else if (global.params.run)
836     {
837         error("flags conflict with -run");
838         fatal();
839     }
840     else
841     {
842         if (global.params.objname && files.dim > 1)
843         {
844             global.params.oneobj = 1;
845             //error("multiple source files, but only one .obj name");
846             //fatal();
847         }
848     }
849     if (global.params.isX86_64)
850     {
851         VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86_64");
852         VersionCondition::addPredefinedGlobalIdent("X86_64");
853         VersionCondition::addPredefinedGlobalIdent("D_LP64");
854 #if TARGET_WINDOS
855         VersionCondition::addPredefinedGlobalIdent("Win64");
856 #endif
857     }
858     else
859     {
860         VersionCondition::addPredefinedGlobalIdent("D_InlineAsm");
861         VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86");
862         VersionCondition::addPredefinedGlobalIdent("X86");
863 #if TARGET_WINDOS
864         VersionCondition::addPredefinedGlobalIdent("Win32");
865 #endif
866     }
867     if (global.params.doDocComments)
868         VersionCondition::addPredefinedGlobalIdent("D_Ddoc");
869     if (global.params.cov)
870         VersionCondition::addPredefinedGlobalIdent("D_Coverage");
871     if (global.params.pic)
872         VersionCondition::addPredefinedGlobalIdent("D_PIC");
873 #if DMDV2
874     if (global.params.useUnitTests)
875         VersionCondition::addPredefinedGlobalIdent("unittest");
876 #endif
877
878     // Initialization
879     Type::init();
880     Id::initialize();
881     Module::init();
882     initPrecedence();
883
884     backend_init();
885
886     if (global.params.verbose)
887     {   printf("binary    %s\n", argv[0]);
888         printf("version   %s\n", global.version);
889         printf("config    %s\n", inifilename ? inifilename : "(none)");
890     }
891
892     //printf("%d source files\n",files.dim);
893
894     // Build import search path
895     if (global.params.imppath)
896     {
897         for (i = 0; i < global.params.imppath->dim; i++)
898         {
899             char *path = (char *)global.params.imppath->data[i];
900             Array *a = FileName::splitPath(path);
901
902             if (a)
903             {
904                 if (!global.path)
905                     global.path = new Array();
906                 global.path->append(a);
907             }
908         }
909     }
910
911     // Build string import search path
912     if (global.params.fileImppath)
913     {
914         for (i = 0; i < global.params.fileImppath->dim; i++)
915         {
916             char *path = (char *)global.params.fileImppath->data[i];
917             Array *a = FileName::splitPath(path);
918
919             if (a)
920             {
921                 if (!global.filePath)
922                     global.filePath = new Array();
923                 global.filePath->append(a);
924             }
925         }
926     }
927
928     // Create Modules
929     Array modules;
930     modules.reserve(files.dim);
931     int firstmodule = 1;
932     for (i = 0; i < files.dim; i++)
933     {
934         char *ext;
935         char *name;
936
937         p = (char *) files.data[i];
938
939 #if _WIN32
940         // Convert / to \ so linker will work
941         for (int i = 0; p[i]; i++)
942         {
943             if (p[i] == '/')
944                 p[i] = '\\';
945         }
946 #endif
947
948         p = FileName::name(p);          // strip path
949         ext = FileName::ext(p);
950         if (ext)
951         {   /* Deduce what to do with a file based on its extension
952              */
953             if (FileName::equals(ext, global.obj_ext))
954             {
955                 global.params.objfiles->push(files.data[i]);
956                 libmodules.push(files.data[i]);
957                 continue;
958             }
959
960             if (FileName::equals(ext, global.lib_ext))
961             {
962                 global.params.libfiles->push(files.data[i]);
963                 libmodules.push(files.data[i]);
964                 continue;
965             }
966
967             if (strcmp(ext, global.ddoc_ext) == 0)
968             {
969                 global.params.ddocfiles->push(files.data[i]);
970                 continue;
971             }
972
973             if (FileName::equals(ext, global.json_ext))
974             {
975                 global.params.doXGeneration = 1;
976                 global.params.xfilename = (char *)files.data[i];
977                 continue;
978             }
979
980             if (FileName::equals(ext, global.map_ext))
981             {
982                 global.params.mapfile = (char *)files.data[i];
983                 continue;
984             }
985
986 #if TARGET_WINDOS
987             if (FileName::equals(ext, "res"))
988             {
989                 global.params.resfile = (char *)files.data[i];
990                 continue;
991             }
992
993             if (FileName::equals(ext, "def"))
994             {
995                 global.params.deffile = (char *)files.data[i];
996                 continue;
997             }
998
999             if (FileName::equals(ext, "exe"))
1000             {
1001                 assert(0);      // should have already been handled
1002             }
1003 #endif
1004
1005             /* Examine extension to see if it is a valid
1006              * D source file extension
1007              */
1008             if (FileName::equals(ext, global.mars_ext) ||
1009                 FileName::equals(ext, global.hdr_ext) ||
1010                 FileName::equals(ext, "dd") ||
1011                 FileName::equals(ext, "htm") ||
1012                 FileName::equals(ext, "html") ||
1013                 FileName::equals(ext, "xhtml"))
1014             {
1015                 ext--;                  // skip onto '.'
1016                 assert(*ext == '.');
1017                 name = (char *)mem.malloc((ext - p) + 1);
1018                 memcpy(name, p, ext - p);
1019                 name[ext - p] = 0;              // strip extension
1020
1021                 if (name[0] == 0 ||
1022                     strcmp(name, "..") == 0 ||
1023                     strcmp(name, ".") == 0)
1024                 {
1025                 Linvalid:
1026                     error("invalid file name '%s'", (char *)files.data[i]);
1027                     fatal();
1028                 }
1029             }
1030             else
1031             {   error("unrecognized file extension %s\n", ext);
1032                 fatal();
1033             }
1034         }
1035         else
1036         {   name = p;
1037             if (!*name)
1038                 goto Linvalid;
1039         }
1040
1041         /* At this point, name is the D source file name stripped of
1042          * its path and extension.
1043          */
1044
1045         Identifier *id = Lexer::idPool(name);
1046         m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration);
1047         modules.push(m);
1048
1049         if (firstmodule)
1050         {   global.params.objfiles->push(m->objfile->name->str);
1051             firstmodule = 0;
1052         }
1053     }
1054
1055 #if WINDOWS_SEH
1056   __try
1057   {
1058 #endif
1059     // Read files
1060 #define ASYNCREAD 1
1061 #if ASYNCREAD
1062     // Multi threaded
1063     AsyncRead *aw = AsyncRead::create(modules.dim);
1064     for (i = 0; i < modules.dim; i++)
1065     {
1066         m = (Module *)modules.data[i];
1067         aw->addFile(m->srcfile);
1068     }
1069     aw->start();
1070 #else
1071     // Single threaded
1072     for (i = 0; i < modules.dim; i++)
1073     {
1074         m = (Module *)modules.data[i];
1075         m->read(0);
1076     }
1077 #endif
1078
1079     // Parse files
1080     int anydocfiles = 0;
1081     for (i = 0; i < modules.dim; i++)
1082     {
1083         m = (Module *)modules.data[i];
1084         if (global.params.verbose)
1085             printf("parse     %s\n", m->toChars());
1086         if (!Module::rootModule)
1087             Module::rootModule = m;
1088         m->importedFrom = m;
1089         if (!global.params.oneobj || i == 0 || m->isDocFile)
1090             m->deleteObjFile();
1091 #if ASYNCREAD
1092         if (aw->read(i))
1093         {
1094             error("cannot read file %s", m->srcfile->name->toChars());
1095         }
1096 #endif
1097         m->parse();
1098         if (m->isDocFile)
1099         {
1100             anydocfiles = 1;
1101             m->gendocfile();
1102
1103             // Remove m from list of modules
1104             modules.remove(i);
1105             i--;
1106
1107             // Remove m's object file from list of object files
1108             for (int j = 0; j < global.params.objfiles->dim; j++)
1109             {
1110                 if (m->objfile->name->str == global.params.objfiles->data[j])
1111                 {
1112                     global.params.objfiles->remove(j);
1113                     break;
1114                 }
1115             }
1116
1117             if (global.params.objfiles->dim == 0)
1118                 global.params.link = 0;
1119         }
1120     }
1121 #if ASYNCREAD
1122     AsyncRead::dispose(aw);
1123 #endif
1124
1125     if (anydocfiles && modules.dim &&
1126         (global.params.oneobj || global.params.objname))
1127     {
1128         error("conflicting Ddoc and obj generation options");
1129         fatal();
1130     }
1131     if (global.errors)
1132         fatal();
1133 #ifdef _DH
1134     if (global.params.doHdrGeneration)
1135     {
1136         /* Generate 'header' import files.
1137          * Since 'header' import files must be independent of command
1138          * line switches and what else is imported, they are generated
1139          * before any semantic analysis.
1140          */
1141         for (i = 0; i < modules.dim; i++)
1142         {
1143             m = (Module *)modules.data[i];
1144             if (global.params.verbose)
1145                 printf("import    %s\n", m->toChars());
1146             m->genhdrfile();
1147         }
1148     }
1149     if (global.errors)
1150         fatal();
1151 #endif
1152
1153     // load all unconditional imports for better symbol resolving
1154     for (i = 0; i < modules.dim; i++)
1155     {
1156        m = (Module *)modules.data[i];
1157        if (global.params.verbose)
1158            printf("importall %s\n", m->toChars());
1159        m->importAll(0);
1160     }
1161     if (global.errors)
1162        fatal();
1163
1164     // Do semantic analysis
1165     for (i = 0; i < modules.dim; i++)
1166     {
1167         m = (Module *)modules.data[i];
1168         if (global.params.verbose)
1169             printf("semantic  %s\n", m->toChars());
1170         m->semantic();
1171     }
1172     if (global.errors)
1173         fatal();
1174
1175     Module::dprogress = 1;
1176     Module::runDeferredSemantic();
1177
1178     // Do pass 2 semantic analysis
1179     for (i = 0; i < modules.dim; i++)
1180     {
1181         m = (Module *)modules.data[i];
1182         if (global.params.verbose)
1183             printf("semantic2 %s\n", m->toChars());
1184         m->semantic2();
1185     }
1186     if (global.errors)
1187         fatal();
1188
1189     // Do pass 3 semantic analysis
1190     for (i = 0; i < modules.dim; i++)
1191     {
1192         m = (Module *)modules.data[i];
1193         if (global.params.verbose)
1194             printf("semantic3 %s\n", m->toChars());
1195         m->semantic3();
1196     }
1197     if (global.errors)
1198         fatal();
1199
1200     if (global.params.moduleDeps != NULL)
1201     {
1202         assert(global.params.moduleDepsFile != NULL);
1203
1204         File deps(global.params.moduleDepsFile);
1205         OutBuffer* ob = global.params.moduleDeps;
1206         deps.setbuffer((void*)ob->data, ob->offset);
1207         deps.writev();
1208     }
1209
1210
1211     // Scan for functions to inline
1212     if (global.params.useInline)
1213     {
1214         /* The problem with useArrayBounds and useAssert is that the
1215          * module being linked to may not have generated them, so if
1216          * we inline functions from those modules, the symbols for them will
1217          * not be found at link time.
1218          */
1219         if (!global.params.useArrayBounds && !global.params.useAssert)
1220         {
1221             // Do pass 3 semantic analysis on all imported modules,
1222             // since otherwise functions in them cannot be inlined
1223             for (i = 0; i < Module::amodules.dim; i++)
1224             {
1225                 m = (Module *)Module::amodules.data[i];
1226                 if (global.params.verbose)
1227                     printf("semantic3 %s\n", m->toChars());
1228                 m->semantic3();
1229             }
1230             if (global.errors)
1231                 fatal();
1232         }
1233
1234         for (i = 0; i < modules.dim; i++)
1235         {
1236             m = (Module *)modules.data[i];
1237             if (global.params.verbose)
1238                 printf("inline scan %s\n", m->toChars());
1239             m->inlineScan();
1240         }
1241     }
1242
1243     // Do not attempt to generate output files if errors or warnings occurred
1244     if (global.errors || global.warnings)
1245         fatal();
1246
1247     Library *library = NULL;
1248     if (global.params.lib)
1249     {
1250         library = new Library();
1251         library->setFilename(global.params.objdir, global.params.libname);
1252
1253         // Add input object and input library files to output library
1254         for (int i = 0; i < libmodules.dim; i++)
1255         {
1256             char *p = (char *)libmodules.data[i];
1257             library->addObject(p, NULL, 0);
1258         }
1259     }
1260
1261     // Generate output files
1262
1263     if (global.params.doXGeneration)
1264         json_generate(&modules);
1265
1266     if (global.params.oneobj)
1267     {
1268         for (i = 0; i < modules.dim; i++)
1269         {
1270             m = (Module *)modules.data[i];
1271             if (global.params.verbose)
1272                 printf("code      %s\n", m->toChars());
1273             if (i == 0)
1274                 obj_start(m->srcfile->toChars());
1275             m->genobjfile(0);
1276             if (!global.errors && global.params.doDocComments)
1277                 m->gendocfile();
1278         }
1279         if (!global.errors && modules.dim)
1280         {
1281             obj_end(library, ((Module *)modules.data[0])->objfile);
1282         }
1283     }
1284     else
1285     {
1286         for (i = 0; i < modules.dim; i++)
1287         {
1288             m = (Module *)modules.data[i];
1289             if (global.params.verbose)
1290                 printf("code      %s\n", m->toChars());
1291             if (global.params.obj)
1292             {   obj_start(m->srcfile->toChars());
1293                 m->genobjfile(global.params.multiobj);
1294                 obj_end(library, m->objfile);
1295                 obj_write_deferred(library);
1296             }
1297             if (global.errors)
1298             {
1299                 if (!global.params.lib)
1300                     m->deleteObjFile();
1301             }
1302             else
1303             {
1304                 if (global.params.doDocComments)
1305                     m->gendocfile();
1306             }
1307         }
1308     }
1309
1310     if (global.params.lib && !global.errors)
1311         library->write();
1312
1313 #if WINDOWS_SEH
1314   }
1315   __except (__ehfilter(GetExceptionInformation()))
1316   {
1317     printf("Stack overflow\n");
1318     fatal();
1319   }
1320 #endif
1321     backend_term();
1322     if (global.errors)
1323         fatal();
1324
1325     if (!global.params.objfiles->dim)
1326     {
1327         if (global.params.link)
1328             error("no object files to link");
1329     }
1330     else
1331     {
1332         if (global.params.link)
1333             status = runLINK();
1334
1335         if (global.params.run)
1336         {
1337             if (!status)
1338             {
1339                 status = runProgram();
1340
1341                 /* Delete .obj files and .exe file
1342                  */
1343                 for (i = 0; i < modules.dim; i++)
1344                 {
1345                     Module *m = (Module *)modules.data[i];
1346                     m->deleteObjFile();
1347                     if (global.params.oneobj)
1348                         break;
1349                 }
1350                 deleteExeFile();
1351             }
1352         }
1353     }
1354
1355     return status;
1356 }
1357
1358
1359
1360 /***********************************
1361  * Parse and append contents of environment variable envvar
1362  * to argc and argv[].
1363  * The string is separated into arguments, processing \ and ".
1364  */
1365
1366 void getenv_setargv(const char *envvar, int *pargc, char** *pargv)
1367 {
1368     char *p;
1369
1370     int instring;
1371     int slash;
1372     char c;
1373
1374     char *env = getenv(envvar);
1375     if (!env)
1376         return;
1377
1378     env = mem.strdup(env);      // create our own writable copy
1379
1380     int argc = *pargc;
1381     Array *argv = new Array();
1382     argv->setDim(argc);
1383
1384     for (int i = 0; i < argc; i++)
1385         argv->data[i] = (void *)(*pargv)[i];
1386
1387     int j = 1;                  // leave argv[0] alone
1388     while (1)
1389     {
1390         int wildcard = 1;       // do wildcard expansion
1391         switch (*env)
1392         {
1393             case ' ':
1394             case '\t':
1395                 env++;
1396                 break;
1397
1398             case 0:
1399                 goto Ldone;
1400
1401             case '"':
1402                 wildcard = 0;
1403             default:
1404                 argv->push(env);                // append
1405                 //argv->insert(j, env);         // insert at position j
1406                 j++;
1407                 argc++;
1408                 p = env;
1409                 slash = 0;
1410                 instring = 0;
1411                 c = 0;
1412
1413                 while (1)
1414                 {
1415                     c = *env++;
1416                     switch (c)
1417                     {
1418                         case '"':
1419                             p -= (slash >> 1);
1420                             if (slash & 1)
1421                             {   p--;
1422                                 goto Laddc;
1423                             }
1424                             instring ^= 1;
1425                             slash = 0;
1426                             continue;
1427
1428                         case ' ':
1429                         case '\t':
1430                             if (instring)
1431                                 goto Laddc;
1432                             *p = 0;
1433                             //if (wildcard)
1434                                 //wildcardexpand();     // not implemented
1435                             break;
1436
1437                         case '\\':
1438                             slash++;
1439                             *p++ = c;
1440                             continue;
1441
1442                         case 0:
1443                             *p = 0;
1444                             //if (wildcard)
1445                                 //wildcardexpand();     // not implemented
1446                             goto Ldone;
1447
1448                         default:
1449                         Laddc:
1450                             slash = 0;
1451                             *p++ = c;
1452                             continue;
1453                     }
1454                     break;
1455                 }
1456         }
1457     }
1458
1459 Ldone:
1460     *pargc = argc;
1461     *pargv = (char **)argv->data;
1462 }
1463
1464 #if WINDOWS_SEH
1465
1466 long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep)
1467 {
1468     //printf("%x\n", ep->ExceptionRecord->ExceptionCode);
1469     if (ep->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)
1470     {
1471 #ifndef DEBUG
1472         return EXCEPTION_EXECUTE_HANDLER;
1473 #endif
1474     }
1475     return EXCEPTION_CONTINUE_SEARCH;
1476 }
1477
1478 #endif
Note: See TracBrowser for help on using the browser.