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, §ions); 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, §ions); 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 }