1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  * Entry point for DMD.
5  *
6  * This modules defines the entry point (main) for DMD, as well as related
7  * utilities needed for arguments parsing, path manipulation, etc...
8  * This file is not shared with other compilers which use the DMD front-end.
9  *
10  * Copyright:   Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
11  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
12  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
13  * Source:      $(DMDSRC _mars.d)
14  */
15 
16 module ddmd.mars;
17 
18 import core.stdc.ctype;
19 import core.stdc.errno;
20 import core.stdc.limits;
21 import core.stdc.stdio;
22 import core.stdc.stdlib;
23 import core.stdc..string;
24 import ddmd.arraytypes;
25 import ddmd.gluelayer;
26 import ddmd.builtin;
27 import ddmd.cond;
28 import ddmd.dinifile;
29 import ddmd.dinterpret;
30 import ddmd.dmodule;
31 import ddmd.doc;
32 import ddmd.dscope;
33 import ddmd.dsymbol;
34 import ddmd.errors;
35 import ddmd.expression;
36 import ddmd.globals;
37 import ddmd.hdrgen;
38 import ddmd.id;
39 import ddmd.identifier;
40 import ddmd.inline;
41 import ddmd.json;
42 import ddmd.lib;
43 import ddmd.link;
44 import ddmd.mtype;
45 import ddmd.objc;
46 import ddmd.parse;
47 import ddmd.root.file;
48 import ddmd.root.filename;
49 import ddmd.root.man;
50 import ddmd.root.outbuffer;
51 import ddmd.root.response;
52 import ddmd.root.rmem;
53 import ddmd.root.stringtable;
54 import ddmd.target;
55 import ddmd.tokens;
56 import ddmd.utils;
57 
58 
59 /**
60  * Print DMD's logo on stdout
61  */
62 private void logo()
63 {
64     printf("DMD%llu D Compiler %s\n%s %s\n", cast(ulong)size_t.sizeof * 8, global._version, global.copyright, global.written);
65 }
66 
67 
68 /**
69  * Print DMD's usage message on stdout
70  */
71 private  void usage()
72 {
73     static if (TARGET_LINUX)
74     {
75         const(char)* fpic = "\n  -fPIC            generate position independent code";
76     }
77     else
78     {
79         const(char)* fpic = "";
80     }
81     static if (TARGET_WINDOS)
82     {
83         const(char)* m32mscoff = "\n  -m32mscoff       generate 32 bit code and write MS-COFF object files";
84     }
85     else
86     {
87         const(char)* m32mscoff = "";
88     }
89     logo();
90     printf("
91 Documentation: http://dlang.org/
92 Config file: %s
93 Usage:
94   dmd [<option>...] <file>...
95   dmd [<option>...] -run <file> [<arg>...]
96 
97 Where:
98   <file>           D source file
99   <arg>            Argument to pass when running the resulting program
100 
101 <option>:
102   @<cmdfile>       read arguments from cmdfile
103   -allinst         generate code for all template instantiations
104   -betterC         omit generating some runtime information and helper functions
105   -boundscheck=[on|safeonly|off]   bounds checks on, in @safe only, or off
106   -c               do not link
107   -color           turn colored console output on
108   -color=[on|off]  force colored console output on or off
109   -conf=<filename> use config file at filename
110   -cov             do code coverage analysis
111   -cov=<nnn>       require at least nnn%% code coverage
112   -D               generate documentation
113   -Dd<directory>   write documentation file to directory
114   -Df<filename>    write documentation file to filename
115   -d               silently allow deprecated features
116   -dw              show use of deprecated features as warnings (default)
117   -de              show use of deprecated features as errors (halt compilation)
118   -debug           compile in debug code
119   -debug=<level>   compile in debug code <= level
120   -debug=<ident>   compile in debug code identified by ident
121   -debuglib=<name> set symbolic debug library to name
122   -defaultlib=<name>
123                    set default library to name
124   -deps            print module dependencies (imports/file/version/debug/lib)
125   -deps=<filename> write module dependencies to filename (only imports)" ~
126   "%s" /* placeholder for fpic */ ~ "
127   -dip25           implement http://wiki.dlang.org/DIP25 (experimental)
128   -g               add symbolic debug info
129   -gc              add symbolic debug info, optimize for non D debuggers
130   -gs              always emit stack frame
131   -gx              add stack stomp code
132   -H               generate 'header' file
133   -Hd=<directory>  write 'header' file to directory
134   -Hf=<filename>   write 'header' file to filename
135   --help           print help and exit
136   -I=<directory>   look for imports also in directory
137   -ignore          ignore unsupported pragmas
138   -inline          do function inlining
139   -J=<directory>   look for string imports also in directory
140   -L=<linkerflag>  pass linkerflag to link
141   -lib             generate library rather than object files
142   -m32             generate 32 bit code" ~
143   "%s" /* placeholder for m32mscoff */ ~ "
144   -m64             generate 64 bit code
145   -main            add default main() (e.g. for unittesting)
146   -man             open web browser on manual page
147   -map             generate linker .map file
148   -noboundscheck   no array bounds checking (deprecated, use -boundscheck=off)
149   -O               optimize
150   -o-              do not write object file
151   -od=<directory>  write object & library files to directory
152   -of=<filename>   name output file to filename
153   -op              preserve source path for output files
154   -profile         profile runtime performance of generated code
155   -profile=gc      profile runtime allocations
156   -release         compile release version
157   -shared          generate shared library (DLL)
158   -transition=<id> help with language change identified by 'id'
159   -transition=?    list all language changes
160   -unittest        compile in unit tests
161   -v               verbose
162   -vcolumns        print character (column) numbers in diagnostics
163   -verrors=<num>   limit the number of error messages (0 means unlimited)
164   -vgc             list all gc allocations including hidden ones
165   -vtls            list all variables going into thread local storage
166   --version        print compiler version and exit
167   -version=<level> compile in version code >= level
168   -version=<ident> compile in version code identified by ident
169   -w               warnings as errors (compilation will halt)
170   -wi              warnings as messages (compilation will continue)
171   -X               generate JSON file
172   -Xf=<filename>   write JSON file to filename
173 ", FileName.canonicalName(global.inifilename), fpic, m32mscoff);
174 }
175 
176 /// DMD-generated module `__entrypoint` where the C main resides
177 extern (C++) __gshared Module entrypoint = null;
178 /// Module in which the D main is
179 extern (C++) __gshared Module rootHasMain = null;
180 
181 
182 /**
183  * Generate C main() in response to seeing D main().
184  *
185  * This function will generate a module called `__entrypoint`,
186  * and set the globals `entrypoint` and `rootHasMain`.
187  *
188  * This used to be in druntime, but contained a reference to _Dmain
189  * which didn't work when druntime was made into a dll and was linked
190  * to a program, such as a C++ program, that didn't have a _Dmain.
191  *
192  * Params:
193  *   sc = Scope which triggered the generation of the C main,
194  *        used to get the module where the D main is.
195  */
196 extern (C++) void genCmain(Scope* sc)
197 {
198     if (entrypoint)
199         return;
200     /* The D code to be generated is provided as D source code in the form of a string.
201      * Note that Solaris, for unknown reasons, requires both a main() and an _main()
202      */
203     immutable cmaincode =
204     q{
205         extern(C)
206         {
207             int _d_run_main(int argc, char **argv, void* mainFunc);
208             int _Dmain(char[][] args);
209             int main(int argc, char **argv)
210             {
211                 return _d_run_main(argc, argv, &_Dmain);
212             }
213             version (Solaris) int _main(int argc, char** argv) { return main(argc, argv); }
214         }
215     };
216     Identifier id = Id.entrypoint;
217     auto m = new Module("__entrypoint.d", id, 0, 0);
218     scope Parser p = new Parser(m, cmaincode, false);
219     p.scanloc = Loc();
220     p.nextToken();
221     m.members = p.parseModule();
222     assert(p.token.value == TOKeof);
223     assert(!p.errors); // shouldn't have failed to parse it
224     bool v = global.params.verbose;
225     global.params.verbose = false;
226     m.importedFrom = m;
227     m.importAll(null);
228     m.semantic(null);
229     m.semantic2(null);
230     m.semantic3(null);
231     global.params.verbose = v;
232     entrypoint = m;
233     rootHasMain = sc._module;
234 }
235 
236 
237 /**
238  * DMD's real entry point
239  *
240  * Parses command line arguments and config file, open and read all
241  * provided source file and do semantic analysis on them.
242  *
243  * Params:
244  *   argc = Number of arguments passed via command line
245  *   argv = Array of string arguments passed via command line
246  *
247  * Returns:
248  *   Application return code
249  */
250 private int tryMain(size_t argc, const(char)** argv)
251 {
252     Strings files;
253     Strings libmodules;
254     global._init();
255     debug
256     {
257         printf("DMD %s DEBUG\n", global._version);
258         fflush(stdout); // avoid interleaving with stderr output when redirecting
259     }
260     // Check for malformed input
261     if (argc < 1 || !argv)
262     {
263     Largs:
264         error(Loc(), "missing or null command line arguments");
265         fatal();
266     }
267     // Convert argc/argv into arguments[] for easier handling
268     Strings arguments;
269     arguments.setDim(argc);
270     for (size_t i = 0; i < argc; i++)
271     {
272         if (!argv[i])
273             goto Largs;
274         arguments[i] = argv[i];
275     }
276     if (response_expand(&arguments)) // expand response files
277         error(Loc(), "can't open response file");
278     //for (size_t i = 0; i < arguments.dim; ++i) printf("arguments[%d] = '%s'\n", i, arguments[i]);
279     files.reserve(arguments.dim - 1);
280     // Set default values
281     global.params.argv0 = arguments[0];
282     global.params.color = isConsoleColorSupported();
283     global.params.link = true;
284     global.params.useAssert = true;
285     global.params.useInvariants = true;
286     global.params.useIn = true;
287     global.params.useOut = true;
288     global.params.useArrayBounds = BOUNDSCHECKdefault; // set correct value later
289     global.params.useSwitchError = true;
290     global.params.useInline = false;
291     global.params.obj = true;
292     global.params.useDeprecated = 2;
293     global.params.hdrStripPlainFunctions = true;
294     global.params.linkswitches = new Strings();
295     global.params.libfiles = new Strings();
296     global.params.dllfiles = new Strings();
297     global.params.objfiles = new Strings();
298     global.params.ddocfiles = new Strings();
299     // Default to -m32 for 32 bit dmd, -m64 for 64 bit dmd
300     global.params.is64bit = (size_t.sizeof == 8);
301     global.params.mscoff = false;
302 
303     // Temporary: Use 32 bits as the default on Windows, for config parsing
304     static if (TARGET_WINDOS)
305         global.params.is64bit = false;
306 
307     global.inifilename = parse_conf_arg(&arguments);
308     if (global.inifilename)
309     {
310         // can be empty as in -conf=
311         if (strlen(global.inifilename) && !FileName.exists(global.inifilename))
312             error(Loc(), "Config file '%s' does not exist.", global.inifilename);
313     }
314     else
315     {
316         version (Windows)
317         {
318             global.inifilename = findConfFile(global.params.argv0, "sc.ini");
319         }
320         else version (Posix)
321         {
322             global.inifilename = findConfFile(global.params.argv0, "dmd.conf");
323         }
324         else
325         {
326             static assert(0, "fix this");
327         }
328     }
329     // Read the configurarion file
330     auto inifile = File(global.inifilename);
331     inifile.read();
332     /* Need path of configuration file, for use in expanding @P macro
333      */
334     const(char)* inifilepath = FileName.path(global.inifilename);
335     Strings sections;
336     StringTable environment;
337     environment._init(7);
338     /* Read the [Environment] section, so we can later
339      * pick up any DFLAGS settings.
340      */
341     sections.push("Environment");
342     parseConfFile(&environment, global.inifilename, inifilepath, inifile.len, inifile.buffer, &sections);
343     Strings dflags;
344     getenv_setargv(readFromEnv(&environment, "DFLAGS"), &dflags);
345     environment.reset(7); // erase cached environment updates
346     const(char)* arch = global.params.is64bit ? "64" : "32"; // use default
347     arch = parse_arch_arg(&arguments, arch);
348     arch = parse_arch_arg(&dflags, arch);
349     bool is64bit = arch[0] == '6';
350     char[80] envsection;
351     sprintf(envsection.ptr, "Environment%s", arch);
352     sections.push(envsection.ptr);
353     parseConfFile(&environment, global.inifilename, inifilepath, inifile.len, inifile.buffer, &sections);
354     getenv_setargv(readFromEnv(&environment, "DFLAGS"), &arguments);
355     updateRealEnvironment(&environment);
356     environment.reset(1); // don't need environment cache any more
357     version (none)
358     {
359         for (size_t i = 0; i < arguments.dim; i++)
360         {
361             printf("arguments[%d] = '%s'\n", i, arguments[i]);
362         }
363     }
364     for (size_t i = 1; i < arguments.dim; i++)
365     {
366         const(char)* p = arguments[i];
367         if (*p == '-')
368         {
369             if (strcmp(p + 1, "allinst") == 0)
370                 global.params.allInst = true;
371             else if (strcmp(p + 1, "de") == 0)
372                 global.params.useDeprecated = 0;
373             else if (strcmp(p + 1, "d") == 0)
374                 global.params.useDeprecated = 1;
375             else if (strcmp(p + 1, "dw") == 0)
376                 global.params.useDeprecated = 2;
377             else if (strcmp(p + 1, "c") == 0)
378                 global.params.link = false;
379             else if (memcmp(p + 1, cast(char*)"color", 5) == 0)
380             {
381                 global.params.color = true;
382                 // Parse:
383                 //      -color
384                 //      -color=on|off
385                 if (p[6] == '=')
386                 {
387                     if (strcmp(p + 7, "off") == 0)
388                         global.params.color = false;
389                     else if (strcmp(p + 7, "on") != 0)
390                         goto Lerror;
391                 }
392                 else if (p[6])
393                     goto Lerror;
394             }
395             else if (memcmp(p + 1, cast(char*)"conf=", 5) == 0)
396             {
397                 // ignore, already handled above
398             }
399             else if (memcmp(p + 1, cast(char*)"cov", 3) == 0)
400             {
401                 global.params.cov = true;
402                 // Parse:
403                 //      -cov
404                 //      -cov=nnn
405                 if (p[4] == '=')
406                 {
407                     if (isdigit(cast(char)p[5]))
408                     {
409                         long percent;
410                         errno = 0;
411                         percent = strtol(p + 5, cast(char**)&p, 10);
412                         if (*p || errno || percent > 100)
413                             goto Lerror;
414                         global.params.covPercent = cast(ubyte)percent;
415                     }
416                     else
417                         goto Lerror;
418                 }
419                 else if (p[4])
420                     goto Lerror;
421             }
422             else if (strcmp(p + 1, "shared") == 0)
423                 global.params.dll = true;
424             else if (strcmp(p + 1, "dylib") == 0)
425             {
426                 static if (TARGET_OSX)
427                 {
428                     Loc loc;
429                     deprecation(loc, "use -shared instead of -dylib");
430                     global.params.dll = true;
431                 }
432                 else
433                 {
434                     goto Lerror;
435                 }
436             }
437             else if (strcmp(p + 1, "fPIC") == 0)
438             {
439                 static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS)
440                 {
441                     global.params.pic = 1;
442                 }
443                 else
444                 {
445                     goto Lerror;
446                 }
447             }
448             else if (strcmp(p + 1, "map") == 0)
449                 global.params.map = true;
450             else if (strcmp(p + 1, "multiobj") == 0)
451                 global.params.multiobj = true;
452             else if (strcmp(p + 1, "g") == 0)
453                 global.params.symdebug = 1;
454             else if (strcmp(p + 1, "gc") == 0)
455                 global.params.symdebug = 2;
456             else if (strcmp(p + 1, "gs") == 0)
457                 global.params.alwaysframe = true;
458             else if (strcmp(p + 1, "gx") == 0)
459                 global.params.stackstomp = true;
460             else if (strcmp(p + 1, "gt") == 0)
461             {
462                 error(Loc(), "use -profile instead of -gt");
463                 global.params.trace = true;
464             }
465             else if (strcmp(p + 1, "m32") == 0)
466             {
467                 global.params.is64bit = false;
468                 global.params.mscoff = false;
469             }
470             else if (strcmp(p + 1, "m64") == 0)
471             {
472                 global.params.is64bit = true;
473                 static if (TARGET_WINDOS)
474                 {
475                     global.params.mscoff = true;
476                 }
477             }
478             else if (strcmp(p + 1, "m32mscoff") == 0)
479             {
480                 static if (TARGET_WINDOS)
481                 {
482                     global.params.is64bit = 0;
483                     global.params.mscoff = true;
484                 }
485                 else
486                 {
487                     error(Loc(), "-m32mscoff can only be used on windows");
488                 }
489             }
490             else if (memcmp(p + 1, cast(char*)"profile", 7) == 0)
491             {
492                 // Parse:
493                 //      -profile
494                 //      -profile=gc
495                 if (p[8] == '=')
496                 {
497                     if (strcmp(p + 9, "gc") == 0)
498                         global.params.tracegc = true;
499                     else
500                         goto Lerror;
501                 }
502                 else if (p[8])
503                     goto Lerror;
504                 else
505                     global.params.trace = true;
506             }
507             else if (strcmp(p + 1, "v") == 0)
508                 global.params.verbose = true;
509             else if (strcmp(p + 1, "vtls") == 0)
510                 global.params.vtls = true;
511             else if (strcmp(p + 1, "vcolumns") == 0)
512                 global.params.showColumns = true;
513             else if (strcmp(p + 1, "vgc") == 0)
514                 global.params.vgc = true;
515             else if (memcmp(p + 1, cast(char*)"verrors", 7) == 0)
516             {
517                 if (p[8] == '=' && isdigit(cast(char)p[9]))
518                 {
519                     long num;
520                     errno = 0;
521                     num = strtol(p + 9, cast(char**)&p, 10);
522                     if (*p || errno || num > INT_MAX)
523                         goto Lerror;
524                     global.errorLimit = cast(uint)num;
525                 }
526                 else
527                     goto Lerror;
528             }
529             else if (memcmp(p + 1, cast(char*)"transition", 10) == 0)
530             {
531                 // Parse:
532                 //      -transition=number
533                 if (p[11] == '=')
534                 {
535                     if (strcmp(p + 12, "?") == 0)
536                     {
537                         printf("
538 Language changes listed by -transition=id:
539   =all           list information on all language changes
540   =checkimports  give deprecation messages about 10378 anomalies
541   =complex,14488 list all usages of complex or imaginary types
542   =field,3449    list all non-mutable fields which occupy an object instance
543   =import,10378  revert to single phase name lookup
544   =tls           list all variables going into thread local storage
545 ");
546                         exit(EXIT_SUCCESS);
547                     }
548                     if (isdigit(cast(char)p[12]))
549                     {
550                         long num;
551                         errno = 0;
552                         num = strtol(p + 12, cast(char**)&p, 10);
553                         if (*p || errno || num > INT_MAX)
554                             goto Lerror;
555                         // Bugzilla issue number
556                         switch (num)
557                         {
558                         case 3449:
559                             global.params.vfield = true;
560                             break;
561                         case 10378:
562                             global.params.bug10378 = true;
563                             break;
564                         case 14488:
565                             global.params.vcomplex = true;
566                             break;
567                         default:
568                             goto Lerror;
569                         }
570                     }
571                     else if (Identifier.isValidIdentifier(p + 12))
572                     {
573                         const ident = p + 12;
574                         switch (ident[0 .. strlen(ident)])
575                         {
576                         case "all":
577                             global.params.vtls = true;
578                             global.params.vfield = true;
579                             global.params.vcomplex = true;
580                             break;
581                         case "checkimports":
582                             global.params.check10378 = true;
583                             break;
584                         case "complex":
585                             global.params.vcomplex = true;
586                             break;
587                         case "field":
588                             global.params.vfield = true;
589                             break;
590                         case "import":
591                             global.params.bug10378 = true;
592                             break;
593                         case "tls":
594                             global.params.vtls = true;
595                             break;
596                         default:
597                             goto Lerror;
598                         }
599                     }
600                     else
601                         goto Lerror;
602                 }
603                 else
604                     goto Lerror;
605             }
606             else if (strcmp(p + 1, "w") == 0)
607                 global.params.warnings = 1;
608             else if (strcmp(p + 1, "wi") == 0)
609                 global.params.warnings = 2;
610             else if (strcmp(p + 1, "O") == 0)
611                 global.params.optimize = true;
612             else if (p[1] == 'o')
613             {
614                 const(char)* path;
615                 switch (p[2])
616                 {
617                 case '-':
618                     global.params.obj = false;
619                     break;
620                 case 'd':
621                     if (!p[3])
622                         goto Lnoarg;
623                     path = p + 3 + (p[3] == '=');
624                     version (Windows)
625                     {
626                         path = toWinPath(path);
627                     }
628                     global.params.objdir = path;
629                     break;
630                 case 'f':
631                     if (!p[3])
632                         goto Lnoarg;
633                     path = p + 3 + (p[3] == '=');
634                     version (Windows)
635                     {
636                         path = toWinPath(path);
637                     }
638                     global.params.objname = path;
639                     break;
640                 case 'p':
641                     if (p[3])
642                         goto Lerror;
643                     global.params.preservePaths = true;
644                     break;
645                 case 0:
646                     error(Loc(), "-o no longer supported, use -of or -od");
647                     break;
648                 default:
649                     goto Lerror;
650                 }
651             }
652             else if (p[1] == 'D')
653             {
654                 global.params.doDocComments = true;
655                 switch (p[2])
656                 {
657                 case 'd':
658                     if (!p[3])
659                         goto Lnoarg;
660                     global.params.docdir = p + 3 + (p[3] == '=');
661                     break;
662                 case 'f':
663                     if (!p[3])
664                         goto Lnoarg;
665                     global.params.docname = p + 3 + (p[3] == '=');
666                     break;
667                 case 0:
668                     break;
669                 default:
670                     goto Lerror;
671                 }
672             }
673             else if (p[1] == 'H')
674             {
675                 global.params.doHdrGeneration = true;
676                 switch (p[2])
677                 {
678                 case 'd':
679                     if (!p[3])
680                         goto Lnoarg;
681                     global.params.hdrdir = p + 3 + (p[3] == '=');
682                     break;
683                 case 'f':
684                     if (!p[3])
685                         goto Lnoarg;
686                     global.params.hdrname = p + 3 + (p[3] == '=');
687                     break;
688                 case 0:
689                     break;
690                 default:
691                     goto Lerror;
692                 }
693             }
694             else if (p[1] == 'X')
695             {
696                 global.params.doJsonGeneration = true;
697                 switch (p[2])
698                 {
699                 case 'f':
700                     if (!p[3])
701                         goto Lnoarg;
702                     global.params.jsonfilename = p + 3 + (p[3] == '=');
703                     break;
704                 case 0:
705                     break;
706                 default:
707                     goto Lerror;
708                 }
709             }
710             else if (strcmp(p + 1, "ignore") == 0)
711                 global.params.ignoreUnsupportedPragmas = true;
712             else if (strcmp(p + 1, "property") == 0)
713                 global.params.enforcePropertySyntax = true;
714             else if (strcmp(p + 1, "inline") == 0)
715             {
716                 global.params.useInline = true;
717                 global.params.hdrStripPlainFunctions = false;
718             }
719             else if (strcmp(p + 1, "dip25") == 0)
720                 global.params.useDIP25 = true;
721             else if (strcmp(p + 1, "lib") == 0)
722                 global.params.lib = true;
723             else if (strcmp(p + 1, "nofloat") == 0)
724                 global.params.nofloat = true;
725             else if (strcmp(p + 1, "quiet") == 0)
726             {
727                 // Ignore
728             }
729             else if (strcmp(p + 1, "release") == 0)
730                 global.params.release = true;
731             else if (strcmp(p + 1, "betterC") == 0)
732                 global.params.betterC = true;
733             else if (strcmp(p + 1, "noboundscheck") == 0)
734             {
735                 global.params.useArrayBounds = BOUNDSCHECKoff;
736             }
737             else if (memcmp(p + 1, cast(char*)"boundscheck", 11) == 0)
738             {
739                 // Parse:
740                 //      -boundscheck=[on|safeonly|off]
741                 if (p[12] == '=')
742                 {
743                     if (strcmp(p + 13, "on") == 0)
744                     {
745                         global.params.useArrayBounds = BOUNDSCHECKon;
746                     }
747                     else if (strcmp(p + 13, "safeonly") == 0)
748                     {
749                         global.params.useArrayBounds = BOUNDSCHECKsafeonly;
750                     }
751                     else if (strcmp(p + 13, "off") == 0)
752                     {
753                         global.params.useArrayBounds = BOUNDSCHECKoff;
754                     }
755                     else
756                         goto Lerror;
757                 }
758                 else
759                     goto Lerror;
760             }
761             else if (strcmp(p + 1, "unittest") == 0)
762                 global.params.useUnitTests = true;
763             else if (p[1] == 'I')
764             {
765                 if (!global.params.imppath)
766                     global.params.imppath = new Strings();
767                 global.params.imppath.push(p + 2 + (p[2] == '='));
768             }
769             else if (p[1] == 'J')
770             {
771                 if (!global.params.fileImppath)
772                     global.params.fileImppath = new Strings();
773                 global.params.fileImppath.push(p + 2 + (p[2] == '='));
774             }
775             else if (memcmp(p + 1, cast(char*)"debug", 5) == 0 && p[6] != 'l')
776             {
777                 // Parse:
778                 //      -debug
779                 //      -debug=number
780                 //      -debug=identifier
781                 if (p[6] == '=')
782                 {
783                     if (isdigit(cast(char)p[7]))
784                     {
785                         long level;
786                         errno = 0;
787                         level = strtol(p + 7, cast(char**)&p, 10);
788                         if (*p || errno || level > INT_MAX)
789                             goto Lerror;
790                         DebugCondition.setGlobalLevel(cast(int)level);
791                     }
792                     else if (Identifier.isValidIdentifier(p + 7))
793                         DebugCondition.addGlobalIdent(p[7 .. p.strlen]);
794                     else
795                         goto Lerror;
796                 }
797                 else if (p[6])
798                     goto Lerror;
799                 else
800                     DebugCondition.setGlobalLevel(1);
801             }
802             else if (memcmp(p + 1, cast(char*)"version", 7) == 0)
803             {
804                 // Parse:
805                 //      -version=number
806                 //      -version=identifier
807                 if (p[8] == '=')
808                 {
809                     if (isdigit(cast(char)p[9]))
810                     {
811                         long level;
812                         errno = 0;
813                         level = strtol(p + 9, cast(char**)&p, 10);
814                         if (*p || errno || level > INT_MAX)
815                             goto Lerror;
816                         VersionCondition.setGlobalLevel(cast(int)level);
817                     }
818                     else if (Identifier.isValidIdentifier(p + 9))
819                         VersionCondition.addGlobalIdent(p[9 .. p.strlen]);
820                     else
821                         goto Lerror;
822                 }
823                 else
824                     goto Lerror;
825             }
826             else if (strcmp(p + 1, "-b") == 0)
827                 global.params.debugb = true;
828             else if (strcmp(p + 1, "-c") == 0)
829                 global.params.debugc = true;
830             else if (strcmp(p + 1, "-f") == 0)
831                 global.params.debugf = true;
832             else if (strcmp(p + 1, "-help") == 0 || strcmp(p + 1, "h") == 0)
833             {
834                 usage();
835                 exit(EXIT_SUCCESS);
836             }
837             else if (strcmp(p + 1, "-r") == 0)
838                 global.params.debugr = true;
839             else if (strcmp(p + 1, "-version") == 0)
840             {
841                 logo();
842                 exit(EXIT_SUCCESS);
843             }
844             else if (strcmp(p + 1, "-x") == 0)
845                 global.params.debugx = true;
846             else if (strcmp(p + 1, "-y") == 0)
847                 global.params.debugy = true;
848             else if (p[1] == 'L')
849             {
850                 global.params.linkswitches.push(p + 2 + (p[2] == '='));
851             }
852             else if (memcmp(p + 1, cast(char*)"defaultlib=", 11) == 0)
853             {
854                 global.params.defaultlibname = p + 1 + 11;
855             }
856             else if (memcmp(p + 1, cast(char*)"debuglib=", 9) == 0)
857             {
858                 global.params.debuglibname = p + 1 + 9;
859             }
860             else if (memcmp(p + 1, cast(char*)"deps", 4) == 0)
861             {
862                 if (global.params.moduleDeps)
863                 {
864                     error(Loc(), "-deps[=file] can only be provided once!");
865                     break;
866                 }
867                 if (p[5] == '=')
868                 {
869                     global.params.moduleDepsFile = p + 1 + 5;
870                     if (!global.params.moduleDepsFile[0])
871                         goto Lnoarg;
872                 }
873                 else if (p[5] != '\0')
874                 {
875                     // Else output to stdout.
876                     goto Lerror;
877                 }
878                 global.params.moduleDeps = new OutBuffer();
879             }
880             else if (strcmp(p + 1, "main") == 0)
881             {
882                 global.params.addMain = true;
883             }
884             else if (memcmp(p + 1, cast(char*)"man", 3) == 0)
885             {
886                 version (Windows)
887                 {
888                     browse("http://dlang.org/dmd-windows.html");
889                 }
890                 version (linux)
891                 {
892                     browse("http://dlang.org/dmd-linux.html");
893                 }
894                 version (OSX)
895                 {
896                     browse("http://dlang.org/dmd-osx.html");
897                 }
898                 version (FreeBSD)
899                 {
900                     browse("http://dlang.org/dmd-freebsd.html");
901                 }
902                 version (OpenBSD)
903                 {
904                     browse("http://dlang.org/dmd-openbsd.html");
905                 }
906                 exit(EXIT_SUCCESS);
907             }
908             else if (strcmp(p + 1, "run") == 0)
909             {
910                 global.params.run = true;
911                 size_t length = argc - i - 1;
912                 if (length)
913                 {
914                     const(char)* ext = FileName.ext(arguments[i + 1]);
915                     if (ext && FileName.equals(ext, "d") == 0 && FileName.equals(ext, "di") == 0)
916                     {
917                         error(Loc(), "-run must be followed by a source file, not '%s'", arguments[i + 1]);
918                         break;
919                     }
920                     files.push(arguments[i + 1]);
921                     global.params.runargs.setDim(length - 1);
922                     for (size_t j = 0; j < length - 1; ++j)
923                     {
924                         global.params.runargs[j] = arguments[i + 2 + j];
925                     }
926                     i += length;
927                 }
928                 else
929                 {
930                     global.params.run = false;
931                     goto Lnoarg;
932                 }
933             }
934             else
935             {
936             Lerror:
937                 error(Loc(), "unrecognized switch '%s'", arguments[i]);
938                 continue;
939             Lnoarg:
940                 error(Loc(), "argument expected for switch '%s'", arguments[i]);
941                 continue;
942             }
943         }
944         else
945         {
946             static if (TARGET_WINDOS)
947             {
948                 const(char)* ext = FileName.ext(p);
949                 if (ext && FileName.compare(ext, "exe") == 0)
950                 {
951                     global.params.objname = p;
952                     continue;
953                 }
954                 if (strcmp(p, `/?`) == 0)
955                 {
956                     usage();
957                     exit(EXIT_SUCCESS);
958                 }
959             }
960             files.push(p);
961         }
962     }
963     if (global.params.is64bit != is64bit)
964         error(Loc(), "the architecture must not be changed in the %s section of %s", envsection.ptr, global.inifilename);
965     if (global.params.enforcePropertySyntax)
966     {
967         /*NOTE: -property used to disallow calling non-properties
968          without parentheses. This behaviour has fallen from grace.
969          Phobos dropped support for it while dmd still recognized it, so
970          that the switch has effectively not been supported. Time to
971          remove it from dmd.
972          Step 1 (2.069): Deprecate -property and ignore it. */
973         Loc loc;
974         deprecation(loc, "The -property switch is deprecated and has no " ~
975             "effect anymore.");
976         /* Step 2: Remove -property. Throw an error when it's set.
977          Do this by removing global.params.enforcePropertySyntax and the code
978          above that sets it. Let it be handled as an unrecognized switch.
979          Step 3: Possibly reintroduce -property with different semantics.
980          Any new semantics need to be decided on first. */
981     }
982     // Target uses 64bit pointers.
983     global.params.isLP64 = global.params.is64bit;
984     if (global.errors)
985     {
986         fatal();
987     }
988     if (files.dim == 0)
989     {
990         usage();
991         return EXIT_FAILURE;
992     }
993     static if (TARGET_OSX)
994     {
995         global.params.pic = 1;
996     }
997     static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS)
998     {
999         if (global.params.lib && global.params.dll)
1000             error(Loc(), "cannot mix -lib and -shared");
1001     }
1002     if (global.params.useArrayBounds == BOUNDSCHECKdefault)
1003     {
1004         // Set the real default value
1005         global.params.useArrayBounds = global.params.release ? BOUNDSCHECKsafeonly : BOUNDSCHECKon;
1006     }
1007     if (global.params.release)
1008     {
1009         global.params.useInvariants = false;
1010         global.params.useIn = false;
1011         global.params.useOut = false;
1012         global.params.useAssert = false;
1013         global.params.useSwitchError = false;
1014     }
1015     if (global.params.useUnitTests)
1016         global.params.useAssert = true;
1017     if (!global.params.obj || global.params.lib)
1018         global.params.link = false;
1019     if (global.params.link)
1020     {
1021         global.params.exefile = global.params.objname;
1022         global.params.oneobj = true;
1023         if (global.params.objname)
1024         {
1025             /* Use this to name the one object file with the same
1026              * name as the exe file.
1027              */
1028             global.params.objname = cast(char*)FileName.forceExt(global.params.objname, global.obj_ext);
1029             /* If output directory is given, use that path rather than
1030              * the exe file path.
1031              */
1032             if (global.params.objdir)
1033             {
1034                 const(char)* name = FileName.name(global.params.objname);
1035                 global.params.objname = cast(char*)FileName.combine(global.params.objdir, name);
1036             }
1037         }
1038     }
1039     else if (global.params.run)
1040     {
1041         error(Loc(), "flags conflict with -run");
1042         fatal();
1043     }
1044     else if (global.params.lib)
1045     {
1046         global.params.libname = global.params.objname;
1047         global.params.objname = null;
1048         // Haven't investigated handling these options with multiobj
1049         if (!global.params.cov && !global.params.trace)
1050             global.params.multiobj = true;
1051     }
1052     else
1053     {
1054         if (global.params.objname && files.dim > 1)
1055         {
1056             global.params.oneobj = true;
1057             //error("multiple source files, but only one .obj name");
1058             //fatal();
1059         }
1060     }
1061 
1062     // Predefined version identifiers
1063     addDefaultVersionIdentifiers();
1064     objc_tryMain_dObjc();
1065 
1066     setDefaultLibrary();
1067 
1068     // Initialization
1069     Type._init();
1070     Id.initialize();
1071     Module._init();
1072     Target._init();
1073     Expression._init();
1074     objc_tryMain_init();
1075     builtin_init();
1076 
1077     if (global.params.verbose)
1078     {
1079         fprintf(global.stdmsg, "binary    %s\n", global.params.argv0);
1080         fprintf(global.stdmsg, "version   %s\n", global._version);
1081         fprintf(global.stdmsg, "config    %s\n", global.inifilename ? global.inifilename : "(none)");
1082     }
1083     //printf("%d source files\n",files.dim);
1084     // Build import search path
1085     if (global.params.imppath)
1086     {
1087         for (size_t i = 0; i < global.params.imppath.dim; i++)
1088         {
1089             const(char)* path = (*global.params.imppath)[i];
1090             Strings* a = FileName.splitPath(path);
1091             if (a)
1092             {
1093                 if (!global.path)
1094                     global.path = new Strings();
1095                 global.path.append(a);
1096             }
1097         }
1098     }
1099     // Build string import search path
1100     if (global.params.fileImppath)
1101     {
1102         for (size_t i = 0; i < global.params.fileImppath.dim; i++)
1103         {
1104             const(char)* path = (*global.params.fileImppath)[i];
1105             Strings* a = FileName.splitPath(path);
1106             if (a)
1107             {
1108                 if (!global.filePath)
1109                     global.filePath = new Strings();
1110                 global.filePath.append(a);
1111             }
1112         }
1113     }
1114     if (global.params.addMain)
1115     {
1116         files.push(cast(char*)global.main_d); // a dummy name, we never actually look up this file
1117     }
1118     // Create Modules
1119     Modules modules;
1120     modules.reserve(files.dim);
1121     bool firstmodule = true;
1122     for (size_t i = 0; i < files.dim; i++)
1123     {
1124         const(char)* name;
1125         version (Windows)
1126         {
1127             files[i] = toWinPath(files[i]);
1128         }
1129         const(char)* p = files[i];
1130         p = FileName.name(p); // strip path
1131         const(char)* ext = FileName.ext(p);
1132         char* newname;
1133         if (ext)
1134         {
1135             /* Deduce what to do with a file based on its extension
1136              */
1137             if (FileName.equals(ext, global.obj_ext))
1138             {
1139                 global.params.objfiles.push(files[i]);
1140                 libmodules.push(files[i]);
1141                 continue;
1142             }
1143             if (FileName.equals(ext, global.lib_ext))
1144             {
1145                 global.params.libfiles.push(files[i]);
1146                 libmodules.push(files[i]);
1147                 continue;
1148             }
1149             static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS)
1150             {
1151                 if (FileName.equals(ext, global.dll_ext))
1152                 {
1153                     global.params.dllfiles.push(files[i]);
1154                     libmodules.push(files[i]);
1155                     continue;
1156                 }
1157             }
1158             if (strcmp(ext, global.ddoc_ext) == 0)
1159             {
1160                 global.params.ddocfiles.push(files[i]);
1161                 continue;
1162             }
1163             if (FileName.equals(ext, global.json_ext))
1164             {
1165                 global.params.doJsonGeneration = true;
1166                 global.params.jsonfilename = files[i];
1167                 continue;
1168             }
1169             if (FileName.equals(ext, global.map_ext))
1170             {
1171                 global.params.mapfile = files[i];
1172                 continue;
1173             }
1174             static if (TARGET_WINDOS)
1175             {
1176                 if (FileName.equals(ext, "res"))
1177                 {
1178                     global.params.resfile = files[i];
1179                     continue;
1180                 }
1181                 if (FileName.equals(ext, "def"))
1182                 {
1183                     global.params.deffile = files[i];
1184                     continue;
1185                 }
1186                 if (FileName.equals(ext, "exe"))
1187                 {
1188                     assert(0); // should have already been handled
1189                 }
1190             }
1191             /* Examine extension to see if it is a valid
1192              * D source file extension
1193              */
1194             if (FileName.equals(ext, global.mars_ext) || FileName.equals(ext, global.hdr_ext) || FileName.equals(ext, "dd"))
1195             {
1196                 ext--; // skip onto '.'
1197                 assert(*ext == '.');
1198                 newname = cast(char*)mem.xmalloc((ext - p) + 1);
1199                 memcpy(newname, p, ext - p);
1200                 newname[ext - p] = 0; // strip extension
1201                 name = newname;
1202                 if (name[0] == 0 || strcmp(name, "..") == 0 || strcmp(name, ".") == 0)
1203                 {
1204                 Linvalid:
1205                     error(Loc(), "invalid file name '%s'", files[i]);
1206                     fatal();
1207                 }
1208             }
1209             else
1210             {
1211                 error(Loc(), "unrecognized file extension %s", ext);
1212                 fatal();
1213             }
1214         }
1215         else
1216         {
1217             name = p;
1218             if (!*name)
1219                 goto Linvalid;
1220         }
1221         /* At this point, name is the D source file name stripped of
1222          * its path and extension.
1223          */
1224         auto id = Identifier.idPool(name, strlen(name));
1225         auto m = new Module(files[i], id, global.params.doDocComments, global.params.doHdrGeneration);
1226         modules.push(m);
1227         if (firstmodule)
1228         {
1229             global.params.objfiles.push(m.objfile.name.str);
1230             firstmodule = false;
1231         }
1232     }
1233     // Read files
1234     /* Start by "reading" the dummy main.d file
1235      */
1236     if (global.params.addMain)
1237     {
1238         for (size_t i = 0; 1; i++)
1239         {
1240             assert(i != modules.dim);
1241             Module m = modules[i];
1242             if (strcmp(m.srcfile.name.str, global.main_d) == 0)
1243             {
1244                 static __gshared const(char)* buf = "int main(){return 0;}";
1245                 m.srcfile.setbuffer(cast(void*)buf, buf.sizeof);
1246                 m.srcfile._ref = 1;
1247                 break;
1248             }
1249         }
1250     }
1251     enum ASYNCREAD = false;
1252     static if (ASYNCREAD)
1253     {
1254         // Multi threaded
1255         AsyncRead* aw = AsyncRead.create(modules.dim);
1256         for (size_t i = 0; i < modules.dim; i++)
1257         {
1258             Module m = modules[i];
1259             aw.addFile(m.srcfile);
1260         }
1261         aw.start();
1262     }
1263     else
1264     {
1265         // Single threaded
1266         for (size_t i = 0; i < modules.dim; i++)
1267         {
1268             Module m = modules[i];
1269             m.read(Loc());
1270         }
1271     }
1272     // Parse files
1273     bool anydocfiles = false;
1274     size_t filecount = modules.dim;
1275     for (size_t filei = 0, modi = 0; filei < filecount; filei++, modi++)
1276     {
1277         Module m = modules[modi];
1278         if (global.params.verbose)
1279             fprintf(global.stdmsg, "parse     %s\n", m.toChars());
1280         if (!Module.rootModule)
1281             Module.rootModule = m;
1282         m.importedFrom = m; // m->isRoot() == true
1283         if (!global.params.oneobj || modi == 0 || m.isDocFile)
1284             m.deleteObjFile();
1285         static if (ASYNCREAD)
1286         {
1287             if (aw.read(filei))
1288             {
1289                 error(Loc(), "cannot read file %s", m.srcfile.name.toChars());
1290                 fatal();
1291             }
1292         }
1293         m.parse();
1294         if (m.isDocFile)
1295         {
1296             anydocfiles = true;
1297             gendocfile(m);
1298             // Remove m from list of modules
1299             modules.remove(modi);
1300             modi--;
1301             // Remove m's object file from list of object files
1302             for (size_t j = 0; j < global.params.objfiles.dim; j++)
1303             {
1304                 if (m.objfile.name.str == (*global.params.objfiles)[j])
1305                 {
1306                     global.params.objfiles.remove(j);
1307                     break;
1308                 }
1309             }
1310             if (global.params.objfiles.dim == 0)
1311                 global.params.link = false;
1312         }
1313     }
1314     static if (ASYNCREAD)
1315     {
1316         AsyncRead.dispose(aw);
1317     }
1318     if (anydocfiles && modules.dim && (global.params.oneobj || global.params.objname))
1319     {
1320         error(Loc(), "conflicting Ddoc and obj generation options");
1321         fatal();
1322     }
1323     if (global.errors)
1324         fatal();
1325 
1326     if (global.params.doHdrGeneration)
1327     {
1328         /* Generate 'header' import files.
1329          * Since 'header' import files must be independent of command
1330          * line switches and what else is imported, they are generated
1331          * before any semantic analysis.
1332          */
1333         for (size_t i = 0; i < modules.dim; i++)
1334         {
1335             Module m = modules[i];
1336             if (global.params.verbose)
1337                 fprintf(global.stdmsg, "import    %s\n", m.toChars());
1338             genhdrfile(m);
1339         }
1340     }
1341     if (global.errors)
1342         fatal();
1343 
1344     // load all unconditional imports for better symbol resolving
1345     for (size_t i = 0; i < modules.dim; i++)
1346     {
1347         Module m = modules[i];
1348         if (global.params.verbose)
1349             fprintf(global.stdmsg, "importall %s\n", m.toChars());
1350         m.importAll(null);
1351     }
1352     if (global.errors)
1353         fatal();
1354 
1355     backend_init();
1356 
1357     // Do semantic analysis
1358     for (size_t i = 0; i < modules.dim; i++)
1359     {
1360         Module m = modules[i];
1361         if (global.params.verbose)
1362             fprintf(global.stdmsg, "semantic  %s\n", m.toChars());
1363         m.semantic(null);
1364     }
1365     //if (global.errors)
1366     //    fatal();
1367     Module.dprogress = 1;
1368     Module.runDeferredSemantic();
1369     if (Module.deferred.dim)
1370     {
1371         for (size_t i = 0; i < Module.deferred.dim; i++)
1372         {
1373             Dsymbol sd = Module.deferred[i];
1374             sd.error("unable to resolve forward reference in definition");
1375         }
1376         //fatal();
1377     }
1378 
1379     // Do pass 2 semantic analysis
1380     for (size_t i = 0; i < modules.dim; i++)
1381     {
1382         Module m = modules[i];
1383         if (global.params.verbose)
1384             fprintf(global.stdmsg, "semantic2 %s\n", m.toChars());
1385         m.semantic2(null);
1386     }
1387     Module.runDeferredSemantic2();
1388     if (global.errors)
1389         fatal();
1390 
1391     // Do pass 3 semantic analysis
1392     for (size_t i = 0; i < modules.dim; i++)
1393     {
1394         Module m = modules[i];
1395         if (global.params.verbose)
1396             fprintf(global.stdmsg, "semantic3 %s\n", m.toChars());
1397         m.semantic3(null);
1398     }
1399     Module.runDeferredSemantic3();
1400     if (global.errors)
1401         fatal();
1402 
1403     // Scan for functions to inline
1404     if (global.params.useInline)
1405     {
1406         for (size_t i = 0; i < modules.dim; i++)
1407         {
1408             Module m = modules[i];
1409             if (global.params.verbose)
1410                 fprintf(global.stdmsg, "inline scan %s\n", m.toChars());
1411             inlineScanModule(m);
1412         }
1413     }
1414     // Do not attempt to generate output files if errors or warnings occurred
1415     if (global.errors || global.warnings)
1416         fatal();
1417 
1418     // inlineScan incrementally run semantic3 of each expanded functions.
1419     // So deps file generation should be moved after the inlinig stage.
1420     if (global.params.moduleDeps)
1421     {
1422         OutBuffer* ob = global.params.moduleDeps;
1423         if (global.params.moduleDepsFile)
1424         {
1425             auto deps = File(global.params.moduleDepsFile);
1426             deps.setbuffer(cast(void*)ob.data, ob.offset);
1427             writeFile(Loc(), &deps);
1428         }
1429         else
1430             printf("%.*s", cast(int)ob.offset, ob.data);
1431     }
1432 
1433     printCtfePerformanceStats();
1434 
1435     Library library = null;
1436     if (global.params.lib)
1437     {
1438         library = Library.factory();
1439         library.setFilename(global.params.objdir, global.params.libname);
1440         // Add input object and input library files to output library
1441         for (size_t i = 0; i < libmodules.dim; i++)
1442         {
1443             const(char)* p = libmodules[i];
1444             library.addObject(p, null);
1445         }
1446     }
1447     // Generate output files
1448     if (global.params.doJsonGeneration)
1449     {
1450         OutBuffer buf;
1451         json_generate(&buf, &modules);
1452         // Write buf to file
1453         const(char)* name = global.params.jsonfilename;
1454         if (name && name[0] == '-' && name[1] == 0)
1455         {
1456             // Write to stdout; assume it succeeds
1457             size_t n = fwrite(buf.data, 1, buf.offset, stdout);
1458             assert(n == buf.offset); // keep gcc happy about return values
1459         }
1460         else
1461         {
1462             /* The filename generation code here should be harmonized with Module::setOutfile()
1463              */
1464             const(char)* jsonfilename;
1465             if (name && *name)
1466             {
1467                 jsonfilename = FileName.defaultExt(name, global.json_ext);
1468             }
1469             else
1470             {
1471                 // Generate json file name from first obj name
1472                 const(char)* n = (*global.params.objfiles)[0];
1473                 n = FileName.name(n);
1474                 //if (!FileName::absolute(name))
1475                 //    name = FileName::combine(dir, name);
1476                 jsonfilename = FileName.forceExt(n, global.json_ext);
1477             }
1478             ensurePathToNameExists(Loc(), jsonfilename);
1479             auto jsonfile = new File(jsonfilename);
1480             jsonfile.setbuffer(buf.data, buf.offset);
1481             jsonfile._ref = 1;
1482             writeFile(Loc(), jsonfile);
1483         }
1484     }
1485     if (!global.errors && global.params.doDocComments)
1486     {
1487         for (size_t i = 0; i < modules.dim; i++)
1488         {
1489             Module m = modules[i];
1490             gendocfile(m);
1491         }
1492     }
1493     if (!global.params.obj)
1494     {
1495     }
1496     else if (global.params.oneobj)
1497     {
1498         if (modules.dim)
1499             obj_start(cast(char*)modules[0].srcfile.toChars());
1500         for (size_t i = 0; i < modules.dim; i++)
1501         {
1502             Module m = modules[i];
1503             if (global.params.verbose)
1504                 fprintf(global.stdmsg, "code      %s\n", m.toChars());
1505             genObjFile(m, false);
1506             if (entrypoint && m == rootHasMain)
1507                 genObjFile(entrypoint, false);
1508         }
1509         if (!global.errors && modules.dim)
1510         {
1511             obj_end(library, modules[0].objfile);
1512         }
1513     }
1514     else
1515     {
1516         for (size_t i = 0; i < modules.dim; i++)
1517         {
1518             Module m = modules[i];
1519             if (global.params.verbose)
1520                 fprintf(global.stdmsg, "code      %s\n", m.toChars());
1521             obj_start(cast(char*)m.srcfile.toChars());
1522             genObjFile(m, global.params.multiobj);
1523             if (entrypoint && m == rootHasMain)
1524                 genObjFile(entrypoint, global.params.multiobj);
1525             obj_end(library, m.objfile);
1526             obj_write_deferred(library);
1527             if (global.errors && !global.params.lib)
1528                 m.deleteObjFile();
1529         }
1530     }
1531     if (global.params.lib && !global.errors)
1532         library.write();
1533     backend_term();
1534     if (global.errors)
1535         fatal();
1536     int status = EXIT_SUCCESS;
1537     if (!global.params.objfiles.dim)
1538     {
1539         if (global.params.link)
1540             error(Loc(), "no object files to link");
1541     }
1542     else
1543     {
1544         if (global.params.link)
1545             status = runLINK();
1546         if (global.params.run)
1547         {
1548             if (!status)
1549             {
1550                 status = runProgram();
1551                 /* Delete .obj files and .exe file
1552                  */
1553                 for (size_t i = 0; i < modules.dim; i++)
1554                 {
1555                     modules[i].deleteObjFile();
1556                     if (global.params.oneobj)
1557                         break;
1558                 }
1559                 remove(global.params.exefile);
1560             }
1561         }
1562     }
1563     return status;
1564 }
1565 
1566 
1567 /**
1568  * Entry point which forwards to `tryMain`.
1569  *
1570  * Returns:
1571  *   Return code of the application
1572  */
1573 int main()
1574 {
1575     import core.memory;
1576     import core.runtime;
1577 
1578     version (GC)
1579     {
1580     }
1581     else
1582     {
1583         GC.disable();
1584     }
1585     version(D_Coverage)
1586     {
1587         // for now we need to manually set the source path
1588         string dirName(string path, char separator)
1589         {
1590             for (size_t i = path.length - 1; i > 0; i--)
1591             {
1592                 if (path[i] == separator)
1593                     return path[0..i];
1594             }
1595             return path;
1596         }
1597         version (Windows)
1598             enum sourcePath = dirName(__FILE_FULL_PATH__, `\`);
1599         else
1600             enum sourcePath = dirName(__FILE_FULL_PATH__, '/');
1601 
1602         dmd_coverSourcePath(sourcePath);
1603         dmd_coverDestPath(sourcePath);
1604         dmd_coverSetMerge(true);
1605     }
1606 
1607     auto args = Runtime.cArgs();
1608     return tryMain(args.argc, cast(const(char)**)args.argv);
1609 }
1610 
1611 
1612 /**
1613  * Parses an environment variable containing command-line flags
1614  * and append them to `args`.
1615  *
1616  * This function is used to read the content of DFLAGS.
1617  * Flags are separated based on spaces and tabs.
1618  *
1619  * Params:
1620  *   envvalue = The content of an environment variable
1621  *   args     = Array to append the flags to, if any.
1622  */
1623 private void getenv_setargv(const(char)* envvalue, Strings* args)
1624 {
1625     if (!envvalue)
1626         return;
1627     char* p;
1628     int instring;
1629     int slash;
1630     char c;
1631     char* env = mem.xstrdup(envvalue); // create our own writable copy
1632     //printf("env = '%s'\n", env);
1633     while (1)
1634     {
1635         switch (*env)
1636         {
1637         case ' ':
1638         case '\t':
1639             env++;
1640             break;
1641         case 0:
1642             return;
1643         default:
1644             args.push(env); // append
1645             p = env;
1646             slash = 0;
1647             instring = 0;
1648             c = 0;
1649             while (1)
1650             {
1651                 c = *env++;
1652                 switch (c)
1653                 {
1654                 case '"':
1655                     p -= (slash >> 1);
1656                     if (slash & 1)
1657                     {
1658                         p--;
1659                         goto Laddc;
1660                     }
1661                     instring ^= 1;
1662                     slash = 0;
1663                     continue;
1664                 case ' ':
1665                 case '\t':
1666                     if (instring)
1667                         goto Laddc;
1668                     *p = 0;
1669                     //if (wildcard)
1670                     //    wildcardexpand();     // not implemented
1671                     break;
1672                 case '\\':
1673                     slash++;
1674                     *p++ = c;
1675                     continue;
1676                 case 0:
1677                     *p = 0;
1678                     //if (wildcard)
1679                     //    wildcardexpand();     // not implemented
1680                     return;
1681                 default:
1682                 Laddc:
1683                     slash = 0;
1684                     *p++ = c;
1685                     continue;
1686                 }
1687                 break;
1688             }
1689         }
1690     }
1691 }
1692 
1693 /**
1694  * Parse command line arguments for -m32 or -m64
1695  * to detect the desired architecture.
1696  *
1697  * Params:
1698  *   args = Command line arguments
1699  *   arch = Default value to use for architecture.
1700  *          Should be "32" or "64"
1701  *
1702  * Returns:
1703  *   "32", "64" or "32mscoff" if the "-m32", "-m64", "-m32mscoff" flags were passed,
1704  *   respectively. If they weren't, return `arch`.
1705  */
1706 private const(char)* parse_arch_arg(Strings* args, const(char)* arch)
1707 {
1708     for (size_t i = 0; i < args.dim; ++i)
1709     {
1710         const(char)* p = (*args)[i];
1711         if (p[0] == '-')
1712         {
1713             if (strcmp(p + 1, "m32") == 0 || strcmp(p + 1, "m32mscoff") == 0 || strcmp(p + 1, "m64") == 0)
1714                 arch = p + 2;
1715             else if (strcmp(p + 1, "run") == 0)
1716                 break;
1717         }
1718     }
1719     return arch;
1720 }
1721 
1722 
1723 /**
1724  * Parse command line arguments for -conf=path.
1725  *
1726  * Params:
1727  *   args = Command line arguments
1728  *
1729  * Returns:
1730  *   Path to the config file to use
1731  */
1732 private const(char)* parse_conf_arg(Strings* args)
1733 {
1734     const(char)* conf = null;
1735     for (size_t i = 0; i < args.dim; ++i)
1736     {
1737         const(char)* p = (*args)[i];
1738         if (p[0] == '-')
1739         {
1740             if (strncmp(p + 1, "conf=", 5) == 0)
1741                 conf = p + 6;
1742             else if (strcmp(p + 1, "run") == 0)
1743                 break;
1744         }
1745     }
1746     return conf;
1747 }
1748 
1749 
1750 /**
1751  * Helper function used by the glue layer
1752  *
1753  * Returns:
1754  *   A new array of Dsymbol
1755  */
1756 extern (C++) Dsymbols* Dsymbols_create()
1757 {
1758     return new Dsymbols();
1759 }
1760 
1761 
1762 /**
1763  * Helper function used by the glue layer
1764  *
1765  * Returns:
1766  *   A new array of VarDeclaration
1767  */
1768 extern (C++) VarDeclarations* VarDeclarations_create()
1769 {
1770     return new VarDeclarations();
1771 }
1772 
1773 
1774 /**
1775  * Helper function used by the glue layer
1776  *
1777  * Returns:
1778  *   A new array of Expression
1779  */
1780 extern (C++) Expressions* Expressions_create()
1781 {
1782     return new Expressions();
1783 }
1784 
1785 /**
1786  * Set the default and debug libraries to link against, if not already set
1787  *
1788  * Must be called after argument parsing is done, as it won't
1789  * override any value.
1790  * Note that if `-defaultlib=` or `-debuglib=` was used,
1791  * we don't override that either.
1792  */
1793 private void setDefaultLibrary()
1794 {
1795     if (global.params.defaultlibname is null)
1796     {
1797         static if (TARGET_WINDOS)
1798         {
1799             if (global.params.is64bit)
1800                 global.params.defaultlibname = "phobos64";
1801             else if (global.params.mscoff)
1802                 global.params.defaultlibname = "phobos32mscoff";
1803             else
1804                 global.params.defaultlibname = "phobos";
1805         }
1806         else static if (TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS)
1807         {
1808             global.params.defaultlibname = "libphobos2.a";
1809         }
1810         else static if (TARGET_OSX)
1811         {
1812             global.params.defaultlibname = "phobos2";
1813         }
1814         else
1815         {
1816             static assert(0, "fix this");
1817         }
1818     }
1819     if (global.params.debuglibname is null)
1820         global.params.debuglibname = global.params.defaultlibname;
1821 }
1822 
1823 
1824 /**
1825  * Add default `version` identifier for ddmd, and set the
1826  * target platform in `global`.
1827  *
1828  * Needs to be run after all arguments parsing (command line, DFLAGS environment
1829  * variable and config file) in order to add final flags (such as `X86_64` or
1830  * the `CRuntime` used).
1831  */
1832 private void addDefaultVersionIdentifiers()
1833 {
1834     VersionCondition.addPredefinedGlobalIdent("DigitalMars");
1835     static if (TARGET_WINDOS)
1836     {
1837         VersionCondition.addPredefinedGlobalIdent("Windows");
1838         global.params.isWindows = true;
1839     }
1840     else static if (TARGET_LINUX)
1841     {
1842         VersionCondition.addPredefinedGlobalIdent("Posix");
1843         VersionCondition.addPredefinedGlobalIdent("linux");
1844         VersionCondition.addPredefinedGlobalIdent("ELFv1");
1845         global.params.isLinux = true;
1846     }
1847     else static if (TARGET_OSX)
1848     {
1849         VersionCondition.addPredefinedGlobalIdent("Posix");
1850         VersionCondition.addPredefinedGlobalIdent("OSX");
1851         global.params.isOSX = true;
1852         // For legacy compatibility
1853         VersionCondition.addPredefinedGlobalIdent("darwin");
1854     }
1855     else static if (TARGET_FREEBSD)
1856     {
1857         VersionCondition.addPredefinedGlobalIdent("Posix");
1858         VersionCondition.addPredefinedGlobalIdent("FreeBSD");
1859         VersionCondition.addPredefinedGlobalIdent("ELFv1");
1860         global.params.isFreeBSD = true;
1861     }
1862     else static if (TARGET_OPENBSD)
1863     {
1864         VersionCondition.addPredefinedGlobalIdent("Posix");
1865         VersionCondition.addPredefinedGlobalIdent("OpenBSD");
1866         VersionCondition.addPredefinedGlobalIdent("ELFv1");
1867         global.params.isOpenBSD = true;
1868     }
1869     else static if (TARGET_SOLARIS)
1870     {
1871         VersionCondition.addPredefinedGlobalIdent("Posix");
1872         VersionCondition.addPredefinedGlobalIdent("Solaris");
1873         VersionCondition.addPredefinedGlobalIdent("ELFv1");
1874         global.params.isSolaris = true;
1875     }
1876     else
1877     {
1878         static assert(0, "fix this");
1879     }
1880     VersionCondition.addPredefinedGlobalIdent("LittleEndian");
1881     VersionCondition.addPredefinedGlobalIdent("D_Version2");
1882     VersionCondition.addPredefinedGlobalIdent("all");
1883 
1884     if (global.params.is64bit)
1885     {
1886         VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86_64");
1887         VersionCondition.addPredefinedGlobalIdent("X86_64");
1888         VersionCondition.addPredefinedGlobalIdent("D_SIMD");
1889         static if (TARGET_WINDOS)
1890         {
1891             VersionCondition.addPredefinedGlobalIdent("Win64");
1892         }
1893     }
1894     else
1895     {
1896         VersionCondition.addPredefinedGlobalIdent("D_InlineAsm"); //legacy
1897         VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86");
1898         VersionCondition.addPredefinedGlobalIdent("X86");
1899         static if (TARGET_OSX)
1900         {
1901             VersionCondition.addPredefinedGlobalIdent("D_SIMD");
1902         }
1903         static if (TARGET_WINDOS)
1904         {
1905             VersionCondition.addPredefinedGlobalIdent("Win32");
1906         }
1907     }
1908     static if (TARGET_WINDOS)
1909     {
1910         if (global.params.mscoff)
1911             VersionCondition.addPredefinedGlobalIdent("CRuntime_Microsoft");
1912         else
1913             VersionCondition.addPredefinedGlobalIdent("CRuntime_DigitalMars");
1914     }
1915     else static if (TARGET_LINUX)
1916     {
1917         VersionCondition.addPredefinedGlobalIdent("CRuntime_Glibc");
1918     }
1919 
1920     if (global.params.isLP64)
1921         VersionCondition.addPredefinedGlobalIdent("D_LP64");
1922     if (global.params.doDocComments)
1923         VersionCondition.addPredefinedGlobalIdent("D_Ddoc");
1924     if (global.params.cov)
1925         VersionCondition.addPredefinedGlobalIdent("D_Coverage");
1926     if (global.params.pic)
1927         VersionCondition.addPredefinedGlobalIdent("D_PIC");
1928     if (global.params.useUnitTests)
1929         VersionCondition.addPredefinedGlobalIdent("unittest");
1930     if (global.params.useAssert)
1931         VersionCondition.addPredefinedGlobalIdent("assert");
1932     if (global.params.useArrayBounds == BOUNDSCHECKoff)
1933         VersionCondition.addPredefinedGlobalIdent("D_NoBoundsChecks");
1934     VersionCondition.addPredefinedGlobalIdent("D_HardFloat");
1935 }