root/trunk/src/mars.c

Revision 616, 40.9 kB (checked in by walter, 3 weeks ago)

bugzilla 3294 forward reference to inferred return type of function call

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