1 /** 2 * Entry point for DMD. 3 * 4 * This modules defines the entry point (main) for DMD, as well as related 5 * utilities needed for arguments parsing, path manipulation, etc... 6 * This file is not shared with other compilers which use the DMD front-end. 7 * 8 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved 9 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 10 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 11 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mars.d, _mars.d) 12 * Documentation: https://dlang.org/phobos/dmd_mars.html 13 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mars.d 14 */ 15 16 module dmd.mars; 17 18 import core.stdc.ctype; 19 import core.stdc.limits; 20 import core.stdc.stdio; 21 import core.stdc.stdlib; 22 import core.stdc.string; 23 24 import dmd.arraytypes; 25 import dmd.astcodegen; 26 import dmd.gluelayer; 27 import dmd.builtin; 28 import dmd.cond; 29 import dmd.console; 30 import dmd.compiler; 31 import dmd.dinifile; 32 import dmd.dinterpret; 33 import dmd.dmodule; 34 import dmd.doc; 35 import dmd.dsymbol; 36 import dmd.dsymbolsem; 37 import dmd.dtemplate; 38 import dmd.dtoh; 39 import dmd.errors; 40 import dmd.expression; 41 import dmd.globals; 42 import dmd.hdrgen; 43 import dmd.id; 44 import dmd.identifier; 45 import dmd.inline; 46 import dmd.json; 47 version (NoMain) {} else 48 { 49 import dmd.lib; 50 import dmd.link; 51 import dmd.vsoptions; 52 } 53 import dmd.mtype; 54 import dmd.objc; 55 import dmd.root.array; 56 import dmd.root.file; 57 import dmd.root.filename; 58 import dmd.root.man; 59 import dmd.root.outbuffer; 60 import dmd.root.response; 61 import dmd.root.rmem; 62 import dmd.root.string; 63 import dmd.root.stringtable; 64 import dmd.semantic2; 65 import dmd.semantic3; 66 import dmd.target; 67 import dmd.utils; 68 69 /** 70 * Print DMD's logo on stdout 71 */ 72 private void logo() 73 { 74 printf("DMD%llu D Compiler %.*s\n%.*s %.*s\n", 75 cast(ulong)size_t.sizeof * 8, 76 cast(int) global.versionString().length, global.versionString().ptr, 77 cast(int)global.copyright.length, global.copyright.ptr, 78 cast(int)global.written.length, global.written.ptr 79 ); 80 } 81 82 /** 83 Print DMD's logo with more debug information and error-reporting pointers. 84 85 Params: 86 stream = output stream to print the information on 87 */ 88 extern(C) void printInternalFailure(FILE* stream) 89 { 90 fputs(("---\n" ~ 91 "ERROR: This is a compiler bug.\n" ~ 92 "Please report it via https://issues.dlang.org/enter_bug.cgi\n" ~ 93 "with, preferably, a reduced, reproducible example and the information below.\n" ~ 94 "DustMite (https://github.com/CyberShadow/DustMite/wiki) can help with the reduction.\n" ~ 95 "---\n").ptr, stream); 96 stream.fprintf("DMD %.*s\n", cast(int) global.versionString().length, global.versionString().ptr); 97 stream.printPredefinedVersions; 98 stream.printGlobalConfigs(); 99 fputs("---\n".ptr, stream); 100 } 101 102 /** 103 * Print DMD's usage message on stdout 104 */ 105 private void usage() 106 { 107 import dmd.cli : CLIUsage; 108 logo(); 109 auto help = CLIUsage.usage; 110 const inifileCanon = FileName.canonicalName(global.inifilename); 111 printf(" 112 Documentation: https://dlang.org/ 113 Config file: %.*s 114 Usage: 115 dmd [<option>...] <file>... 116 dmd [<option>...] -run <file> [<arg>...] 117 118 Where: 119 <file> D source file 120 <arg> Argument to pass when running the resulting program 121 122 <option>: 123 @<cmdfile> read arguments from cmdfile 124 %.*s", cast(int)inifileCanon.length, inifileCanon.ptr, cast(int)help.length, &help[0]); 125 } 126 127 /** 128 * DMD's real entry point 129 * 130 * Parses command line arguments and config file, open and read all 131 * provided source file and do semantic analysis on them. 132 * 133 * Params: 134 * argc = Number of arguments passed via command line 135 * argv = Array of string arguments passed via command line 136 * 137 * Returns: 138 * Application return code 139 */ 140 version (NoMain) {} else 141 private int tryMain(size_t argc, const(char)** argv, ref Param params) 142 { 143 Strings files; 144 Strings libmodules; 145 global._init(); 146 // Check for malformed input 147 if (argc < 1 || !argv) 148 { 149 Largs: 150 error(Loc.initial, "missing or null command line arguments"); 151 fatal(); 152 } 153 // Convert argc/argv into arguments[] for easier handling 154 Strings arguments = Strings(argc); 155 for (size_t i = 0; i < argc; i++) 156 { 157 if (!argv[i]) 158 goto Largs; 159 arguments[i] = argv[i]; 160 } 161 if (!responseExpand(arguments)) // expand response files 162 error(Loc.initial, "can't open response file"); 163 //for (size_t i = 0; i < arguments.dim; ++i) printf("arguments[%d] = '%s'\n", i, arguments[i]); 164 files.reserve(arguments.dim - 1); 165 // Set default values 166 params.argv0 = arguments[0].toDString; 167 168 // Temporary: Use 32 bits OMF as the default on Windows, for config parsing 169 static if (TARGET.Windows) 170 { 171 params.is64bit = false; 172 params.mscoff = false; 173 } 174 175 global.inifilename = parse_conf_arg(&arguments); 176 if (global.inifilename) 177 { 178 // can be empty as in -conf= 179 if (global.inifilename.length && !FileName.exists(global.inifilename)) 180 error(Loc.initial, "Config file '%.*s' does not exist.", 181 cast(int)global.inifilename.length, global.inifilename.ptr); 182 } 183 else 184 { 185 version (Windows) 186 { 187 global.inifilename = findConfFile(params.argv0, "sc.ini"); 188 } 189 else version (Posix) 190 { 191 global.inifilename = findConfFile(params.argv0, "dmd.conf"); 192 } 193 else 194 { 195 static assert(0, "fix this"); 196 } 197 } 198 // Read the configuration file 199 const iniReadResult = global.inifilename.toCStringThen!(fn => File.read(fn.ptr)); 200 const inifileBuffer = iniReadResult.buffer.data; 201 /* Need path of configuration file, for use in expanding @P macro 202 */ 203 const(char)[] inifilepath = FileName.path(global.inifilename); 204 Strings sections; 205 StringTable!(char*) environment; 206 environment._init(7); 207 /* Read the [Environment] section, so we can later 208 * pick up any DFLAGS settings. 209 */ 210 sections.push("Environment"); 211 parseConfFile(environment, global.inifilename, inifilepath, inifileBuffer, §ions); 212 213 const(char)[] arch = params.is64bit ? "64" : "32"; // use default 214 arch = parse_arch_arg(&arguments, arch); 215 216 // parse architecture from DFLAGS read from [Environment] section 217 { 218 Strings dflags; 219 getenv_setargv(readFromEnv(environment, "DFLAGS"), &dflags); 220 environment.reset(7); // erase cached environment updates 221 arch = parse_arch_arg(&dflags, arch); 222 } 223 224 bool is64bit = arch[0] == '6'; 225 226 version(Windows) // delete LIB entry in [Environment] (necessary for optlink) to allow inheriting environment for MS-COFF 227 if (is64bit || arch == "32mscoff") 228 environment.update("LIB", 3).value = null; 229 230 // read from DFLAGS in [Environment{arch}] section 231 char[80] envsection = void; 232 sprintf(envsection.ptr, "Environment%.*s", cast(int) arch.length, arch.ptr); 233 sections.push(envsection.ptr); 234 parseConfFile(environment, global.inifilename, inifilepath, inifileBuffer, §ions); 235 getenv_setargv(readFromEnv(environment, "DFLAGS"), &arguments); 236 updateRealEnvironment(environment); 237 environment.reset(1); // don't need environment cache any more 238 239 if (parseCommandLine(arguments, argc, params, files)) 240 { 241 Loc loc; 242 errorSupplemental(loc, "run `dmd` to print the compiler manual"); 243 errorSupplemental(loc, "run `dmd -man` to open browser on manual"); 244 return EXIT_FAILURE; 245 } 246 247 if (params.usage) 248 { 249 usage(); 250 return EXIT_SUCCESS; 251 } 252 253 if (params.logo) 254 { 255 logo(); 256 return EXIT_SUCCESS; 257 } 258 259 /* 260 Prints a supplied usage text to the console and 261 returns the exit code for the help usage page. 262 263 Returns: 264 `EXIT_SUCCESS` if no errors occurred, `EXIT_FAILURE` otherwise 265 */ 266 static int printHelpUsage(string help) 267 { 268 printf("%.*s", cast(int)help.length, &help[0]); 269 return global.errors ? EXIT_FAILURE : EXIT_SUCCESS; 270 } 271 272 /* 273 Generates code to check for all `params` whether any usage page 274 has been requested. 275 If so, the generated code will print the help page of the flag 276 and return with an exit code. 277 278 Params: 279 params = parameters with `Usage` suffices in `params` for which 280 their truthness should be checked. 281 282 Returns: generated code for checking the usage pages of the provided `params`. 283 */ 284 static string generateUsageChecks(string[] params) 285 { 286 string s; 287 foreach (n; params) 288 { 289 s ~= q{ 290 if (params..}~n~q{Usage) 291 return printHelpUsage(CLIUsage..}~n~q{Usage); 292 }; 293 } 294 return s; 295 } 296 import dmd.cli : CLIUsage; 297 mixin(generateUsageChecks(["mcpu", "transition", "check", "checkAction", 298 "preview", "revert", "externStd", "hc"])); 299 300 if (params.manual) 301 { 302 version (Windows) 303 { 304 browse("http://dlang.org/dmd-windows.html"); 305 } 306 version (linux) 307 { 308 browse("http://dlang.org/dmd-linux.html"); 309 } 310 version (OSX) 311 { 312 browse("http://dlang.org/dmd-osx.html"); 313 } 314 version (FreeBSD) 315 { 316 browse("http://dlang.org/dmd-freebsd.html"); 317 } 318 /*NOTE: No regular builds for openbsd/dragonflybsd (yet) */ 319 /* 320 version (OpenBSD) 321 { 322 browse("http://dlang.org/dmd-openbsd.html"); 323 } 324 version (DragonFlyBSD) 325 { 326 browse("http://dlang.org/dmd-dragonflybsd.html"); 327 } 328 */ 329 return EXIT_SUCCESS; 330 } 331 332 if (params.color) 333 global.console = Console.create(core.stdc.stdio.stderr); 334 335 setTarget(params); // set target operating system 336 setTargetCPU(params); 337 if (params.is64bit != is64bit) 338 error(Loc.initial, "the architecture must not be changed in the %s section of %.*s", 339 envsection.ptr, cast(int)global.inifilename.length, global.inifilename.ptr); 340 341 if (global.errors) 342 { 343 fatal(); 344 } 345 if (files.dim == 0) 346 { 347 if (params.jsonFieldFlags) 348 { 349 generateJson(null); 350 return EXIT_SUCCESS; 351 } 352 usage(); 353 return EXIT_FAILURE; 354 } 355 356 reconcileCommands(params, files.dim); 357 358 // Add in command line versions 359 if (params.versionids) 360 foreach (charz; *params.versionids) 361 VersionCondition.addGlobalIdent(charz.toDString()); 362 if (params.debugids) 363 foreach (charz; *params.debugids) 364 DebugCondition.addGlobalIdent(charz.toDString()); 365 366 setTarget(params); 367 368 // Predefined version identifiers 369 addDefaultVersionIdentifiers(params); 370 371 setDefaultLibrary(); 372 373 // Initialization 374 Type._init(); 375 Id.initialize(); 376 Module._init(); 377 target._init(params); 378 Expression._init(); 379 Objc._init(); 380 import dmd.filecache : FileCache; 381 FileCache._init(); 382 383 version(CRuntime_Microsoft) 384 { 385 import dmd.root.longdouble; 386 initFPU(); 387 } 388 import dmd.root.ctfloat : CTFloat; 389 CTFloat.initialize(); 390 391 if (params.verbose) 392 { 393 stdout.printPredefinedVersions(); 394 stdout.printGlobalConfigs(); 395 } 396 //printf("%d source files\n",files.dim); 397 398 // Build import search path 399 400 static Strings* buildPath(Strings* imppath) 401 { 402 Strings* result = null; 403 if (imppath) 404 { 405 foreach (const path; *imppath) 406 { 407 Strings* a = FileName.splitPath(path); 408 if (a) 409 { 410 if (!result) 411 result = new Strings(); 412 result.append(a); 413 } 414 } 415 } 416 return result; 417 } 418 419 if (params.mixinFile) 420 { 421 params.mixinOut = cast(OutBuffer*)Mem.check(calloc(1, OutBuffer.sizeof)); 422 atexit(&flushMixins); // see comment for flushMixins 423 } 424 scope(exit) flushMixins(); 425 global.path = buildPath(params.imppath); 426 global.filePath = buildPath(params.fileImppath); 427 428 if (params.addMain) 429 files.push("__main.d"); 430 // Create Modules 431 Modules modules = createModules(files, libmodules); 432 // Read files 433 // Start by "reading" the special files (__main.d, __stdin.d) 434 foreach (m; modules) 435 { 436 if (params.addMain && m.srcfile.toString() == "__main.d") 437 { 438 auto data = arraydup("int main(){return 0;}\0\0\0\0"); // need 2 trailing nulls for sentinel and 2 for lexer 439 m.srcBuffer = new FileBuffer(cast(ubyte[]) data[0 .. $-4]); 440 } 441 else if (m.srcfile.toString() == "__stdin.d") 442 { 443 auto buffer = readFromStdin(); 444 m.srcBuffer = new FileBuffer(buffer.extractSlice()); 445 } 446 } 447 448 foreach (m; modules) 449 { 450 m.read(Loc.initial); 451 } 452 453 // Parse files 454 bool anydocfiles = false; 455 size_t filecount = modules.dim; 456 for (size_t filei = 0, modi = 0; filei < filecount; filei++, modi++) 457 { 458 Module m = modules[modi]; 459 if (params.verbose) 460 message("parse %s", m.toChars()); 461 if (!Module.rootModule) 462 Module.rootModule = m; 463 m.importedFrom = m; // m.isRoot() == true 464 if (!params.oneobj || modi == 0 || m.isDocFile) 465 m.deleteObjFile(); 466 467 m.parse(); 468 if (m.isHdrFile) 469 { 470 // Remove m's object file from list of object files 471 for (size_t j = 0; j < params.objfiles.length; j++) 472 { 473 if (m.objfile.toChars() == params.objfiles[j]) 474 { 475 params.objfiles.remove(j); 476 break; 477 } 478 } 479 if (params.objfiles.length == 0) 480 params.link = false; 481 } 482 if (m.isDocFile) 483 { 484 anydocfiles = true; 485 gendocfile(m); 486 // Remove m from list of modules 487 modules.remove(modi); 488 modi--; 489 // Remove m's object file from list of object files 490 for (size_t j = 0; j < params.objfiles.length; j++) 491 { 492 if (m.objfile.toChars() == params.objfiles[j]) 493 { 494 params.objfiles.remove(j); 495 break; 496 } 497 } 498 if (params.objfiles.length == 0) 499 params.link = false; 500 } 501 } 502 503 if (anydocfiles && modules.dim && (params.oneobj || params.objname)) 504 { 505 error(Loc.initial, "conflicting Ddoc and obj generation options"); 506 fatal(); 507 } 508 if (global.errors) 509 fatal(); 510 511 if (params.doHdrGeneration) 512 { 513 /* Generate 'header' import files. 514 * Since 'header' import files must be independent of command 515 * line switches and what else is imported, they are generated 516 * before any semantic analysis. 517 */ 518 foreach (m; modules) 519 { 520 if (m.isHdrFile) 521 continue; 522 if (params.verbose) 523 message("import %s", m.toChars()); 524 genhdrfile(m); 525 } 526 } 527 if (global.errors) 528 removeHdrFilesAndFail(params, modules); 529 530 // load all unconditional imports for better symbol resolving 531 foreach (m; modules) 532 { 533 if (params.verbose) 534 message("importall %s", m.toChars()); 535 m.importAll(null); 536 } 537 if (global.errors) 538 removeHdrFilesAndFail(params, modules); 539 540 backend_init(); 541 542 // Do semantic analysis 543 foreach (m; modules) 544 { 545 if (params.verbose) 546 message("semantic %s", m.toChars()); 547 m.dsymbolSemantic(null); 548 } 549 //if (global.errors) 550 // fatal(); 551 Module.dprogress = 1; 552 Module.runDeferredSemantic(); 553 if (Module.deferred.dim) 554 { 555 for (size_t i = 0; i < Module.deferred.dim; i++) 556 { 557 Dsymbol sd = Module.deferred[i]; 558 sd.error("unable to resolve forward reference in definition"); 559 } 560 //fatal(); 561 } 562 563 // Do pass 2 semantic analysis 564 foreach (m; modules) 565 { 566 if (params.verbose) 567 message("semantic2 %s", m.toChars()); 568 m.semantic2(null); 569 } 570 Module.runDeferredSemantic2(); 571 if (global.errors) 572 removeHdrFilesAndFail(params, modules); 573 574 // Do pass 3 semantic analysis 575 foreach (m; modules) 576 { 577 if (params.verbose) 578 message("semantic3 %s", m.toChars()); 579 m.semantic3(null); 580 } 581 if (includeImports) 582 { 583 // Note: DO NOT USE foreach here because Module.amodules.dim can 584 // change on each iteration of the loop 585 for (size_t i = 0; i < compiledImports.dim; i++) 586 { 587 auto m = compiledImports[i]; 588 assert(m.isRoot); 589 if (params.verbose) 590 message("semantic3 %s", m.toChars()); 591 m.semantic3(null); 592 modules.push(m); 593 } 594 } 595 Module.runDeferredSemantic3(); 596 if (global.errors) 597 removeHdrFilesAndFail(params, modules); 598 599 // Scan for functions to inline 600 foreach (m; modules) 601 { 602 if (params.useInline || m.hasAlwaysInlines) 603 { 604 if (params.verbose) 605 message("inline scan %s", m.toChars()); 606 inlineScanModule(m); 607 } 608 } 609 610 // Do not attempt to generate output files if errors or warnings occurred 611 if (global.errors || global.warnings) 612 removeHdrFilesAndFail(params, modules); 613 614 // inlineScan incrementally run semantic3 of each expanded functions. 615 // So deps file generation should be moved after the inlining stage. 616 if (OutBuffer* ob = params.moduleDeps) 617 { 618 foreach (i; 1 .. modules[0].aimports.dim) 619 semantic3OnDependencies(modules[0].aimports[i]); 620 Module.runDeferredSemantic3(); 621 622 const data = (*ob)[]; 623 if (params.moduleDepsFile) 624 writeFile(Loc.initial, params.moduleDepsFile, data); 625 else 626 printf("%.*s", cast(int)data.length, data.ptr); 627 } 628 629 printCtfePerformanceStats(); 630 printTemplateStats(); 631 632 Library library = null; 633 if (params.lib) 634 { 635 if (params.objfiles.length == 0) 636 { 637 error(Loc.initial, "no input files"); 638 return EXIT_FAILURE; 639 } 640 library = Library.factory(); 641 library.setFilename(params.objdir, params.libname); 642 // Add input object and input library files to output library 643 foreach (p; libmodules) 644 library.addObject(p.toDString(), null); 645 } 646 // Generate output files 647 if (params.doJsonGeneration) 648 { 649 generateJson(&modules); 650 } 651 if (!global.errors && params.doDocComments) 652 { 653 foreach (m; modules) 654 { 655 gendocfile(m); 656 } 657 } 658 if (params.vcg_ast) 659 { 660 import dmd.hdrgen; 661 foreach (mod; modules) 662 { 663 auto buf = OutBuffer(); 664 buf.doindent = 1; 665 moduleToBuffer(&buf, mod); 666 667 // write the output to $(filename).cg 668 auto cgFilename = FileName.addExt(mod.srcfile.toString(), "cg"); 669 File.write(cgFilename.ptr, buf[]); 670 } 671 } 672 673 if (global.params.doCxxHdrGeneration) 674 genCppHdrFiles(modules); 675 676 if (global.errors) 677 fatal(); 678 679 if (!params.obj) 680 { 681 } 682 else if (params.oneobj) 683 { 684 Module firstm; // first module we generate code for 685 foreach (m; modules) 686 { 687 if (m.isHdrFile) 688 continue; 689 if (!firstm) 690 { 691 firstm = m; 692 obj_start(m.srcfile.toChars()); 693 } 694 if (params.verbose) 695 message("code %s", m.toChars()); 696 genObjFile(m, false); 697 } 698 if (!global.errors && firstm) 699 { 700 obj_end(library, firstm.objfile.toChars()); 701 } 702 } 703 else 704 { 705 foreach (m; modules) 706 { 707 if (m.isHdrFile) 708 continue; 709 if (params.verbose) 710 message("code %s", m.toChars()); 711 obj_start(m.srcfile.toChars()); 712 genObjFile(m, params.multiobj); 713 obj_end(library, m.objfile.toChars()); 714 obj_write_deferred(library); 715 if (global.errors && !params.lib) 716 m.deleteObjFile(); 717 } 718 } 719 if (params.lib && !global.errors) 720 library.write(); 721 backend_term(); 722 if (global.errors) 723 fatal(); 724 int status = EXIT_SUCCESS; 725 if (!params.objfiles.length) 726 { 727 if (params.link) 728 error(Loc.initial, "no object files to link"); 729 } 730 else 731 { 732 if (params.link) 733 status = runLINK(); 734 if (params.run) 735 { 736 if (!status) 737 { 738 status = runProgram(); 739 /* Delete .obj files and .exe file 740 */ 741 foreach (m; modules) 742 { 743 m.deleteObjFile(); 744 if (params.oneobj) 745 break; 746 } 747 params.exefile.toCStringThen!(ef => File.remove(ef.ptr)); 748 } 749 } 750 } 751 if (global.errors || global.warnings) 752 removeHdrFilesAndFail(params, modules); 753 754 return status; 755 } 756 757 private FileBuffer readFromStdin() 758 { 759 enum bufIncrement = 128 * 1024; 760 size_t pos = 0; 761 size_t sz = bufIncrement; 762 763 ubyte* buffer = null; 764 for (;;) 765 { 766 buffer = cast(ubyte*)mem.xrealloc(buffer, sz + 4); // +2 for sentinel and +2 for lexer 767 768 // Fill up buffer 769 do 770 { 771 assert(sz > pos); 772 size_t rlen = fread(buffer + pos, 1, sz - pos, stdin); 773 pos += rlen; 774 if (ferror(stdin)) 775 { 776 import core.stdc.errno; 777 error(Loc.initial, "cannot read from stdin, errno = %d", errno); 778 fatal(); 779 } 780 if (feof(stdin)) 781 { 782 // We're done 783 assert(pos < sz + 2); 784 buffer[pos] = '\0'; 785 buffer[pos + 1] = '\0'; 786 buffer[pos + 2] = '\0'; 787 buffer[pos + 3] = '\0'; 788 return FileBuffer(buffer[0 .. pos]); 789 } 790 } while (pos < sz); 791 792 // Buffer full, expand 793 sz += bufIncrement; 794 } 795 796 assert(0); 797 } 798 799 extern (C++) void generateJson(Modules* modules) 800 { 801 OutBuffer buf; 802 json_generate(&buf, modules); 803 804 // Write buf to file 805 const(char)[] name = global.params.jsonfilename; 806 if (name == "-") 807 { 808 // Write to stdout; assume it succeeds 809 size_t n = fwrite(buf[].ptr, 1, buf.length, stdout); 810 assert(n == buf.length); // keep gcc happy about return values 811 } 812 else 813 { 814 /* The filename generation code here should be harmonized with Module.setOutfilename() 815 */ 816 const(char)[] jsonfilename; 817 if (name) 818 { 819 jsonfilename = FileName.defaultExt(name, global.json_ext); 820 } 821 else 822 { 823 if (global.params.objfiles.length == 0) 824 { 825 error(Loc.initial, "cannot determine JSON filename, use `-Xf=<file>` or provide a source file"); 826 fatal(); 827 } 828 // Generate json file name from first obj name 829 const(char)[] n = global.params.objfiles[0].toDString; 830 n = FileName.name(n); 831 //if (!FileName::absolute(name)) 832 // name = FileName::combine(dir, name); 833 jsonfilename = FileName.forceExt(n, global.json_ext); 834 } 835 writeFile(Loc.initial, jsonfilename, buf[]); 836 } 837 } 838 839 version (DigitalMars) 840 { 841 private void installMemErrHandler() 842 { 843 // (only available on some platforms on DMD) 844 const shouldDoMemoryError = getenv("DMD_INSTALL_MEMERR_HANDLER"); 845 if (shouldDoMemoryError !is null && *shouldDoMemoryError == '1') 846 { 847 import etc.linux.memoryerror; 848 static if (is(typeof(registerMemoryErrorHandler()))) 849 { 850 registerMemoryErrorHandler(); 851 } 852 else 853 { 854 printf("**WARNING** Memory error handler not supported on this platform!\n"); 855 } 856 } 857 } 858 } 859 860 version (NoMain) 861 { 862 version (DigitalMars) 863 { 864 shared static this() 865 { 866 installMemErrHandler(); 867 } 868 } 869 } 870 else 871 { 872 // in druntime: 873 alias MainFunc = extern(C) int function(char[][] args); 874 extern (C) int _d_run_main(int argc, char** argv, MainFunc dMain); 875 876 877 // When using a C main, host DMD may not link against host druntime by default. 878 version (DigitalMars) 879 { 880 version (Win64) 881 pragma(lib, "phobos64"); 882 else version (Win32) 883 { 884 version (CRuntime_Microsoft) 885 pragma(lib, "phobos32mscoff"); 886 else 887 pragma(lib, "phobos"); 888 } 889 } 890 891 extern extern(C) __gshared string[] rt_options; 892 893 /** 894 * DMD's entry point, C main. 895 * 896 * Without `-lowmem`, we need to switch to the bump-pointer allocation scheme 897 * right from the start, before any module ctors are run, so we need this hook 898 * before druntime is initialized and `_Dmain` is called. 899 * 900 * Returns: 901 * Return code of the application 902 */ 903 extern (C) int main(int argc, char** argv) 904 { 905 static if (isGCAvailable) 906 { 907 bool lowmem = false; 908 foreach (i; 1 .. argc) 909 { 910 if (strcmp(argv[i], "-lowmem") == 0) 911 { 912 lowmem = true; 913 break; 914 } 915 } 916 if (!lowmem) 917 { 918 __gshared string[] disable_options = [ "gcopt=disable:1" ]; 919 rt_options = disable_options; 920 mem.disableGC(); 921 } 922 } 923 924 // initialize druntime and call _Dmain() below 925 return _d_run_main(argc, argv, &_Dmain); 926 } 927 928 /** 929 * Manual D main (for druntime initialization), which forwards to `tryMain`. 930 * 931 * Returns: 932 * Return code of the application 933 */ 934 extern (C) int _Dmain(char[][]) 935 { 936 // possibly install memory error handler 937 version (DigitalMars) 938 { 939 installMemErrHandler(); 940 } 941 942 import core.runtime; 943 import core.memory; 944 static if (!isGCAvailable) 945 GC.disable(); 946 947 version(D_Coverage) 948 { 949 // for now we need to manually set the source path 950 string dirName(string path, char separator) 951 { 952 for (size_t i = path.length - 1; i > 0; i--) 953 { 954 if (path[i] == separator) 955 return path[0..i]; 956 } 957 return path; 958 } 959 version (Windows) 960 enum sourcePath = dirName(dirName(dirName(__FILE_FULL_PATH__, '\\'), '\\'), '\\'); 961 else 962 enum sourcePath = dirName(dirName(dirName(__FILE_FULL_PATH__, '/'), '/'), '/'); 963 964 dmd_coverSourcePath(sourcePath); 965 dmd_coverDestPath(sourcePath); 966 dmd_coverSetMerge(true); 967 } 968 969 scope(failure) stderr.printInternalFailure; 970 971 auto args = Runtime.cArgs(); 972 return tryMain(args.argc, cast(const(char)**)args.argv, global.params); 973 } 974 } // !NoMain 975 976 /** 977 * Parses an environment variable containing command-line flags 978 * and append them to `args`. 979 * 980 * This function is used to read the content of DFLAGS. 981 * Flags are separated based on spaces and tabs. 982 * 983 * Params: 984 * envvalue = The content of an environment variable 985 * args = Array to append the flags to, if any. 986 */ 987 void getenv_setargv(const(char)* envvalue, Strings* args) 988 { 989 if (!envvalue) 990 return; 991 992 char* env = mem.xstrdup(envvalue); // create our own writable copy 993 //printf("env = '%s'\n", env); 994 while (1) 995 { 996 switch (*env) 997 { 998 case ' ': 999 case '\t': 1000 env++; 1001 break; 1002 1003 case 0: 1004 return; 1005 1006 default: 1007 { 1008 args.push(env); // append 1009 auto p = env; 1010 auto slash = 0; 1011 bool instring = false; 1012 while (1) 1013 { 1014 auto c = *env++; 1015 switch (c) 1016 { 1017 case '"': 1018 p -= (slash >> 1); 1019 if (slash & 1) 1020 { 1021 p--; 1022 goto default; 1023 } 1024 instring ^= true; 1025 slash = 0; 1026 continue; 1027 1028 case ' ': 1029 case '\t': 1030 if (instring) 1031 goto default; 1032 *p = 0; 1033 //if (wildcard) 1034 // wildcardexpand(); // not implemented 1035 break; 1036 1037 case '\\': 1038 slash++; 1039 *p++ = c; 1040 continue; 1041 1042 case 0: 1043 *p = 0; 1044 //if (wildcard) 1045 // wildcardexpand(); // not implemented 1046 return; 1047 1048 default: 1049 slash = 0; 1050 *p++ = c; 1051 continue; 1052 } 1053 break; 1054 } 1055 break; 1056 } 1057 } 1058 } 1059 } 1060 1061 /** 1062 * Parse command line arguments for the last instance of -m32, -m64 or -m32mscoff 1063 * to detect the desired architecture. 1064 * 1065 * Params: 1066 * args = Command line arguments 1067 * arch = Default value to use for architecture. 1068 * Should be "32" or "64" 1069 * 1070 * Returns: 1071 * "32", "64" or "32mscoff" if the "-m32", "-m64", "-m32mscoff" flags were passed, 1072 * respectively. If they weren't, return `arch`. 1073 */ 1074 const(char)[] parse_arch_arg(Strings* args, const(char)[] arch) 1075 { 1076 foreach (const p; *args) 1077 { 1078 const(char)[] arg = p.toDString; 1079 1080 if (arg.length && arg[0] == '-') 1081 { 1082 if (arg[1 .. $] == "m32" || arg[1 .. $] == "m32mscoff" || arg[1 .. $] == "m64") 1083 arch = arg[2 .. $]; 1084 else if (arg[1 .. $] == "run") 1085 break; 1086 } 1087 } 1088 return arch; 1089 } 1090 1091 1092 /** 1093 * Parse command line arguments for the last instance of -conf=path. 1094 * 1095 * Params: 1096 * args = Command line arguments 1097 * 1098 * Returns: 1099 * The 'path' in -conf=path, which is the path to the config file to use 1100 */ 1101 const(char)[] parse_conf_arg(Strings* args) 1102 { 1103 const(char)[] conf; 1104 foreach (const p; *args) 1105 { 1106 const(char)[] arg = p.toDString; 1107 if (arg.length && arg[0] == '-') 1108 { 1109 if(arg.length >= 6 && arg[1 .. 6] == "conf="){ 1110 conf = arg[6 .. $]; 1111 } 1112 else if (arg[1 .. $] == "run") 1113 break; 1114 } 1115 } 1116 return conf; 1117 } 1118 1119 1120 /** 1121 * Set the default and debug libraries to link against, if not already set 1122 * 1123 * Must be called after argument parsing is done, as it won't 1124 * override any value. 1125 * Note that if `-defaultlib=` or `-debuglib=` was used, 1126 * we don't override that either. 1127 */ 1128 private void setDefaultLibrary() 1129 { 1130 if (global.params.defaultlibname is null) 1131 { 1132 static if (TARGET.Windows) 1133 { 1134 if (global.params.is64bit) 1135 global.params.defaultlibname = "phobos64"; 1136 else if (global.params.mscoff) 1137 global.params.defaultlibname = "phobos32mscoff"; 1138 else 1139 global.params.defaultlibname = "phobos"; 1140 } 1141 else static if (TARGET.Linux || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) 1142 { 1143 global.params.defaultlibname = "libphobos2.a"; 1144 } 1145 else static if (TARGET.OSX) 1146 { 1147 global.params.defaultlibname = "phobos2"; 1148 } 1149 else 1150 { 1151 static assert(0, "fix this"); 1152 } 1153 } 1154 else if (!global.params.defaultlibname.length) // if `-defaultlib=` (i.e. an empty defaultlib) 1155 global.params.defaultlibname = null; 1156 1157 if (global.params.debuglibname is null) 1158 global.params.debuglibname = global.params.defaultlibname; 1159 } 1160 1161 /************************************* 1162 * Set the `is` target fields of `params` according 1163 * to the TARGET value. 1164 * Params: 1165 * params = where the `is` fields are 1166 */ 1167 void setTarget(ref Param params) 1168 { 1169 static if (TARGET.Windows) 1170 params.isWindows = true; 1171 else static if (TARGET.Linux) 1172 params.isLinux = true; 1173 else static if (TARGET.OSX) 1174 params.isOSX = true; 1175 else static if (TARGET.FreeBSD) 1176 params.isFreeBSD = true; 1177 else static if (TARGET.OpenBSD) 1178 params.isOpenBSD = true; 1179 else static if (TARGET.Solaris) 1180 params.isSolaris = true; 1181 else static if (TARGET.DragonFlyBSD) 1182 params.isDragonFlyBSD = true; 1183 else 1184 static assert(0, "unknown TARGET"); 1185 } 1186 1187 /** 1188 * Add default `version` identifier for dmd, and set the 1189 * target platform in `params`. 1190 * https://dlang.org/spec/version.html#predefined-versions 1191 * 1192 * Needs to be run after all arguments parsing (command line, DFLAGS environment 1193 * variable and config file) in order to add final flags (such as `X86_64` or 1194 * the `CRuntime` used). 1195 * 1196 * Params: 1197 * params = which target to compile for (set by `setTarget()`) 1198 */ 1199 void addDefaultVersionIdentifiers(const ref Param params) 1200 { 1201 VersionCondition.addPredefinedGlobalIdent("DigitalMars"); 1202 if (params.isWindows) 1203 { 1204 VersionCondition.addPredefinedGlobalIdent("Windows"); 1205 if (global.params.mscoff) 1206 { 1207 VersionCondition.addPredefinedGlobalIdent("CRuntime_Microsoft"); 1208 VersionCondition.addPredefinedGlobalIdent("CppRuntime_Microsoft"); 1209 } 1210 else 1211 { 1212 VersionCondition.addPredefinedGlobalIdent("CRuntime_DigitalMars"); 1213 VersionCondition.addPredefinedGlobalIdent("CppRuntime_DigitalMars"); 1214 } 1215 } 1216 else if (params.isLinux) 1217 { 1218 VersionCondition.addPredefinedGlobalIdent("Posix"); 1219 VersionCondition.addPredefinedGlobalIdent("linux"); 1220 VersionCondition.addPredefinedGlobalIdent("ELFv1"); 1221 // Note: This should be done with a target triplet, to support cross compilation. 1222 // However DMD currently does not support it, so this is a simple 1223 // fix to make DMD compile on Musl-based systems such as Alpine. 1224 // See https://github.com/dlang/dmd/pull/8020 1225 // And https://wiki.osdev.org/Target_Triplet 1226 version (CRuntime_Musl) 1227 VersionCondition.addPredefinedGlobalIdent("CRuntime_Musl"); 1228 else 1229 VersionCondition.addPredefinedGlobalIdent("CRuntime_Glibc"); 1230 VersionCondition.addPredefinedGlobalIdent("CppRuntime_Gcc"); 1231 } 1232 else if (params.isOSX) 1233 { 1234 VersionCondition.addPredefinedGlobalIdent("Posix"); 1235 VersionCondition.addPredefinedGlobalIdent("OSX"); 1236 VersionCondition.addPredefinedGlobalIdent("CppRuntime_Clang"); 1237 // For legacy compatibility 1238 VersionCondition.addPredefinedGlobalIdent("darwin"); 1239 } 1240 else if (params.isFreeBSD) 1241 { 1242 VersionCondition.addPredefinedGlobalIdent("Posix"); 1243 VersionCondition.addPredefinedGlobalIdent("FreeBSD"); 1244 VersionCondition.addPredefinedGlobalIdent("ELFv1"); 1245 VersionCondition.addPredefinedGlobalIdent("CppRuntime_Clang"); 1246 } 1247 else if (params.isOpenBSD) 1248 { 1249 VersionCondition.addPredefinedGlobalIdent("Posix"); 1250 VersionCondition.addPredefinedGlobalIdent("OpenBSD"); 1251 VersionCondition.addPredefinedGlobalIdent("ELFv1"); 1252 VersionCondition.addPredefinedGlobalIdent("CppRuntime_Gcc"); 1253 } 1254 else if (params.isDragonFlyBSD) 1255 { 1256 VersionCondition.addPredefinedGlobalIdent("Posix"); 1257 VersionCondition.addPredefinedGlobalIdent("DragonFlyBSD"); 1258 VersionCondition.addPredefinedGlobalIdent("ELFv1"); 1259 VersionCondition.addPredefinedGlobalIdent("CppRuntime_Gcc"); 1260 } 1261 else if (params.isSolaris) 1262 { 1263 VersionCondition.addPredefinedGlobalIdent("Posix"); 1264 VersionCondition.addPredefinedGlobalIdent("Solaris"); 1265 VersionCondition.addPredefinedGlobalIdent("ELFv1"); 1266 VersionCondition.addPredefinedGlobalIdent("CppRuntime_Sun"); 1267 } 1268 else 1269 { 1270 assert(0); 1271 } 1272 VersionCondition.addPredefinedGlobalIdent("LittleEndian"); 1273 VersionCondition.addPredefinedGlobalIdent("D_Version2"); 1274 VersionCondition.addPredefinedGlobalIdent("all"); 1275 1276 if (params.cpu >= CPU.sse2) 1277 { 1278 VersionCondition.addPredefinedGlobalIdent("D_SIMD"); 1279 if (params.cpu >= CPU.avx) 1280 VersionCondition.addPredefinedGlobalIdent("D_AVX"); 1281 if (params.cpu >= CPU.avx2) 1282 VersionCondition.addPredefinedGlobalIdent("D_AVX2"); 1283 } 1284 1285 if (params.is64bit) 1286 { 1287 VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86_64"); 1288 VersionCondition.addPredefinedGlobalIdent("X86_64"); 1289 if (params.isWindows) 1290 { 1291 VersionCondition.addPredefinedGlobalIdent("Win64"); 1292 } 1293 } 1294 else 1295 { 1296 VersionCondition.addPredefinedGlobalIdent("D_InlineAsm"); //legacy 1297 VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86"); 1298 VersionCondition.addPredefinedGlobalIdent("X86"); 1299 if (params.isWindows) 1300 { 1301 VersionCondition.addPredefinedGlobalIdent("Win32"); 1302 } 1303 } 1304 1305 if (params.isLP64) 1306 VersionCondition.addPredefinedGlobalIdent("D_LP64"); 1307 if (params.doDocComments) 1308 VersionCondition.addPredefinedGlobalIdent("D_Ddoc"); 1309 if (params.cov) 1310 VersionCondition.addPredefinedGlobalIdent("D_Coverage"); 1311 if (params.pic != PIC.fixed) 1312 VersionCondition.addPredefinedGlobalIdent(params.pic == PIC.pic ? "D_PIC" : "D_PIE"); 1313 if (params.useUnitTests) 1314 VersionCondition.addPredefinedGlobalIdent("unittest"); 1315 if (params.useAssert == CHECKENABLE.on) 1316 VersionCondition.addPredefinedGlobalIdent("assert"); 1317 if (params.useArrayBounds == CHECKENABLE.off) 1318 VersionCondition.addPredefinedGlobalIdent("D_NoBoundsChecks"); 1319 if (params.betterC) 1320 { 1321 VersionCondition.addPredefinedGlobalIdent("D_BetterC"); 1322 } 1323 else 1324 { 1325 VersionCondition.addPredefinedGlobalIdent("D_ModuleInfo"); 1326 VersionCondition.addPredefinedGlobalIdent("D_Exceptions"); 1327 VersionCondition.addPredefinedGlobalIdent("D_TypeInfo"); 1328 } 1329 1330 VersionCondition.addPredefinedGlobalIdent("D_HardFloat"); 1331 } 1332 1333 private void printPredefinedVersions(FILE* stream) 1334 { 1335 if (global.versionids) 1336 { 1337 OutBuffer buf; 1338 foreach (const str; *global.versionids) 1339 { 1340 buf.writeByte(' '); 1341 buf.writestring(str.toChars()); 1342 } 1343 stream.fprintf("predefs %s\n", buf.peekChars()); 1344 } 1345 } 1346 1347 extern(C) void printGlobalConfigs(FILE* stream) 1348 { 1349 stream.fprintf("binary %.*s\n", cast(int)global.params.argv0.length, global.params.argv0.ptr); 1350 stream.fprintf("version %.*s\n", cast(int) global.versionString().length, global.versionString().ptr); 1351 const iniOutput = global.inifilename ? global.inifilename : "(none)"; 1352 stream.fprintf("config %.*s\n", cast(int)iniOutput.length, iniOutput.ptr); 1353 // Print DFLAGS environment variable 1354 { 1355 StringTable!(char*) environment; 1356 environment._init(0); 1357 Strings dflags; 1358 getenv_setargv(readFromEnv(environment, "DFLAGS"), &dflags); 1359 environment.reset(1); 1360 OutBuffer buf; 1361 foreach (flag; dflags[]) 1362 { 1363 bool needsQuoting; 1364 foreach (c; flag.toDString()) 1365 { 1366 if (!(isalnum(c) || c == '_')) 1367 { 1368 needsQuoting = true; 1369 break; 1370 } 1371 } 1372 1373 if (flag.strchr(' ')) 1374 buf.printf("'%s' ", flag); 1375 else 1376 buf.printf("%s ", flag); 1377 } 1378 1379 auto res = buf[] ? buf[][0 .. $ - 1] : "(none)"; 1380 stream.fprintf("DFLAGS %.*s\n", cast(int)res.length, res.ptr); 1381 } 1382 } 1383 1384 /**************************************** 1385 * Determine the instruction set to be used, i.e. set params.cpu 1386 * by combining the command line setting of 1387 * params.cpu with the target operating system. 1388 * Params: 1389 * params = parameters set by command line switch 1390 */ 1391 1392 private void setTargetCPU(ref Param params) 1393 { 1394 if (target.isXmmSupported()) 1395 { 1396 switch (params.cpu) 1397 { 1398 case CPU.baseline: 1399 params.cpu = CPU.sse2; 1400 break; 1401 1402 case CPU.native: 1403 { 1404 import core.cpuid; 1405 params.cpu = core.cpuid.avx2 ? CPU.avx2 : 1406 core.cpuid.avx ? CPU.avx : 1407 CPU.sse2; 1408 break; 1409 } 1410 1411 default: 1412 break; 1413 } 1414 } 1415 else 1416 params.cpu = CPU.x87; // cannot support other instruction sets 1417 } 1418 1419 /************************************** 1420 * we want to write the mixin expansion file also on error, but there 1421 * are too many ways to terminate dmd (e.g. fatal() which calls exit(EXIT_FAILURE)), 1422 * so we can't rely on scope(exit) ... in tryMain() actually being executed 1423 * so we add atexit(&flushMixins); for those fatal exits (with the GC still valid) 1424 */ 1425 extern(C) void flushMixins() 1426 { 1427 if (!global.params.mixinOut) 1428 return; 1429 1430 assert(global.params.mixinFile); 1431 File.write(global.params.mixinFile, (*global.params.mixinOut)[]); 1432 1433 global.params.mixinOut.destroy(); 1434 global.params.mixinOut = null; 1435 } 1436 1437 /**************************************************** 1438 * Parse command line arguments. 1439 * 1440 * Prints message(s) if there are errors. 1441 * 1442 * Params: 1443 * arguments = command line arguments 1444 * argc = argument count 1445 * params = set to result of parsing `arguments` 1446 * files = set to files pulled from `arguments` 1447 * Returns: 1448 * true if errors in command line 1449 */ 1450 1451 bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param params, ref Strings files) 1452 { 1453 bool errors; 1454 1455 void error(Args ...)(const(char)* format, Args args) 1456 { 1457 dmd.errors.error(Loc.initial, format, args); 1458 errors = true; 1459 } 1460 1461 /** 1462 * Print an error messsage about an invalid switch. 1463 * If an optional supplemental message has been provided, 1464 * it will be printed too. 1465 * 1466 * Params: 1467 * p = 0 terminated string 1468 * availableOptions = supplemental help message listing the available options 1469 */ 1470 void errorInvalidSwitch(const(char)* p, string availableOptions = null) 1471 { 1472 error("Switch `%s` is invalid", p); 1473 if (availableOptions !is null) 1474 errorSupplemental(Loc.initial, "%.*s", cast(int)availableOptions.length, availableOptions.ptr); 1475 } 1476 1477 enum CheckOptions { success, error, help } 1478 1479 /* 1480 Checks whether the CLI options contains a valid argument or a help argument. 1481 If a help argument has been used, it will set the `usageFlag`. 1482 1483 Params: 1484 p = string as a D array 1485 usageFlag = parameter for the usage help page to set (by `ref`) 1486 missingMsg = error message to use when no argument has been provided 1487 1488 Returns: 1489 `success` if a valid argument has been passed and it's not a help page 1490 `error` if an error occurred (e.g. `-foobar`) 1491 `help` if a help page has been request (e.g. `-flag` or `-flag=h`) 1492 */ 1493 CheckOptions checkOptions(const(char)[] p, ref bool usageFlag, string missingMsg) 1494 { 1495 // Checks whether a flag has no options (e.g. -foo or -foo=) 1496 if (p.length == 0 || p == "=") 1497 { 1498 .error(Loc.initial, "%.*s", cast(int)missingMsg.length, missingMsg.ptr); 1499 errors = true; 1500 usageFlag = true; 1501 return CheckOptions.help; 1502 } 1503 if (p[0] != '=') 1504 return CheckOptions.error; 1505 p = p[1 .. $]; 1506 /* Checks whether the option pointer supplied is a request 1507 for the help page, e.g. -foo=j */ 1508 if ((p == "h" || p == "?") || // -flag=h || -flag=? 1509 p == "help") 1510 { 1511 usageFlag = true; 1512 return CheckOptions.help; 1513 } 1514 return CheckOptions.success; 1515 } 1516 1517 static string checkOptionsMixin(string usageFlag, string missingMsg) 1518 { 1519 return q{ 1520 final switch (checkOptions(arg[len - 1 .. $], params..}~usageFlag~","~ 1521 `"`~missingMsg~`"`~q{)) 1522 { 1523 case CheckOptions.error: 1524 goto Lerror; 1525 case CheckOptions.help: 1526 return false; 1527 case CheckOptions.success: 1528 break; 1529 } 1530 }; 1531 } 1532 1533 import dmd.cli : Usage; 1534 bool parseCLIOption(string name, Usage.Feature[] features)(ref Param params, const(char)[] p) 1535 { 1536 // Parse: 1537 // -<name>=<feature> 1538 const(char)[] ps = p[name.length + 1 .. $]; 1539 const(char)[] ident = ps[1 .. $]; 1540 if (Identifier.isValidIdentifier(ident)) 1541 { 1542 string generateTransitionsText() 1543 { 1544 import dmd.cli : Usage; 1545 string buf = `case "all":`; 1546 foreach (t; features) 1547 { 1548 if (t.deprecated_) 1549 continue; 1550 1551 buf ~= `params.`~t.paramName~` = true;`; 1552 } 1553 buf ~= "return true;\n"; 1554 1555 foreach (t; features) 1556 { 1557 buf ~= `case "`~t.name~`":`; 1558 if (t.deprecated_) 1559 buf ~= "deprecation(Loc.initial, \"`-"~name~"="~t.name~"` no longer has any effect.\"); "; 1560 buf ~= `params.`~t.paramName~` = true; return true;`; 1561 } 1562 return buf; 1563 } 1564 1565 switch (ident) 1566 { 1567 mixin(generateTransitionsText()); 1568 default: 1569 return false; 1570 } 1571 } 1572 return false; 1573 } 1574 1575 version (none) 1576 { 1577 for (size_t i = 0; i < arguments.dim; i++) 1578 { 1579 printf("arguments[%d] = '%s'\n", i, arguments[i]); 1580 } 1581 } 1582 for (size_t i = 1; i < arguments.dim; i++) 1583 { 1584 const(char)* p = arguments[i]; 1585 const(char)[] arg = p.toDString(); 1586 if (*p != '-') 1587 { 1588 static if (TARGET.Windows) 1589 { 1590 const ext = FileName.ext(arg); 1591 if (ext.length && FileName.equals(ext, "exe")) 1592 { 1593 params.objname = arg; 1594 continue; 1595 } 1596 if (arg == "/?") 1597 { 1598 params.usage = true; 1599 return false; 1600 } 1601 } 1602 files.push(p); 1603 continue; 1604 } 1605 1606 if (arg == "-allinst") // https://dlang.org/dmd.html#switch-allinst 1607 params.allInst = true; 1608 else if (arg == "-de") // https://dlang.org/dmd.html#switch-de 1609 params.useDeprecated = DiagnosticReporting.error; 1610 else if (arg == "-d") // https://dlang.org/dmd.html#switch-d 1611 params.useDeprecated = DiagnosticReporting.off; 1612 else if (arg == "-dw") // https://dlang.org/dmd.html#switch-dw 1613 params.useDeprecated = DiagnosticReporting.inform; 1614 else if (arg == "-c") // https://dlang.org/dmd.html#switch-c 1615 params.link = false; 1616 else if (startsWith(p + 1, "checkaction")) // https://dlang.org/dmd.html#switch-checkaction 1617 { 1618 /* Parse: 1619 * -checkaction=D|C|halt|context 1620 */ 1621 enum len = "-checkaction=".length; 1622 mixin(checkOptionsMixin("checkActionUsage", 1623 "`-check=<behavior>` requires a behavior")); 1624 switch (arg[len .. $]) 1625 { 1626 case "D": 1627 params.checkAction = CHECKACTION.D; 1628 break; 1629 case "C": 1630 params.checkAction = CHECKACTION.C; 1631 break; 1632 case "halt": 1633 params.checkAction = CHECKACTION.halt; 1634 break; 1635 case "context": 1636 params.checkAction = CHECKACTION.context; 1637 break; 1638 default: 1639 errorInvalidSwitch(p); 1640 params.checkActionUsage = true; 1641 return false; 1642 } 1643 } 1644 else if (startsWith(p + 1, "check")) // https://dlang.org/dmd.html#switch-check 1645 { 1646 enum len = "-check=".length; 1647 mixin(checkOptionsMixin("checkUsage", 1648 "`-check=<action>` requires an action")); 1649 /* Parse: 1650 * -check=[assert|bounds|in|invariant|out|switch][=[on|off]] 1651 */ 1652 1653 // Check for legal option string; return true if so 1654 static bool check(const(char)[] checkarg, string name, ref CHECKENABLE ce) 1655 { 1656 if (checkarg.length >= name.length && 1657 checkarg[0 .. name.length] == name) 1658 { 1659 checkarg = checkarg[name.length .. $]; 1660 1661 if (checkarg.length == 0 || 1662 checkarg == "=on") 1663 { 1664 ce = CHECKENABLE.on; 1665 return true; 1666 } 1667 else if (checkarg == "=off") 1668 { 1669 ce = CHECKENABLE.off; 1670 return true; 1671 } 1672 } 1673 return false; 1674 } 1675 1676 const(char)[] checkarg = arg[len .. $]; 1677 if (!(check(checkarg, "assert", params.useAssert ) || 1678 check(checkarg, "bounds", params.useArrayBounds) || 1679 check(checkarg, "in", params.useIn ) || 1680 check(checkarg, "invariant", params.useInvariants ) || 1681 check(checkarg, "out", params.useOut ) || 1682 check(checkarg, "switch", params.useSwitchError))) 1683 { 1684 errorInvalidSwitch(p); 1685 params.checkUsage = true; 1686 return false; 1687 } 1688 } 1689 else if (startsWith(p + 1, "color")) // https://dlang.org/dmd.html#switch-color 1690 { 1691 // Parse: 1692 // -color 1693 // -color=auto|on|off 1694 if (p[6] == '=') 1695 { 1696 switch(arg[7 .. $]) 1697 { 1698 case "on": 1699 params.color = true; 1700 break; 1701 case "off": 1702 params.color = false; 1703 break; 1704 case "auto": 1705 break; 1706 default: 1707 errorInvalidSwitch(p, "Available options for `-color` are `on`, `off` and `auto`"); 1708 return true; 1709 } 1710 } 1711 else if (p[6]) 1712 goto Lerror; 1713 else 1714 params.color = true; 1715 } 1716 else if (startsWith(p + 1, "conf=")) // https://dlang.org/dmd.html#switch-conf 1717 { 1718 // ignore, already handled above 1719 } 1720 else if (startsWith(p + 1, "cov")) // https://dlang.org/dmd.html#switch-cov 1721 { 1722 params.cov = true; 1723 // Parse: 1724 // -cov 1725 // -cov=ctfe 1726 // -cov=nnn 1727 if (arg == "-cov=ctfe") 1728 { 1729 params.ctfe_cov = true; 1730 } 1731 else if (p[4] == '=') 1732 { 1733 if (!params.covPercent.parseDigits(p.toDString()[5 .. $], 100)) 1734 { 1735 errorInvalidSwitch(p, "Only a number between 0 and 100 can be passed to `-cov=<num>`"); 1736 return true; 1737 } 1738 } 1739 else if (p[4]) 1740 goto Lerror; 1741 } 1742 else if (arg == "-shared") 1743 params.dll = true; 1744 else if (arg == "-fPIC") 1745 { 1746 static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) 1747 { 1748 params.pic = PIC.pic; 1749 } 1750 else 1751 { 1752 goto Lerror; 1753 } 1754 } 1755 else if (arg == "-fPIE") 1756 { 1757 static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) 1758 { 1759 params.pic = PIC.pie; 1760 } 1761 else 1762 { 1763 goto Lerror; 1764 } 1765 } 1766 else if (arg == "-map") // https://dlang.org/dmd.html#switch-map 1767 params.map = true; 1768 else if (arg == "-multiobj") 1769 params.multiobj = true; 1770 else if (startsWith(p + 1, "mixin=")) 1771 { 1772 auto tmp = p + 6 + 1; 1773 if (!tmp[0]) 1774 goto Lnoarg; 1775 params.mixinFile = mem.xstrdup(tmp); 1776 } 1777 else if (arg == "-g") // https://dlang.org/dmd.html#switch-g 1778 params.symdebug = 1; 1779 else if (arg == "-gf") 1780 { 1781 if (!params.symdebug) 1782 params.symdebug = 1; 1783 params.symdebugref = true; 1784 } 1785 else if (arg == "-gs") // https://dlang.org/dmd.html#switch-gs 1786 params.alwaysframe = true; 1787 else if (arg == "-gx") // https://dlang.org/dmd.html#switch-gx 1788 params.stackstomp = true; 1789 else if (arg == "-lowmem") // https://dlang.org/dmd.html#switch-lowmem 1790 { 1791 static if (isGCAvailable) 1792 { 1793 // ignore, already handled in C main 1794 } 1795 else 1796 { 1797 error("switch '%s' requires DMD to be built with '-version=GC'", arg.ptr); 1798 continue; 1799 } 1800 } 1801 else if (arg.length > 6 && arg[0..6] == "--DRT-") 1802 { 1803 continue; // skip druntime options, e.g. used to configure the GC 1804 } 1805 else if (arg == "-m32") // https://dlang.org/dmd.html#switch-m32 1806 { 1807 static if (TARGET.DragonFlyBSD) { 1808 error("-m32 is not supported on DragonFlyBSD, it is 64-bit only"); 1809 } else { 1810 params.is64bit = false; 1811 params.mscoff = false; 1812 } 1813 } 1814 else if (arg == "-m64") // https://dlang.org/dmd.html#switch-m64 1815 { 1816 params.is64bit = true; 1817 static if (TARGET.Windows) 1818 { 1819 params.mscoff = true; 1820 } 1821 } 1822 else if (arg == "-m32mscoff") // https://dlang.org/dmd.html#switch-m32mscoff 1823 { 1824 static if (TARGET.Windows) 1825 { 1826 params.is64bit = 0; 1827 params.mscoff = true; 1828 } 1829 else 1830 { 1831 error("-m32mscoff can only be used on windows"); 1832 } 1833 } 1834 else if (startsWith(p + 1, "mscrtlib=")) 1835 { 1836 static if (TARGET.Windows) 1837 { 1838 params.mscrtlib = arg[10 .. $]; 1839 } 1840 else 1841 { 1842 error("-mscrtlib"); 1843 } 1844 } 1845 else if (startsWith(p + 1, "profile")) // https://dlang.org/dmd.html#switch-profile 1846 { 1847 // Parse: 1848 // -profile 1849 // -profile=gc 1850 if (p[8] == '=') 1851 { 1852 if (arg[9 .. $] == "gc") 1853 params.tracegc = true; 1854 else 1855 { 1856 errorInvalidSwitch(p, "Only `gc` is allowed for `-profile`"); 1857 return true; 1858 } 1859 } 1860 else if (p[8]) 1861 goto Lerror; 1862 else 1863 params.trace = true; 1864 } 1865 else if (arg == "-v") // https://dlang.org/dmd.html#switch-v 1866 params.verbose = true; 1867 else if (arg == "-vcg-ast") 1868 params.vcg_ast = true; 1869 else if (arg == "-vtls") // https://dlang.org/dmd.html#switch-vtls 1870 params.vtls = true; 1871 else if (startsWith(p + 1, "vtemplates")) // https://dlang.org/dmd.html#switch-vtemplates 1872 { 1873 params.vtemplates = true; 1874 if (p[1 + "vtemplates".length] == '=') 1875 { 1876 const(char)[] style = arg[1 + "vtemplates=".length .. $]; 1877 switch (style) 1878 { 1879 case "list-instances": 1880 params.vtemplatesListInstances = true; 1881 break; 1882 default: 1883 error("unknown vtemplates style '%.*s', must be 'list-instances'", cast(int) style.length, style.ptr); 1884 } 1885 } 1886 } 1887 else if (arg == "-vcolumns") // https://dlang.org/dmd.html#switch-vcolumns 1888 params.showColumns = true; 1889 else if (arg == "-vgc") // https://dlang.org/dmd.html#switch-vgc 1890 params.vgc = true; 1891 else if (startsWith(p + 1, "verrors")) // https://dlang.org/dmd.html#switch-verrors 1892 { 1893 if (p[8] != '=') 1894 { 1895 errorInvalidSwitch(p, "Expected argument following `-verrors , e.g. `-verrors=100`"); 1896 return true; 1897 } 1898 if (startsWith(p + 9, "spec")) 1899 { 1900 params.showGaggedErrors = true; 1901 } 1902 else if (startsWith(p + 9, "context")) 1903 { 1904 params.printErrorContext = true; 1905 } 1906 else if (!params.errorLimit.parseDigits(p.toDString()[9 .. $])) 1907 { 1908 errorInvalidSwitch(p, "Only number, `spec`, or `context` are allowed for `-verrors`"); 1909 return true; 1910 } 1911 } 1912 else if (startsWith(p + 1, "verror-style=")) 1913 { 1914 const(char)[] style = arg["verror-style=".length + 1 .. $]; 1915 1916 switch (style) 1917 { 1918 case "digitalmars": 1919 params.messageStyle = MessageStyle.digitalmars; 1920 break; 1921 case "gnu": 1922 params.messageStyle = MessageStyle.gnu; 1923 break; 1924 default: 1925 error("unknown error style '%.*s', must be 'digitalmars' or 'gnu'", cast(int) style.length, style.ptr); 1926 } 1927 } 1928 else if (startsWith(p + 1, "mcpu")) // https://dlang.org/dmd.html#switch-mcpu 1929 { 1930 enum len = "-mcpu=".length; 1931 // Parse: 1932 // -mcpu=identifier 1933 mixin(checkOptionsMixin("mcpuUsage", 1934 "`-mcpu=<architecture>` requires an architecture")); 1935 if (Identifier.isValidIdentifier(p + len)) 1936 { 1937 const ident = p + len; 1938 switch (ident.toDString()) 1939 { 1940 case "baseline": 1941 params.cpu = CPU.baseline; 1942 break; 1943 case "avx": 1944 params.cpu = CPU.avx; 1945 break; 1946 case "avx2": 1947 params.cpu = CPU.avx2; 1948 break; 1949 case "native": 1950 params.cpu = CPU.native; 1951 break; 1952 default: 1953 errorInvalidSwitch(p, "Only `baseline`, `avx`, `avx2` or `native` are allowed for `-mcpu`"); 1954 params.mcpuUsage = true; 1955 return false; 1956 } 1957 } 1958 else 1959 { 1960 errorInvalidSwitch(p, "Only `baseline`, `avx`, `avx2` or `native` are allowed for `-mcpu`"); 1961 params.mcpuUsage = true; 1962 return false; 1963 } 1964 } 1965 else if (startsWith(p + 1, "extern-std")) // https://dlang.org/dmd.html#switch-extern-std 1966 { 1967 enum len = "-extern-std=".length; 1968 // Parse: 1969 // -extern-std=identifier 1970 mixin(checkOptionsMixin("externStdUsage", 1971 "`-extern-std=<standard>` requires a standard")); 1972 const(char)[] cpprev = arg[len .. $]; 1973 1974 switch (cpprev) 1975 { 1976 case "c++98": 1977 params.cplusplus = CppStdRevision.cpp98; 1978 break; 1979 case "c++11": 1980 params.cplusplus = CppStdRevision.cpp11; 1981 break; 1982 case "c++14": 1983 params.cplusplus = CppStdRevision.cpp14; 1984 break; 1985 case "c++17": 1986 params.cplusplus = CppStdRevision.cpp17; 1987 break; 1988 default: 1989 error("Switch `%s` is invalid", p); 1990 params.externStdUsage = true; 1991 return false; 1992 } 1993 } 1994 else if (startsWith(p + 1, "transition")) // https://dlang.org/dmd.html#switch-transition 1995 { 1996 enum len = "-transition=".length; 1997 // Parse: 1998 // -transition=number 1999 mixin(checkOptionsMixin("transitionUsage", 2000 "`-transition=<name>` requires a name")); 2001 if (!parseCLIOption!("transition", Usage.transitions)(params, arg)) 2002 { 2003 // Legacy -transition flags 2004 // Before DMD 2.085, DMD `-transition` was used for all language flags 2005 // These are kept for backwards compatibility, but no longer documented 2006 if (isdigit(cast(char)p[len])) 2007 { 2008 uint num; 2009 if (!num.parseDigits(p.toDString()[len .. $])) 2010 goto Lerror; 2011 2012 // Bugzilla issue number 2013 switch (num) 2014 { 2015 case 3449: 2016 params.vfield = true; 2017 break; 2018 case 14_246: 2019 params.dtorFields = true; 2020 break; 2021 case 14_488: 2022 params.vcomplex = true; 2023 break; 2024 case 16_997: 2025 params.fix16997 = true; 2026 break; 2027 default: 2028 error("Transition `%s` is invalid", p); 2029 params.transitionUsage = true; 2030 return false; 2031 } 2032 } 2033 else if (Identifier.isValidIdentifier(p + len)) 2034 { 2035 const ident = p + len; 2036 switch (ident.toDString()) 2037 { 2038 case "dtorfields": 2039 params.dtorFields = true; 2040 break; 2041 case "intpromote": 2042 params.fix16997 = true; 2043 break; 2044 case "markdown": 2045 params.markdown = true; 2046 break; 2047 default: 2048 error("Transition `%s` is invalid", p); 2049 params.transitionUsage = true; 2050 return false; 2051 } 2052 } 2053 errorInvalidSwitch(p); 2054 params.transitionUsage = true; 2055 return false; 2056 } 2057 } 2058 else if (startsWith(p + 1, "preview") ) // https://dlang.org/dmd.html#switch-preview 2059 { 2060 enum len = "-preview=".length; 2061 // Parse: 2062 // -preview=name 2063 mixin(checkOptionsMixin("previewUsage", 2064 "`-preview=<name>` requires a name")); 2065 2066 if (!parseCLIOption!("preview", Usage.previews)(params, arg)) 2067 { 2068 error("Preview `%s` is invalid", p); 2069 params.previewUsage = true; 2070 return false; 2071 } 2072 2073 if (params.useDIP1021) 2074 params.vsafe = true; // dip1021 implies dip1000 2075 2076 // copy previously standalone flags from -transition 2077 // -preview=dip1000 implies -preview=dip25 too 2078 if (params.vsafe) 2079 params.useDIP25 = true; 2080 } 2081 else if (startsWith(p + 1, "revert") ) // https://dlang.org/dmd.html#switch-revert 2082 { 2083 enum len = "-revert=".length; 2084 // Parse: 2085 // -revert=name 2086 mixin(checkOptionsMixin("revertUsage", 2087 "`-revert=<name>` requires a name")); 2088 2089 if (!parseCLIOption!("revert", Usage.reverts)(params, arg)) 2090 { 2091 error("Revert `%s` is invalid", p); 2092 params.revertUsage = true; 2093 return false; 2094 } 2095 2096 if (params.noDIP25) 2097 params.useDIP25 = false; 2098 } 2099 else if (arg == "-w") // https://dlang.org/dmd.html#switch-w 2100 params.warnings = DiagnosticReporting.error; 2101 else if (arg == "-wi") // https://dlang.org/dmd.html#switch-wi 2102 params.warnings = DiagnosticReporting.inform; 2103 else if (arg == "-O") // https://dlang.org/dmd.html#switch-O 2104 params.optimize = true; 2105 else if (p[1] == 'o') 2106 { 2107 const(char)* path; 2108 switch (p[2]) 2109 { 2110 case '-': // https://dlang.org/dmd.html#switch-o- 2111 params.obj = false; 2112 break; 2113 case 'd': // https://dlang.org/dmd.html#switch-od 2114 if (!p[3]) 2115 goto Lnoarg; 2116 path = p + 3 + (p[3] == '='); 2117 version (Windows) 2118 { 2119 path = toWinPath(path); 2120 } 2121 params.objdir = path.toDString; 2122 break; 2123 case 'f': // https://dlang.org/dmd.html#switch-of 2124 if (!p[3]) 2125 goto Lnoarg; 2126 path = p + 3 + (p[3] == '='); 2127 version (Windows) 2128 { 2129 path = toWinPath(path); 2130 } 2131 params.objname = path.toDString; 2132 break; 2133 case 'p': // https://dlang.org/dmd.html#switch-op 2134 if (p[3]) 2135 goto Lerror; 2136 params.preservePaths = true; 2137 break; 2138 case 0: 2139 error("-o no longer supported, use -of or -od"); 2140 break; 2141 default: 2142 goto Lerror; 2143 } 2144 } 2145 else if (p[1] == 'D') // https://dlang.org/dmd.html#switch-D 2146 { 2147 params.doDocComments = true; 2148 switch (p[2]) 2149 { 2150 case 'd': // https://dlang.org/dmd.html#switch-Dd 2151 if (!p[3]) 2152 goto Lnoarg; 2153 params.docdir = (p + 3 + (p[3] == '=')).toDString(); 2154 break; 2155 case 'f': // https://dlang.org/dmd.html#switch-Df 2156 if (!p[3]) 2157 goto Lnoarg; 2158 params.docname = (p + 3 + (p[3] == '=')).toDString(); 2159 break; 2160 case 0: 2161 break; 2162 default: 2163 goto Lerror; 2164 } 2165 } 2166 else if (p[1] == 'H' && p[2] == 'C') // https://dlang.org/dmd.html#switch-HC 2167 { 2168 params.doCxxHdrGeneration = CxxHeaderMode.silent; 2169 switch (p[3]) 2170 { 2171 case 'd': // https://dlang.org/dmd.html#switch-HCd 2172 if (!p[4]) 2173 goto Lnoarg; 2174 params.cxxhdrdir = (p + 4 + (p[4] == '=')).toDString; 2175 break; 2176 case 'f': // https://dlang.org/dmd.html#switch-HCf 2177 if (!p[4]) 2178 goto Lnoarg; 2179 params.cxxhdrname = (p + 4 + (p[4] == '=')).toDString; 2180 break; 2181 case '=': 2182 enum len = "-HC=".length; 2183 mixin(checkOptionsMixin("hcUsage", "`-HC=<mode>` requires a valid mode")); 2184 const mode = arg[len .. $]; 2185 switch (mode) 2186 { 2187 case "silent": 2188 /* already set above */ 2189 break; 2190 case "verbose": 2191 params.doCxxHdrGeneration = CxxHeaderMode.verbose; 2192 break; 2193 default: 2194 errorInvalidSwitch(p); 2195 params.hcUsage = true; 2196 return false; 2197 } 2198 break; 2199 case 0: 2200 break; 2201 default: 2202 goto Lerror; 2203 } 2204 } 2205 else if (p[1] == 'H') // https://dlang.org/dmd.html#switch-H 2206 { 2207 params.doHdrGeneration = true; 2208 switch (p[2]) 2209 { 2210 case 'd': // https://dlang.org/dmd.html#switch-Hd 2211 if (!p[3]) 2212 goto Lnoarg; 2213 params.hdrdir = (p + 3 + (p[3] == '=')).toDString; 2214 break; 2215 case 'f': // https://dlang.org/dmd.html#switch-Hf 2216 if (!p[3]) 2217 goto Lnoarg; 2218 params.hdrname = (p + 3 + (p[3] == '=')).toDString; 2219 break; 2220 case 0: 2221 break; 2222 default: 2223 goto Lerror; 2224 } 2225 } 2226 else if (startsWith(p + 1, "Xcc=")) 2227 { 2228 // Linking code is guarded by version (Posix): 2229 static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) 2230 { 2231 params.linkswitches.push(p + 5); 2232 params.linkswitchIsForCC.push(true); 2233 } 2234 else 2235 { 2236 goto Lerror; 2237 } 2238 } 2239 else if (p[1] == 'X') // https://dlang.org/dmd.html#switch-X 2240 { 2241 params.doJsonGeneration = true; 2242 switch (p[2]) 2243 { 2244 case 'f': // https://dlang.org/dmd.html#switch-Xf 2245 if (!p[3]) 2246 goto Lnoarg; 2247 params.jsonfilename = (p + 3 + (p[3] == '=')).toDString; 2248 break; 2249 case 'i': 2250 if (!p[3]) 2251 goto Lnoarg; 2252 if (p[3] != '=') 2253 goto Lerror; 2254 if (!p[4]) 2255 goto Lnoarg; 2256 2257 { 2258 auto flag = tryParseJsonField(p + 4); 2259 if (!flag) 2260 { 2261 error("unknown JSON field `-Xi=%s`, expected one of " ~ jsonFieldNames, p + 4); 2262 continue; 2263 } 2264 global.params.jsonFieldFlags |= flag; 2265 } 2266 break; 2267 case 0: 2268 break; 2269 default: 2270 goto Lerror; 2271 } 2272 } 2273 else if (arg == "-ignore") // https://dlang.org/dmd.html#switch-ignore 2274 params.ignoreUnsupportedPragmas = true; 2275 else if (arg == "-inline") // https://dlang.org/dmd.html#switch-inline 2276 { 2277 params.useInline = true; 2278 params.hdrStripPlainFunctions = false; 2279 } 2280 else if (arg == "-i") 2281 includeImports = true; 2282 else if (startsWith(p + 1, "i=")) 2283 { 2284 includeImports = true; 2285 if (!p[3]) 2286 { 2287 error("invalid option '%s', module patterns cannot be empty", p); 2288 } 2289 else 2290 { 2291 // NOTE: we could check that the argument only contains valid "module-pattern" characters. 2292 // Invalid characters doesn't break anything but an error message to the user might 2293 // be nice. 2294 includeModulePatterns.push(p + 3); 2295 } 2296 } 2297 else if (arg == "-dip25") // https://dlang.org/dmd.html#switch-dip25 2298 params.useDIP25 = true; 2299 else if (arg == "-dip1000") 2300 { 2301 params.useDIP25 = true; 2302 params.vsafe = true; 2303 } 2304 else if (arg == "-dip1008") 2305 { 2306 params.ehnogc = true; 2307 } 2308 else if (arg == "-lib") // https://dlang.org/dmd.html#switch-lib 2309 params.lib = true; 2310 else if (arg == "-nofloat") 2311 params.nofloat = true; 2312 else if (arg == "-quiet") 2313 { 2314 // Ignore 2315 } 2316 else if (arg == "-release") // https://dlang.org/dmd.html#switch-release 2317 params.release = true; 2318 else if (arg == "-betterC") // https://dlang.org/dmd.html#switch-betterC 2319 params.betterC = true; 2320 else if (arg == "-noboundscheck") // https://dlang.org/dmd.html#switch-noboundscheck 2321 { 2322 params.boundscheck = CHECKENABLE.off; 2323 } 2324 else if (startsWith(p + 1, "boundscheck")) // https://dlang.org/dmd.html#switch-boundscheck 2325 { 2326 // Parse: 2327 // -boundscheck=[on|safeonly|off] 2328 if (p[12] == '=') 2329 { 2330 const(char)[] boundscheck = arg[13 .. $]; 2331 2332 switch (boundscheck) 2333 { 2334 case "on": 2335 params.boundscheck = CHECKENABLE.on; 2336 break; 2337 case "safeonly": 2338 params.boundscheck = CHECKENABLE.safeonly; 2339 break; 2340 case "off": 2341 params.boundscheck = CHECKENABLE.off; 2342 break; 2343 default: 2344 goto Lerror; 2345 } 2346 } 2347 else 2348 goto Lerror; 2349 } 2350 else if (arg == "-unittest") 2351 params.useUnitTests = true; 2352 else if (p[1] == 'I') // https://dlang.org/dmd.html#switch-I 2353 { 2354 if (!params.imppath) 2355 params.imppath = new Strings(); 2356 params.imppath.push(p + 2 + (p[2] == '=')); 2357 } 2358 else if (p[1] == 'm' && p[2] == 'v' && p[3] == '=') // https://dlang.org/dmd.html#switch-mv 2359 { 2360 if (p[4] && strchr(p + 5, '=')) 2361 { 2362 params.modFileAliasStrings.push(p + 4); 2363 } 2364 else 2365 goto Lerror; 2366 } 2367 else if (p[1] == 'J') // https://dlang.org/dmd.html#switch-J 2368 { 2369 if (!params.fileImppath) 2370 params.fileImppath = new Strings(); 2371 params.fileImppath.push(p + 2 + (p[2] == '=')); 2372 } 2373 else if (startsWith(p + 1, "debug") && p[6] != 'l') // https://dlang.org/dmd.html#switch-debug 2374 { 2375 // Parse: 2376 // -debug 2377 // -debug=number 2378 // -debug=identifier 2379 if (p[6] == '=') 2380 { 2381 if (isdigit(cast(char)p[7])) 2382 { 2383 if (!params.debuglevel.parseDigits(p.toDString()[7 .. $])) 2384 goto Lerror; 2385 } 2386 else if (Identifier.isValidIdentifier(p + 7)) 2387 { 2388 if (!params.debugids) 2389 params.debugids = new Array!(const(char)*); 2390 params.debugids.push(p + 7); 2391 } 2392 else 2393 goto Lerror; 2394 } 2395 else if (p[6]) 2396 goto Lerror; 2397 else 2398 params.debuglevel = 1; 2399 } 2400 else if (startsWith(p + 1, "version")) // https://dlang.org/dmd.html#switch-version 2401 { 2402 // Parse: 2403 // -version=number 2404 // -version=identifier 2405 if (p[8] == '=') 2406 { 2407 if (isdigit(cast(char)p[9])) 2408 { 2409 if (!params.versionlevel.parseDigits(p.toDString()[9 .. $])) 2410 goto Lerror; 2411 } 2412 else if (Identifier.isValidIdentifier(p + 9)) 2413 { 2414 if (!params.versionids) 2415 params.versionids = new Array!(const(char)*); 2416 params.versionids.push(p + 9); 2417 } 2418 else 2419 goto Lerror; 2420 } 2421 else 2422 goto Lerror; 2423 } 2424 else if (arg == "--b") 2425 params.debugb = true; 2426 else if (arg == "--c") 2427 params.debugc = true; 2428 else if (arg == "--f") 2429 params.debugf = true; 2430 else if (arg == "--help" || 2431 arg == "-h") 2432 { 2433 params.usage = true; 2434 return false; 2435 } 2436 else if (arg == "--r") 2437 params.debugr = true; 2438 else if (arg == "--version") 2439 { 2440 params.logo = true; 2441 return false; 2442 } 2443 else if (arg == "--x") 2444 params.debugx = true; 2445 else if (arg == "--y") 2446 params.debugy = true; 2447 else if (p[1] == 'L') // https://dlang.org/dmd.html#switch-L 2448 { 2449 params.linkswitches.push(p + 2 + (p[2] == '=')); 2450 params.linkswitchIsForCC.push(false); 2451 } 2452 else if (startsWith(p + 1, "defaultlib=")) // https://dlang.org/dmd.html#switch-defaultlib 2453 { 2454 params.defaultlibname = (p + 1 + 11).toDString; 2455 } 2456 else if (startsWith(p + 1, "debuglib=")) // https://dlang.org/dmd.html#switch-debuglib 2457 { 2458 params.debuglibname = (p + 1 + 9).toDString; 2459 } 2460 else if (startsWith(p + 1, "deps")) // https://dlang.org/dmd.html#switch-deps 2461 { 2462 if (params.moduleDeps) 2463 { 2464 error("-deps[=file] can only be provided once!"); 2465 break; 2466 } 2467 if (p[5] == '=') 2468 { 2469 params.moduleDepsFile = (p + 1 + 5).toDString; 2470 if (!params.moduleDepsFile[0]) 2471 goto Lnoarg; 2472 } 2473 else if (p[5] != '\0') 2474 { 2475 // Else output to stdout. 2476 goto Lerror; 2477 } 2478 params.moduleDeps = new OutBuffer(); 2479 } 2480 else if (arg == "-main") // https://dlang.org/dmd.html#switch-main 2481 { 2482 params.addMain = true; 2483 } 2484 else if (startsWith(p + 1, "man")) // https://dlang.org/dmd.html#switch-man 2485 { 2486 params.manual = true; 2487 return false; 2488 } 2489 else if (arg == "-run") // https://dlang.org/dmd.html#switch-run 2490 { 2491 params.run = true; 2492 size_t length = argc - i - 1; 2493 if (length) 2494 { 2495 const(char)[] runarg = arguments[i + 1].toDString(); 2496 const(char)[] ext = FileName.ext(runarg); 2497 if (ext && FileName.equals(ext, "d") == 0 && FileName.equals(ext, "di") == 0) 2498 { 2499 error("-run must be followed by a source file, not '%s'", arguments[i + 1]); 2500 break; 2501 } 2502 if (runarg == "-") 2503 files.push("__stdin.d"); 2504 else 2505 files.push(arguments[i + 1]); 2506 params.runargs.setDim(length - 1); 2507 for (size_t j = 0; j < length - 1; ++j) 2508 { 2509 params.runargs[j] = arguments[i + 2 + j]; 2510 } 2511 i += length; 2512 } 2513 else 2514 { 2515 params.run = false; 2516 goto Lnoarg; 2517 } 2518 } 2519 else if (p[1] == '\0') 2520 files.push("__stdin.d"); 2521 else 2522 { 2523 Lerror: 2524 error("unrecognized switch '%s'", arguments[i]); 2525 continue; 2526 Lnoarg: 2527 error("argument expected for switch '%s'", arguments[i]); 2528 continue; 2529 } 2530 } 2531 return errors; 2532 } 2533 2534 /*********************************************** 2535 * Adjust gathered command line switches and reconcile them. 2536 * Params: 2537 * params = switches gathered from command line, 2538 * and update in place 2539 * numSrcFiles = number of source files 2540 */ 2541 version (NoMain) {} else 2542 private void reconcileCommands(ref Param params, size_t numSrcFiles) 2543 { 2544 static if (TARGET.OSX) 2545 { 2546 params.pic = PIC.pic; 2547 } 2548 static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) 2549 { 2550 if (params.lib && params.dll) 2551 error(Loc.initial, "cannot mix -lib and -shared"); 2552 } 2553 static if (TARGET.Windows) 2554 { 2555 if (params.mscoff && !params.mscrtlib) 2556 { 2557 VSOptions vsopt; 2558 vsopt.initialize(); 2559 params.mscrtlib = vsopt.defaultRuntimeLibrary(params.is64bit).toDString; 2560 } 2561 } 2562 2563 // Target uses 64bit pointers. 2564 params.isLP64 = params.is64bit; 2565 2566 if (params.boundscheck != CHECKENABLE._default) 2567 { 2568 if (params.useArrayBounds == CHECKENABLE._default) 2569 params.useArrayBounds = params.boundscheck; 2570 } 2571 2572 if (params.useUnitTests) 2573 { 2574 if (params.useAssert == CHECKENABLE._default) 2575 params.useAssert = CHECKENABLE.on; 2576 } 2577 2578 if (params.release) 2579 { 2580 if (params.useInvariants == CHECKENABLE._default) 2581 params.useInvariants = CHECKENABLE.off; 2582 2583 if (params.useIn == CHECKENABLE._default) 2584 params.useIn = CHECKENABLE.off; 2585 2586 if (params.useOut == CHECKENABLE._default) 2587 params.useOut = CHECKENABLE.off; 2588 2589 if (params.useArrayBounds == CHECKENABLE._default) 2590 params.useArrayBounds = CHECKENABLE.safeonly; 2591 2592 if (params.useAssert == CHECKENABLE._default) 2593 params.useAssert = CHECKENABLE.off; 2594 2595 if (params.useSwitchError == CHECKENABLE._default) 2596 params.useSwitchError = CHECKENABLE.off; 2597 } 2598 else 2599 { 2600 if (params.useInvariants == CHECKENABLE._default) 2601 params.useInvariants = CHECKENABLE.on; 2602 2603 if (params.useIn == CHECKENABLE._default) 2604 params.useIn = CHECKENABLE.on; 2605 2606 if (params.useOut == CHECKENABLE._default) 2607 params.useOut = CHECKENABLE.on; 2608 2609 if (params.useArrayBounds == CHECKENABLE._default) 2610 params.useArrayBounds = CHECKENABLE.on; 2611 2612 if (params.useAssert == CHECKENABLE._default) 2613 params.useAssert = CHECKENABLE.on; 2614 2615 if (params.useSwitchError == CHECKENABLE._default) 2616 params.useSwitchError = CHECKENABLE.on; 2617 } 2618 2619 if (params.betterC) 2620 { 2621 params.checkAction = CHECKACTION.C; 2622 params.useModuleInfo = false; 2623 params.useTypeInfo = false; 2624 params.useExceptions = false; 2625 } 2626 2627 2628 if (!params.obj || params.lib) 2629 params.link = false; 2630 if (params.link) 2631 { 2632 params.exefile = params.objname; 2633 params.oneobj = true; 2634 if (params.objname) 2635 { 2636 /* Use this to name the one object file with the same 2637 * name as the exe file. 2638 */ 2639 params.objname = FileName.forceExt(params.objname, global.obj_ext); 2640 /* If output directory is given, use that path rather than 2641 * the exe file path. 2642 */ 2643 if (params.objdir) 2644 { 2645 const(char)[] name = FileName.name(params.objname); 2646 params.objname = FileName.combine(params.objdir, name); 2647 } 2648 } 2649 } 2650 else if (params.run) 2651 { 2652 error(Loc.initial, "flags conflict with -run"); 2653 fatal(); 2654 } 2655 else if (params.lib) 2656 { 2657 params.libname = params.objname; 2658 params.objname = null; 2659 // Haven't investigated handling these options with multiobj 2660 if (!params.cov && !params.trace) 2661 params.multiobj = true; 2662 } 2663 else 2664 { 2665 if (params.objname && numSrcFiles) 2666 { 2667 params.oneobj = true; 2668 //error("multiple source files, but only one .obj name"); 2669 //fatal(); 2670 } 2671 } 2672 2673 if (params.noDIP25) 2674 params.useDIP25 = false; 2675 } 2676 2677 /** 2678 Creates the module based on the file provided 2679 2680 The file is dispatched in one of the various arrays 2681 (global.params.{ddocfiles,dllfiles,jsonfiles,etc...}) 2682 according to its extension. 2683 If it is a binary file, it is added to libmodules. 2684 2685 Params: 2686 file = File name to dispatch 2687 libmodules = Array to which binaries (shared/static libs and object files) 2688 will be appended 2689 2690 Returns: 2691 A D module 2692 */ 2693 Module createModule(const(char)* file, ref Strings libmodules) 2694 { 2695 const(char)[] name; 2696 version (Windows) 2697 { 2698 file = toWinPath(file); 2699 } 2700 const(char)[] p = file.toDString(); 2701 p = FileName.name(p); // strip path 2702 const(char)[] ext = FileName.ext(p); 2703 if (!ext) 2704 { 2705 if (!p.length) 2706 { 2707 error(Loc.initial, "invalid file name '%s'", file); 2708 fatal(); 2709 } 2710 auto id = Identifier.idPool(p); 2711 return new Module(file.toDString, id, global.params.doDocComments, global.params.doHdrGeneration); 2712 } 2713 2714 /* Deduce what to do with a file based on its extension 2715 */ 2716 if (FileName.equals(ext, global.obj_ext)) 2717 { 2718 global.params.objfiles.push(file); 2719 libmodules.push(file); 2720 return null; 2721 } 2722 if (FileName.equals(ext, global.lib_ext)) 2723 { 2724 global.params.libfiles.push(file); 2725 libmodules.push(file); 2726 return null; 2727 } 2728 static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) 2729 { 2730 if (FileName.equals(ext, global.dll_ext)) 2731 { 2732 global.params.dllfiles.push(file); 2733 libmodules.push(file); 2734 return null; 2735 } 2736 } 2737 if (ext == global.ddoc_ext) 2738 { 2739 global.params.ddocfiles.push(file); 2740 return null; 2741 } 2742 if (FileName.equals(ext, global.json_ext)) 2743 { 2744 global.params.doJsonGeneration = true; 2745 global.params.jsonfilename = file.toDString; 2746 return null; 2747 } 2748 if (FileName.equals(ext, global.map_ext)) 2749 { 2750 global.params.mapfile = file.toDString; 2751 return null; 2752 } 2753 static if (TARGET.Windows) 2754 { 2755 if (FileName.equals(ext, "res")) 2756 { 2757 global.params.resfile = file.toDString; 2758 return null; 2759 } 2760 if (FileName.equals(ext, "def")) 2761 { 2762 global.params.deffile = file.toDString; 2763 return null; 2764 } 2765 if (FileName.equals(ext, "exe")) 2766 { 2767 assert(0); // should have already been handled 2768 } 2769 } 2770 /* Examine extension to see if it is a valid 2771 * D source file extension 2772 */ 2773 if (FileName.equals(ext, global.mars_ext) || FileName.equals(ext, global.hdr_ext) || FileName.equals(ext, "dd")) 2774 { 2775 name = FileName.removeExt(p); 2776 if (!name.length || name == ".." || name == ".") 2777 { 2778 error(Loc.initial, "invalid file name '%s'", file); 2779 fatal(); 2780 } 2781 } 2782 else 2783 { 2784 error(Loc.initial, "unrecognized file extension %.*s", cast(int)ext.length, ext.ptr); 2785 fatal(); 2786 } 2787 2788 /* At this point, name is the D source file name stripped of 2789 * its path and extension. 2790 */ 2791 auto id = Identifier.idPool(name); 2792 2793 return new Module(file.toDString, id, global.params.doDocComments, global.params.doHdrGeneration); 2794 } 2795 2796 /** 2797 Creates the list of modules based on the files provided 2798 2799 Files are dispatched in the various arrays 2800 (global.params.{ddocfiles,dllfiles,jsonfiles,etc...}) 2801 according to their extension. 2802 Binary files are added to libmodules. 2803 2804 Params: 2805 files = File names to dispatch 2806 libmodules = Array to which binaries (shared/static libs and object files) 2807 will be appended 2808 2809 Returns: 2810 An array of path to D modules 2811 */ 2812 Modules createModules(ref Strings files, ref Strings libmodules) 2813 { 2814 Modules modules; 2815 modules.reserve(files.dim); 2816 bool firstmodule = true; 2817 for (size_t i = 0; i < files.dim; i++) 2818 { 2819 auto m = createModule(files[i], libmodules); 2820 2821 if (m is null) 2822 continue; 2823 2824 modules.push(m); 2825 if (firstmodule) 2826 { 2827 global.params.objfiles.push(m.objfile.toChars()); 2828 firstmodule = false; 2829 } 2830 } 2831 return modules; 2832 }