1 2 /** 3 * This modules defines related 4 * utilities needed for arguments parsing, path manipulation, etc... 5 * This file is not shared with other compilers which use the DMD front-end. 6 * 7 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 8 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 9 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 10 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mars.d, _mars.d) 11 * Documentation: https://dlang.org/phobos/dmd_mars.html 12 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mars.d 13 */ 14 15 module dmd.mars; 16 17 import core.stdc.ctype; 18 import core.stdc.stdio; 19 import core.stdc.stdlib; 20 import core.stdc.string; 21 22 import dmd.arraytypes; 23 import dmd.astenums; 24 import dmd.cond; 25 import dmd.console; 26 import dmd.compiler; 27 import dmd.cpreprocess; 28 import dmd.dmdparams; 29 import dmd.dinifile; 30 import dmd.dinterpret; 31 import dmd.dmodule; 32 import dmd.doc; 33 import dmd.dsymbol; 34 import dmd.dsymbolsem; 35 import dmd.dtemplate; 36 import dmd.dtoh; 37 import dmd.errors; 38 import dmd.expression; 39 import dmd.globals; 40 import dmd.hdrgen; 41 import dmd.id; 42 import dmd.identifier; 43 import dmd.inline; 44 import dmd.location; 45 import dmd.json; 46 import dmd.mtype; 47 import dmd.objc; 48 import dmd.root.array; 49 import dmd.root.file; 50 import dmd.root.filename; 51 import dmd.root.man; 52 import dmd.common.outbuffer; 53 import dmd.root.response; 54 import dmd.root.rmem; 55 import dmd.root.string; 56 import dmd.root.stringtable; 57 import dmd.semantic2; 58 import dmd.semantic3; 59 import dmd.target; 60 import dmd.utils; 61 62 /** 63 * Print DMD's logo on stdout 64 */ 65 void logo() 66 { 67 printf("DMD%llu D Compiler %.*s\n%.*s %.*s\n", 68 cast(ulong)size_t.sizeof * 8, 69 cast(int) global.versionString().length, global.versionString().ptr, 70 cast(int)global.copyright.length, global.copyright.ptr, 71 cast(int)global.written.length, global.written.ptr 72 ); 73 } 74 75 /** 76 Print DMD's logo with more debug information and error-reporting pointers. 77 78 Params: 79 stream = output stream to print the information on 80 */ 81 void printInternalFailure(FILE* stream) 82 { 83 fputs(("---\n" ~ 84 "ERROR: This is a compiler bug.\n" ~ 85 "Please report it via https://issues.dlang.org/enter_bug.cgi\n" ~ 86 "with, preferably, a reduced, reproducible example and the information below.\n" ~ 87 "DustMite (https://github.com/CyberShadow/DustMite/wiki) can help with the reduction.\n" ~ 88 "---\n").ptr, stream); 89 stream.fprintf("DMD %.*s\n", cast(int) global.versionString().length, global.versionString().ptr); 90 stream.printPredefinedVersions; 91 stream.printGlobalConfigs(); 92 fputs("---\n".ptr, stream); 93 } 94 95 /** 96 * Print DMD's usage message on stdout 97 */ 98 void usage() 99 { 100 import dmd.cli : CLIUsage; 101 logo(); 102 auto help = CLIUsage.usage; 103 const inifileCanon = FileName.canonicalName(global.inifilename); 104 printf(" 105 Documentation: https://dlang.org/ 106 Config file: %.*s 107 Usage: 108 dmd [<option>...] <file>... 109 dmd [<option>...] -run <file> [<arg>...] 110 111 Where: 112 <file> D source file 113 <arg> Argument to pass when running the resulting program 114 115 <option>: 116 @<cmdfile> read arguments from cmdfile 117 %.*s", cast(int)inifileCanon.length, inifileCanon.ptr, cast(int)help.length, &help[0]); 118 } 119 120 extern (C++) void generateJson(ref Modules modules) 121 { 122 OutBuffer buf; 123 json_generate(modules, buf); 124 125 // Write buf to file 126 const(char)[] name = global.params.json.name; 127 if (name == "-") 128 { 129 // Write to stdout; assume it succeeds 130 size_t n = fwrite(buf[].ptr, 1, buf.length, stdout); 131 assert(n == buf.length); // keep gcc happy about return values 132 } 133 else 134 { 135 /* The filename generation code here should be harmonized with Module.setOutfilename() 136 */ 137 const(char)[] jsonfilename; 138 if (name) 139 { 140 jsonfilename = FileName.defaultExt(name, json_ext); 141 } 142 else 143 { 144 if (global.params.objfiles.length == 0) 145 { 146 error(Loc.initial, "cannot determine JSON filename, use `-Xf=<file>` or provide a source file"); 147 fatal(); 148 } 149 // Generate json file name from first obj name 150 const(char)[] n = global.params.objfiles[0].toDString; 151 n = FileName.name(n); 152 //if (!FileName::absolute(name)) 153 // name = FileName::combine(dir, name); 154 jsonfilename = FileName.forceExt(n, json_ext); 155 } 156 if (!writeFile(Loc.initial, jsonfilename, buf[])) 157 fatal(); 158 } 159 } 160 161 version (DigitalMars) 162 { 163 void installMemErrHandler() 164 { 165 // (only available on some platforms on DMD) 166 const shouldDoMemoryError = getenv("DMD_INSTALL_MEMERR_HANDLER"); 167 if (shouldDoMemoryError !is null && *shouldDoMemoryError == '1') 168 { 169 import etc.linux.memoryerror; 170 static if (is(typeof(registerMemoryErrorHandler()))) 171 { 172 registerMemoryErrorHandler(); 173 } 174 else 175 { 176 printf("**WARNING** Memory error handler not supported on this platform!\n"); 177 } 178 } 179 } 180 } 181 182 version (NoMain) 183 { 184 version (DigitalMars) 185 { 186 shared static this() 187 { 188 installMemErrHandler(); 189 } 190 } 191 } 192 193 /** 194 * Parses an environment variable containing command-line flags 195 * and append them to `args`. 196 * 197 * This function is used to read the content of DFLAGS. 198 * Flags are separated based on spaces and tabs. 199 * 200 * Params: 201 * envvalue = The content of an environment variable 202 * args = Array to append the flags to, if any. 203 */ 204 void getenv_setargv(const(char)* envvalue, Strings* args) 205 { 206 if (!envvalue) 207 return; 208 209 char* env = mem.xstrdup(envvalue); // create our own writable copy 210 //printf("env = '%s'\n", env); 211 while (1) 212 { 213 switch (*env) 214 { 215 case ' ': 216 case '\t': 217 env++; 218 break; 219 220 case 0: 221 return; 222 223 default: 224 { 225 args.push(env); // append 226 auto p = env; 227 auto slash = 0; 228 bool instring = false; 229 while (1) 230 { 231 auto c = *env++; 232 switch (c) 233 { 234 case '"': 235 p -= (slash >> 1); 236 if (slash & 1) 237 { 238 p--; 239 goto default; 240 } 241 instring ^= true; 242 slash = 0; 243 continue; 244 245 case ' ': 246 case '\t': 247 if (instring) 248 goto default; 249 *p = 0; 250 //if (wildcard) 251 // wildcardexpand(); // not implemented 252 break; 253 254 case '\\': 255 slash++; 256 *p++ = c; 257 continue; 258 259 case 0: 260 *p = 0; 261 //if (wildcard) 262 // wildcardexpand(); // not implemented 263 return; 264 265 default: 266 slash = 0; 267 *p++ = c; 268 continue; 269 } 270 break; 271 } 272 break; 273 } 274 } 275 } 276 } 277 278 /** 279 * Parse command line arguments for the last instance of -m32, -m64, -m32mscoff or -m32omfobj 280 * to detect the desired architecture. 281 * 282 * Params: 283 * args = Command line arguments 284 * arch = Default value to use for architecture. 285 * Should be "32" or "64" 286 * 287 * Returns: 288 * "32", "64" or "32omf" if the "-m32", "-m64", "-m32omf" flags were passed, 289 * respectively. If they weren't, return `arch`. 290 */ 291 const(char)[] parse_arch_arg(Strings* args, const(char)[] arch) 292 { 293 foreach (const p; *args) 294 { 295 const(char)[] arg = p.toDString; 296 297 if (arg.length && arg[0] == '-') 298 { 299 if (arg[1 .. $] == "m32" || arg[1 .. $] == "m32omf" || arg[1 .. $] == "m64") 300 arch = arg[2 .. $]; 301 else if (arg[1 .. $] == "m32mscoff") 302 arch = "32"; 303 else if (arg[1 .. $] == "run") 304 break; 305 } 306 } 307 return arch; 308 } 309 310 311 /** 312 * Parse command line arguments for the last instance of -conf=path. 313 * 314 * Params: 315 * args = Command line arguments 316 * 317 * Returns: 318 * The 'path' in -conf=path, which is the path to the config file to use 319 */ 320 const(char)[] parse_conf_arg(Strings* args) 321 { 322 const(char)[] conf; 323 foreach (const p; *args) 324 { 325 const(char)[] arg = p.toDString; 326 if (arg.length && arg[0] == '-') 327 { 328 if(arg.length >= 6 && arg[1 .. 6] == "conf="){ 329 conf = arg[6 .. $]; 330 } 331 else if (arg[1 .. $] == "run") 332 break; 333 } 334 } 335 return conf; 336 } 337 338 339 /** 340 * Set the default and debug libraries to link against, if not already set 341 * 342 * Must be called after argument parsing is done, as it won't 343 * override any value. 344 * Note that if `-defaultlib=` or `-debuglib=` was used, 345 * we don't override that either. 346 */ 347 void setDefaultLibrary(ref Param params, const ref Target target) 348 { 349 if (driverParams.defaultlibname is null) 350 { 351 if (target.os == Target.OS.Windows) 352 { 353 if (target.isX86_64) 354 driverParams.defaultlibname = "phobos64"; 355 else if (!target.omfobj) 356 driverParams.defaultlibname = "phobos32mscoff"; 357 else 358 driverParams.defaultlibname = "phobos"; 359 } 360 else if (target.os & (Target.OS.linux | Target.OS.FreeBSD | Target.OS.OpenBSD | Target.OS.Solaris | Target.OS.DragonFlyBSD)) 361 { 362 driverParams.defaultlibname = "libphobos2.a"; 363 } 364 else if (target.os == Target.OS.OSX) 365 { 366 driverParams.defaultlibname = "phobos2"; 367 } 368 else 369 { 370 assert(0, "fix this"); 371 } 372 } 373 else if (!driverParams.defaultlibname.length) // if `-defaultlib=` (i.e. an empty defaultlib) 374 driverParams.defaultlibname = null; 375 376 if (driverParams.debuglibname is null) 377 driverParams.debuglibname = driverParams.defaultlibname; 378 } 379 380 void printPredefinedVersions(FILE* stream) 381 { 382 if (global.versionids) 383 { 384 OutBuffer buf; 385 foreach (const str; *global.versionids) 386 { 387 buf.writeByte(' '); 388 buf.writestring(str.toChars()); 389 } 390 stream.fprintf("predefs %s\n", buf.peekChars()); 391 } 392 } 393 394 extern(C) void printGlobalConfigs(FILE* stream) 395 { 396 stream.fprintf("binary %.*s\n", cast(int)global.params.argv0.length, global.params.argv0.ptr); 397 stream.fprintf("version %.*s\n", cast(int) global.versionString().length, global.versionString().ptr); 398 const iniOutput = global.inifilename ? global.inifilename : "(none)"; 399 stream.fprintf("config %.*s\n", cast(int)iniOutput.length, iniOutput.ptr); 400 // Print DFLAGS environment variable 401 { 402 StringTable!(char*) environment; 403 environment._init(0); 404 Strings dflags; 405 getenv_setargv(readFromEnv(environment, "DFLAGS"), &dflags); 406 environment.reset(1); 407 OutBuffer buf; 408 foreach (flag; dflags[]) 409 { 410 bool needsQuoting; 411 foreach (c; flag.toDString()) 412 { 413 if (!(isalnum(c) || c == '_')) 414 { 415 needsQuoting = true; 416 break; 417 } 418 } 419 420 if (flag.strchr(' ')) 421 buf.printf("'%s' ", flag); 422 else 423 buf.printf("%s ", flag); 424 } 425 426 auto res = buf[] ? buf[][0 .. $ - 1] : "(none)"; 427 stream.fprintf("DFLAGS %.*s\n", cast(int)res.length, res.ptr); 428 } 429 } 430 431 /************************************** 432 * we want to write the mixin expansion file also on error, but there 433 * are too many ways to terminate dmd (e.g. fatal() which calls exit(EXIT_FAILURE)), 434 * so we can't rely on scope(exit) ... in tryMain() actually being executed 435 * so we add atexit(&flushMixins); for those fatal exits (with the GC still valid) 436 */ 437 extern(C) void flushMixins() 438 { 439 if (!global.params.mixinOut.buffer) 440 return; 441 442 assert(global.params.mixinOut.name); 443 File.write(global.params.mixinOut.name, (*global.params.mixinOut.buffer)[]); 444 445 global.params.mixinOut.buffer.destroy(); 446 global.params.mixinOut.buffer = null; 447 } 448 449 /**************************************************** 450 * Parse command line arguments. 451 * 452 * Prints message(s) if there are errors. 453 * 454 * Params: 455 * arguments = command line arguments 456 * argc = argument count 457 * params = set to result of parsing `arguments` 458 * files = set to files pulled from `arguments` 459 * target = more things set to result of parsing `arguments` 460 * Returns: 461 * true if errors in command line 462 */ 463 464 bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param params, ref Strings files, ref Target target) 465 { 466 bool errors; 467 468 void error(Args ...)(const(char)* format, Args args) 469 { 470 dmd.errors.error(Loc.initial, format, args); 471 errors = true; 472 } 473 474 /** 475 * Print an error messsage about an invalid switch. 476 * If an optional supplemental message has been provided, 477 * it will be printed too. 478 * 479 * Params: 480 * p = 0 terminated string 481 * availableOptions = supplemental help message listing the available options 482 */ 483 void errorInvalidSwitch(const(char)* p, string availableOptions = null) 484 { 485 error("switch `%s` is invalid", p); 486 if (availableOptions !is null) 487 errorSupplemental(Loc.initial, "%.*s", cast(int)availableOptions.length, availableOptions.ptr); 488 } 489 490 enum CheckOptions { success, error, help } 491 492 /* 493 Checks whether the CLI options contains a valid argument or a help argument. 494 If a help argument has been used, it will set the `usageFlag`. 495 496 Params: 497 p = string as a D array 498 usageFlag = parameter for the usage help page to set (by `ref`) 499 missingMsg = error message to use when no argument has been provided 500 501 Returns: 502 `success` if a valid argument has been passed and it's not a help page 503 `error` if an error occurred (e.g. `-foobar`) 504 `help` if a help page has been request (e.g. `-flag` or `-flag=h`) 505 */ 506 CheckOptions checkOptions(const(char)[] p, ref bool usageFlag, string missingMsg) 507 { 508 // Checks whether a flag has no options (e.g. -foo or -foo=) 509 if (p.length == 0 || p == "=") 510 { 511 .error(Loc.initial, "%.*s", cast(int)missingMsg.length, missingMsg.ptr); 512 errors = true; 513 usageFlag = true; 514 return CheckOptions.help; 515 } 516 if (p[0] != '=') 517 return CheckOptions.error; 518 p = p[1 .. $]; 519 /* Checks whether the option pointer supplied is a request 520 for the help page, e.g. -foo=j */ 521 if ((p == "h" || p == "?") || // -flag=h || -flag=? 522 p == "help") 523 { 524 usageFlag = true; 525 return CheckOptions.help; 526 } 527 return CheckOptions.success; 528 } 529 530 static string checkOptionsMixin(string usageFlag, string missingMsg) 531 { 532 return q{ 533 final switch (checkOptions(arg[len - 1 .. $], params.help..}~usageFlag~","~ 534 `"`~missingMsg~`"`~q{)) 535 { 536 case CheckOptions.error: 537 goto Lerror; 538 case CheckOptions.help: 539 return false; 540 case CheckOptions.success: 541 break; 542 } 543 }; 544 } 545 546 import dmd.cli : Usage; 547 bool parseCLIOption(string name, Usage.Feature[] features)(ref Param params, const(char)[] p) 548 { 549 // Parse: 550 // -<name>=<feature> 551 const(char)[] ps = p[name.length + 1 .. $]; 552 const(char)[] ident = ps[1 .. $]; 553 if (Identifier.isValidIdentifier(ident)) 554 { 555 string generateTransitionsText() 556 { 557 import dmd.cli : Usage; 558 string buf = `case "all":`; 559 foreach (t; features) 560 { 561 if (t.deprecated_) 562 continue; 563 564 buf ~= `setFlagFor(name, params.`~t.paramName~`);`; 565 } 566 buf ~= "return true;\n"; 567 568 foreach (t; features) 569 { 570 buf ~= `case "`~t.name~`":`; 571 if (t.deprecated_) 572 buf ~= "deprecation(Loc.initial, \"`-"~name~"="~t.name~"` no longer has any effect.\"); "; 573 buf ~= `setFlagFor(name, params.`~t.paramName~`); return true;`; 574 } 575 return buf; 576 } 577 578 switch (ident) 579 { 580 mixin(generateTransitionsText()); 581 default: 582 return false; 583 } 584 } 585 return false; 586 } 587 588 version (none) 589 { 590 for (size_t i = 0; i < arguments.length; i++) 591 { 592 printf("arguments[%d] = '%s'\n", i, arguments[i]); 593 } 594 } 595 596 files.reserve(arguments.length - 1); 597 598 for (size_t i = 1; i < arguments.length; i++) 599 { 600 const(char)* p = arguments[i]; 601 const(char)[] arg = p.toDString(); 602 if (*p != '-') 603 { 604 if (target.os == Target.OS.Windows) 605 { 606 const ext = FileName.ext(arg); 607 if (ext.length && FileName.equals(ext, "exe")) 608 { 609 params.objname = arg; 610 continue; 611 } 612 if (arg == "/?") 613 { 614 params.help.usage = true; 615 return false; 616 } 617 } 618 files.push(p); 619 continue; 620 } 621 622 if (arg == "-allinst") // https://dlang.org/dmd.html#switch-allinst 623 params.allInst = true; 624 else if (startsWith(p + 1, "cpp=")) // https://dlang.org/dmd.html#switch-cpp 625 { 626 if (p[5]) 627 { 628 params.cpp = p + 5; 629 } 630 else 631 { 632 errorInvalidSwitch(p, "it must be followed by the filename of the desired C preprocessor"); 633 return false; 634 } 635 } 636 else if (arg == "-de") // https://dlang.org/dmd.html#switch-de 637 params.useDeprecated = DiagnosticReporting.error; 638 else if (arg == "-d") // https://dlang.org/dmd.html#switch-d 639 params.useDeprecated = DiagnosticReporting.off; 640 else if (arg == "-dw") // https://dlang.org/dmd.html#switch-dw 641 params.useDeprecated = DiagnosticReporting.inform; 642 else if (arg == "-c") // https://dlang.org/dmd.html#switch-c 643 driverParams.link = false; 644 else if (startsWith(p + 1, "checkaction")) // https://dlang.org/dmd.html#switch-checkaction 645 { 646 /* Parse: 647 * -checkaction=D|C|halt|context 648 */ 649 enum len = "-checkaction=".length; 650 mixin(checkOptionsMixin("checkAction", 651 "`-check=<behavior>` requires a behavior")); 652 switch (arg[len .. $]) 653 { 654 case "D": 655 params.checkAction = CHECKACTION.D; 656 break; 657 case "C": 658 params.checkAction = CHECKACTION.C; 659 break; 660 case "halt": 661 params.checkAction = CHECKACTION.halt; 662 break; 663 case "context": 664 params.checkAction = CHECKACTION.context; 665 break; 666 default: 667 errorInvalidSwitch(p); 668 params.help.checkAction = true; 669 return false; 670 } 671 } 672 else if (startsWith(p + 1, "check")) // https://dlang.org/dmd.html#switch-check 673 { 674 enum len = "-check=".length; 675 mixin(checkOptionsMixin("check", 676 "`-check=<action>` requires an action")); 677 /* Parse: 678 * -check=[assert|bounds|in|invariant|out|switch][=[on|off]] 679 */ 680 681 // Check for legal option string; return true if so 682 static bool check(const(char)[] checkarg, string name, ref CHECKENABLE ce) 683 { 684 if (checkarg.length >= name.length && 685 checkarg[0 .. name.length] == name) 686 { 687 checkarg = checkarg[name.length .. $]; 688 689 if (checkarg.length == 0 || 690 checkarg == "=on") 691 { 692 ce = CHECKENABLE.on; 693 return true; 694 } 695 else if (checkarg == "=off") 696 { 697 ce = CHECKENABLE.off; 698 return true; 699 } 700 } 701 return false; 702 } 703 704 const(char)[] checkarg = arg[len .. $]; 705 if (checkarg == "on") 706 { 707 params.useAssert = CHECKENABLE.on; 708 params.useArrayBounds = CHECKENABLE.on; 709 params.useIn = CHECKENABLE.on; 710 params.useInvariants = CHECKENABLE.on; 711 params.useOut = CHECKENABLE.on; 712 params.useSwitchError = CHECKENABLE.on; 713 } 714 else if (checkarg == "off") 715 { 716 params.useAssert = CHECKENABLE.off; 717 params.useArrayBounds = CHECKENABLE.off; 718 params.useIn = CHECKENABLE.off; 719 params.useInvariants = CHECKENABLE.off; 720 params.useOut = CHECKENABLE.off; 721 params.useSwitchError = CHECKENABLE.off; 722 } 723 else if (!(check(checkarg, "assert", params.useAssert) || 724 check(checkarg, "bounds", params.useArrayBounds) || 725 check(checkarg, "in", params.useIn ) || 726 check(checkarg, "invariant", params.useInvariants ) || 727 check(checkarg, "out", params.useOut ) || 728 check(checkarg, "switch", params.useSwitchError))) 729 { 730 errorInvalidSwitch(p); 731 params.help.check = true; 732 return false; 733 } 734 } 735 else if (startsWith(p + 1, "color")) // https://dlang.org/dmd.html#switch-color 736 { 737 // Parse: 738 // -color 739 // -color=auto|on|off 740 if (p[6] == '=') 741 { 742 switch(arg[7 .. $]) 743 { 744 case "on": 745 params.v.color = true; 746 break; 747 case "off": 748 params.v.color = false; 749 break; 750 case "auto": 751 break; 752 default: 753 errorInvalidSwitch(p, "Available options for `-color` are `on`, `off` and `auto`"); 754 return true; 755 } 756 } 757 else if (p[6]) 758 goto Lerror; 759 else 760 params.v.color = true; 761 } 762 else if (startsWith(p + 1, "conf=")) // https://dlang.org/dmd.html#switch-conf 763 { 764 // ignore, already handled above 765 } 766 else if (startsWith(p + 1, "cov")) // https://dlang.org/dmd.html#switch-cov 767 { 768 params.cov = true; 769 // Parse: 770 // -cov 771 // -cov=ctfe 772 // -cov=nnn 773 if (arg == "-cov=ctfe") 774 { 775 params.ctfe_cov = true; 776 } 777 else if (p[4] == '=') 778 { 779 if (!params.covPercent.parseDigits(p.toDString()[5 .. $], 100)) 780 { 781 errorInvalidSwitch(p, "Only a number between 0 and 100 can be passed to `-cov=<num>`"); 782 return true; 783 } 784 } 785 else if (p[4]) 786 goto Lerror; 787 } 788 else if (arg == "-shared") 789 driverParams.dll = true; 790 else if (arg == "-fIBT") 791 { 792 driverParams.ibt = true; 793 } 794 else if (arg == "-fPIC") 795 { 796 driverParams.pic = PIC.pic; 797 } 798 else if (arg == "-fPIE") 799 { 800 driverParams.pic = PIC.pie; 801 } 802 else if (arg == "-map") // https://dlang.org/dmd.html#switch-map 803 driverParams.map = true; 804 else if (arg == "-multiobj") 805 params.multiobj = true; 806 else if (startsWith(p + 1, "mixin=")) 807 { 808 auto tmp = p + 6 + 1; 809 if (!tmp[0]) 810 goto Lnoarg; 811 params.mixinOut.doOutput = true; 812 params.mixinOut.name = mem.xstrdup(tmp).toDString; 813 } 814 else if (arg == "-g") // https://dlang.org/dmd.html#switch-g 815 driverParams.symdebug = true; 816 else if (startsWith(p + 1, "gdwarf")) // https://dlang.org/dmd.html#switch-gdwarf 817 { 818 if (driverParams.dwarf) 819 { 820 error("`-gdwarf=<version>` can only be provided once"); 821 break; 822 } 823 driverParams.symdebug = true; 824 825 enum len = "-gdwarf=".length; 826 // Parse: 827 // -gdwarf=version 828 if (arg.length < len || !driverParams.dwarf.parseDigits(arg[len .. $], 5) || driverParams.dwarf < 3) 829 { 830 error("`-gdwarf=<version>` requires a valid version [3|4|5]", p); 831 return false; 832 } 833 } 834 else if (arg == "-gf") 835 { 836 driverParams.symdebug = true; 837 driverParams.symdebugref = true; 838 } 839 else if (arg == "-gs") // https://dlang.org/dmd.html#switch-gs 840 driverParams.alwaysframe = true; 841 else if (arg == "-gx") // https://dlang.org/dmd.html#switch-gx 842 driverParams.stackstomp = true; 843 else if (arg == "-lowmem") // https://dlang.org/dmd.html#switch-lowmem 844 { 845 // ignore, already handled in C main 846 } 847 else if (arg.length > 6 && arg[0..6] == "--DRT-") 848 { 849 continue; // skip druntime options, e.g. used to configure the GC 850 } 851 else if (arg == "-m32") // https://dlang.org/dmd.html#switch-m32 852 { 853 target.isX86_64 = false; 854 target.omfobj = false; 855 } 856 else if (arg == "-m64") // https://dlang.org/dmd.html#switch-m64 857 { 858 target.isX86_64 = true; 859 target.omfobj = false; 860 } 861 else if (arg == "-m32mscoff") // https://dlang.org/dmd.html#switch-m32mscoff 862 { 863 target.isX86_64 = false; 864 target.omfobj = false; 865 } 866 else if (arg == "-m32omf") // https://dlang.org/dmd.html#switch-m32omfobj 867 { 868 target.isX86_64 = false; 869 target.omfobj = true; 870 } 871 else if (startsWith(p + 1, "mscrtlib=")) 872 { 873 driverParams.mscrtlib = arg[10 .. $]; 874 } 875 else if (startsWith(p + 1, "profile")) // https://dlang.org/dmd.html#switch-profile 876 { 877 // Parse: 878 // -profile 879 // -profile=gc 880 if (p[8] == '=') 881 { 882 if (arg[9 .. $] == "gc") 883 params.tracegc = true; 884 else 885 { 886 errorInvalidSwitch(p, "Only `gc` is allowed for `-profile`"); 887 return true; 888 } 889 } 890 else if (p[8]) 891 goto Lerror; 892 else 893 params.trace = true; 894 } 895 else if (arg == "-v") // https://dlang.org/dmd.html#switch-v 896 params.v.verbose = true; 897 else if (arg == "-vcg-ast") 898 params.vcg_ast = true; 899 else if (arg == "-vasm") // https://dlang.org/dmd.html#switch-vasm 900 driverParams.vasm = true; 901 else if (arg == "-vtls") // https://dlang.org/dmd.html#switch-vtls 902 params.v.tls = true; 903 else if (startsWith(p + 1, "vtemplates")) // https://dlang.org/dmd.html#switch-vtemplates 904 { 905 params.v.templates = true; 906 if (p[1 + "vtemplates".length] == '=') 907 { 908 const(char)[] style = arg[1 + "vtemplates=".length .. $]; 909 switch (style) 910 { 911 case "list-instances": 912 params.v.templatesListInstances = true; 913 break; 914 default: 915 error("unknown vtemplates style '%.*s', must be 'list-instances'", cast(int) style.length, style.ptr); 916 } 917 } 918 } 919 else if (arg == "-vcolumns") // https://dlang.org/dmd.html#switch-vcolumns 920 params.v.showColumns = true; 921 else if (arg == "-vgc") // https://dlang.org/dmd.html#switch-vgc 922 params.v.gc = true; 923 else if (startsWith(p + 1, "verrors")) // https://dlang.org/dmd.html#switch-verrors 924 { 925 if (p[8] != '=') 926 { 927 errorInvalidSwitch(p, "Expected argument following `-verrors , e.g. `-verrors=100`"); 928 return true; 929 } 930 if (startsWith(p + 9, "spec")) 931 { 932 params.v.showGaggedErrors = true; 933 } 934 else if (startsWith(p + 9, "context")) 935 { 936 params.v.printErrorContext = true; 937 } 938 else if (!params.v.errorLimit.parseDigits(p.toDString()[9 .. $])) 939 { 940 errorInvalidSwitch(p, "Only number, `spec`, or `context` are allowed for `-verrors`"); 941 return true; 942 } 943 } 944 else if (startsWith(p + 1, "verror-supplements")) 945 { 946 if (!params.v.errorSupplementLimit.parseDigits(p.toDString()[20 .. $])) 947 { 948 errorInvalidSwitch(p, "Only a number is allowed for `-verror-supplements`"); 949 return true; 950 } 951 } 952 else if (startsWith(p + 1, "verror-style=")) 953 { 954 const(char)[] style = arg["verror-style=".length + 1 .. $]; 955 956 switch (style) 957 { 958 case "digitalmars": 959 params.v.messageStyle = MessageStyle.digitalmars; 960 break; 961 case "gnu": 962 params.v.messageStyle = MessageStyle.gnu; 963 break; 964 default: 965 error("unknown error style '%.*s', must be 'digitalmars' or 'gnu'", cast(int) style.length, style.ptr); 966 } 967 } 968 else if (startsWith(p + 1, "target")) 969 { 970 enum len = "-target=".length; 971 const triple = Triple(p + len); 972 target.setTriple(triple); 973 } 974 else if (startsWith(p + 1, "mcpu")) // https://dlang.org/dmd.html#switch-mcpu 975 { 976 enum len = "-mcpu=".length; 977 // Parse: 978 // -mcpu=identifier 979 mixin(checkOptionsMixin("mcpu", 980 "`-mcpu=<architecture>` requires an architecture")); 981 if (Identifier.isValidIdentifier(p + len)) 982 { 983 const ident = p + len; 984 switch (ident.toDString()) 985 { 986 case "baseline": 987 target.cpu = CPU.baseline; 988 break; 989 case "avx": 990 target.cpu = CPU.avx; 991 break; 992 case "avx2": 993 target.cpu = CPU.avx2; 994 break; 995 case "native": 996 target.cpu = CPU.native; 997 break; 998 default: 999 errorInvalidSwitch(p, "Only `baseline`, `avx`, `avx2` or `native` are allowed for `-mcpu`"); 1000 params.help.mcpu = true; 1001 return false; 1002 } 1003 } 1004 else 1005 { 1006 errorInvalidSwitch(p, "Only `baseline`, `avx`, `avx2` or `native` are allowed for `-mcpu`"); 1007 params.help.mcpu = true; 1008 return false; 1009 } 1010 } 1011 else if (startsWith(p + 1, "os")) // https://dlang.org/dmd.html#switch-os 1012 { 1013 enum len = "-os=".length; 1014 // Parse: 1015 // -os=identifier 1016 immutable string msg = "Only `host`, `linux`, `windows`, `osx`,`openbsd`, `freebsd`, `solaris`, `dragonflybsd` allowed for `-os`"; 1017 if (Identifier.isValidIdentifier(p + len)) 1018 { 1019 const ident = p + len; 1020 switch (ident.toDString()) 1021 { 1022 case "host": target.os = defaultTargetOS(); break; 1023 case "linux": target.os = Target.OS.linux; break; 1024 case "windows": target.os = Target.OS.Windows; break; 1025 case "osx": target.os = Target.OS.OSX; break; 1026 case "openbsd": target.os = Target.OS.OpenBSD; break; 1027 case "freebsd": target.os = Target.OS.FreeBSD; break; 1028 case "solaris": target.os = Target.OS.Solaris; break; 1029 case "dragonflybsd": target.os = Target.OS.DragonFlyBSD; break; 1030 default: 1031 errorInvalidSwitch(p, msg); 1032 return false; 1033 } 1034 } 1035 else 1036 { 1037 errorInvalidSwitch(p, msg); 1038 return false; 1039 } 1040 } 1041 else if (startsWith(p + 1, "extern-std")) // https://dlang.org/dmd.html#switch-extern-std 1042 { 1043 enum len = "-extern-std=".length; 1044 // Parse: 1045 // -extern-std=identifier 1046 mixin(checkOptionsMixin("externStd", 1047 "`-extern-std=<standard>` requires a standard")); 1048 const(char)[] cpprev = arg[len .. $]; 1049 1050 switch (cpprev) 1051 { 1052 case "c++98": 1053 params.cplusplus = CppStdRevision.cpp98; 1054 break; 1055 case "c++11": 1056 params.cplusplus = CppStdRevision.cpp11; 1057 break; 1058 case "c++14": 1059 params.cplusplus = CppStdRevision.cpp14; 1060 break; 1061 case "c++17": 1062 params.cplusplus = CppStdRevision.cpp17; 1063 break; 1064 case "c++20": 1065 params.cplusplus = CppStdRevision.cpp20; 1066 break; 1067 default: 1068 error("switch `%s` is invalid", p); 1069 params.help.externStd = true; 1070 return false; 1071 } 1072 } 1073 else if (startsWith(p + 1, "transition")) // https://dlang.org/dmd.html#switch-transition 1074 { 1075 enum len = "-transition=".length; 1076 // Parse: 1077 // -transition=number 1078 mixin(checkOptionsMixin("transition", 1079 "`-transition=<name>` requires a name")); 1080 if (!parseCLIOption!("transition", Usage.transitions)(params, arg)) 1081 { 1082 // Legacy -transition flags 1083 // Before DMD 2.085, DMD `-transition` was used for all language flags 1084 // These are kept for backwards compatibility, but no longer documented 1085 if (isdigit(cast(char)p[len])) 1086 { 1087 uint num; 1088 if (!num.parseDigits(p.toDString()[len .. $])) 1089 goto Lerror; 1090 1091 // Bugzilla issue number 1092 switch (num) 1093 { 1094 case 3449: 1095 params.v.field = true; 1096 break; 1097 case 14_246: 1098 params.dtorFields = FeatureState.enabled; 1099 break; 1100 case 14_488: 1101 break; 1102 case 16_997: 1103 deprecation(Loc.initial, "`-transition=16997` is now the default behavior"); 1104 break; 1105 default: 1106 error("transition `%s` is invalid", p); 1107 params.help.transition = true; 1108 return false; 1109 } 1110 } 1111 else if (Identifier.isValidIdentifier(p + len)) 1112 { 1113 const ident = p + len; 1114 switch (ident.toDString()) 1115 { 1116 case "dtorfields": 1117 params.dtorFields = FeatureState.enabled; 1118 break; 1119 case "intpromote": 1120 deprecation(Loc.initial, "`-transition=intpromote` is now the default behavior"); 1121 break; 1122 default: 1123 error("transition `%s` is invalid", p); 1124 params.help.transition = true; 1125 return false; 1126 } 1127 } 1128 errorInvalidSwitch(p); 1129 params.help.transition = true; 1130 return false; 1131 } 1132 } 1133 else if (startsWith(p + 1, "preview") ) // https://dlang.org/dmd.html#switch-preview 1134 { 1135 enum len = "-preview=".length; 1136 // Parse: 1137 // -preview=name 1138 mixin(checkOptionsMixin("preview", 1139 "`-preview=<name>` requires a name")); 1140 1141 if (!parseCLIOption!("preview", Usage.previews)(params, arg)) 1142 { 1143 error("preview `%s` is invalid", p); 1144 params.help.preview = true; 1145 return false; 1146 } 1147 1148 if (params.useDIP1021) 1149 params.useDIP1000 = FeatureState.enabled; // dip1021 implies dip1000 1150 1151 // copy previously standalone flags from -transition 1152 // -preview=dip1000 implies -preview=dip25 too 1153 if (params.useDIP1000 == FeatureState.enabled) 1154 params.useDIP25 = FeatureState.enabled; 1155 } 1156 else if (startsWith(p + 1, "revert") ) // https://dlang.org/dmd.html#switch-revert 1157 { 1158 enum len = "-revert=".length; 1159 // Parse: 1160 // -revert=name 1161 mixin(checkOptionsMixin("revert", 1162 "`-revert=<name>` requires a name")); 1163 1164 if (!parseCLIOption!("revert", Usage.reverts)(params, arg)) 1165 { 1166 error("revert `%s` is invalid", p); 1167 params.help.revert = true; 1168 return false; 1169 } 1170 } 1171 else if (arg == "-w") // https://dlang.org/dmd.html#switch-w 1172 params.warnings = DiagnosticReporting.error; 1173 else if (arg == "-wi") // https://dlang.org/dmd.html#switch-wi 1174 params.warnings = DiagnosticReporting.inform; 1175 else if (arg == "-wo") // https://dlang.org/dmd.html#switch-wo 1176 { 1177 // Obsolete features has been obsoleted until a DIP for "additions" 1178 // has been drafted and ratified in the language spec. 1179 // Rather, these old features will just be accepted without warning. 1180 } 1181 else if (arg == "-O") // https://dlang.org/dmd.html#switch-O 1182 driverParams.optimize = true; 1183 else if (arg == "-o-") // https://dlang.org/dmd.html#switch-o- 1184 params.obj = false; 1185 else if (p[1] == 'o') 1186 { 1187 const(char)* path; 1188 switch (p[2]) 1189 { 1190 case 'd': // https://dlang.org/dmd.html#switch-od 1191 if (!p[3]) 1192 goto Lnoarg; 1193 path = p + 3 + (p[3] == '='); 1194 version (Windows) 1195 { 1196 path = toWinPath(path); 1197 } 1198 params.objdir = path.toDString; 1199 break; 1200 case 'f': // https://dlang.org/dmd.html#switch-of 1201 if (!p[3]) 1202 goto Lnoarg; 1203 path = p + 3 + (p[3] == '='); 1204 version (Windows) 1205 { 1206 path = toWinPath(path); 1207 } 1208 params.objname = path.toDString; 1209 break; 1210 case 'p': // https://dlang.org/dmd.html#switch-op 1211 if (p[3]) 1212 goto Lerror; 1213 params.preservePaths = true; 1214 break; 1215 case 0: 1216 error("-o no longer supported, use -of or -od"); 1217 break; 1218 default: 1219 goto Lerror; 1220 } 1221 } 1222 else if (p[1] == 'D') // https://dlang.org/dmd.html#switch-D 1223 { 1224 params.ddoc.doOutput = true; 1225 switch (p[2]) 1226 { 1227 case 'd': // https://dlang.org/dmd.html#switch-Dd 1228 if (!p[3]) 1229 goto Lnoarg; 1230 params.ddoc.dir = (p + 3 + (p[3] == '=')).toDString(); 1231 break; 1232 case 'f': // https://dlang.org/dmd.html#switch-Df 1233 if (!p[3]) 1234 goto Lnoarg; 1235 params.ddoc.name = (p + 3 + (p[3] == '=')).toDString(); 1236 break; 1237 case 0: 1238 break; 1239 default: 1240 goto Lerror; 1241 } 1242 } 1243 else if (p[1] == 'H' && p[2] == 'C') // https://dlang.org/dmd.html#switch-HC 1244 { 1245 params.cxxhdr.doOutput = true; 1246 switch (p[3]) 1247 { 1248 case 'd': // https://dlang.org/dmd.html#switch-HCd 1249 if (!p[4]) 1250 goto Lnoarg; 1251 params.cxxhdr.dir = (p + 4 + (p[4] == '=')).toDString; 1252 break; 1253 case 'f': // https://dlang.org/dmd.html#switch-HCf 1254 if (!p[4]) 1255 goto Lnoarg; 1256 params.cxxhdr.name = (p + 4 + (p[4] == '=')).toDString; 1257 break; 1258 case '=': 1259 enum len = "-HC=".length; 1260 mixin(checkOptionsMixin("hc", "`-HC=<mode>` requires a valid mode")); 1261 const mode = arg[len .. $]; 1262 switch (mode) 1263 { 1264 case "silent": 1265 /* already set above */ 1266 break; 1267 case "verbose": 1268 params.cxxhdr.fullOutput = true; 1269 break; 1270 default: 1271 errorInvalidSwitch(p); 1272 params.help.hc = true; 1273 return false; 1274 } 1275 break; 1276 case 0: 1277 break; 1278 default: 1279 goto Lerror; 1280 } 1281 } 1282 else if (p[1] == 'H') // https://dlang.org/dmd.html#switch-H 1283 { 1284 params.dihdr.doOutput = true; 1285 switch (p[2]) 1286 { 1287 case 'd': // https://dlang.org/dmd.html#switch-Hd 1288 if (!p[3]) 1289 goto Lnoarg; 1290 params.dihdr.dir = (p + 3 + (p[3] == '=')).toDString; 1291 break; 1292 case 'f': // https://dlang.org/dmd.html#switch-Hf 1293 if (!p[3]) 1294 goto Lnoarg; 1295 params.dihdr.name = (p + 3 + (p[3] == '=')).toDString; 1296 break; 1297 case 0: 1298 break; 1299 default: 1300 goto Lerror; 1301 } 1302 } 1303 else if (startsWith(p + 1, "Xcc=")) 1304 { 1305 params.linkswitches.push(p + 5); 1306 params.linkswitchIsForCC.push(true); 1307 } 1308 else if (p[1] == 'X') // https://dlang.org/dmd.html#switch-X 1309 { 1310 params.json.doOutput = true; 1311 switch (p[2]) 1312 { 1313 case 'f': // https://dlang.org/dmd.html#switch-Xf 1314 if (!p[3]) 1315 goto Lnoarg; 1316 params.json.name = (p + 3 + (p[3] == '=')).toDString; 1317 break; 1318 case 'i': 1319 if (!p[3]) 1320 goto Lnoarg; 1321 if (p[3] != '=') 1322 goto Lerror; 1323 if (!p[4]) 1324 goto Lnoarg; 1325 1326 { 1327 auto flag = tryParseJsonField(p + 4); 1328 if (!flag) 1329 { 1330 error("unknown JSON field `-Xi=%s`, expected one of " ~ jsonFieldNames, p + 4); 1331 continue; 1332 } 1333 global.params.jsonFieldFlags |= flag; 1334 } 1335 break; 1336 case 0: 1337 break; 1338 default: 1339 goto Lerror; 1340 } 1341 } 1342 else if (arg == "-ignore") // https://dlang.org/dmd.html#switch-ignore 1343 params.ignoreUnsupportedPragmas = true; 1344 else if (arg == "-inline") // https://dlang.org/dmd.html#switch-inline 1345 { 1346 params.useInline = true; 1347 params.dihdr.fullOutput = true; 1348 } 1349 else if (arg == "-i") 1350 includeImports = true; 1351 else if (startsWith(p + 1, "i=")) 1352 { 1353 includeImports = true; 1354 if (!p[3]) 1355 { 1356 error("invalid option '%s', module patterns cannot be empty", p); 1357 } 1358 else 1359 { 1360 // NOTE: we could check that the argument only contains valid "module-pattern" characters. 1361 // Invalid characters doesn't break anything but an error message to the user might 1362 // be nice. 1363 includeModulePatterns.push(p + 3); 1364 } 1365 } 1366 else if (arg == "-dip25") // https://dlang.org/dmd.html#switch-dip25 1367 { 1368 // @@@ DEPRECATION 2.112 @@@ 1369 deprecation(Loc.initial, "`-dip25` no longer has any effect"); 1370 params.useDIP25 = FeatureState.enabled; 1371 } 1372 else if (arg == "-dip1000") 1373 { 1374 params.useDIP25 = FeatureState.enabled; 1375 params.useDIP1000 = FeatureState.enabled; 1376 } 1377 else if (arg == "-dip1008") 1378 { 1379 params.ehnogc = true; 1380 } 1381 else if (arg == "-lib") // https://dlang.org/dmd.html#switch-lib 1382 driverParams.lib = true; 1383 else if (arg == "-nofloat") 1384 driverParams.nofloat = true; 1385 else if (arg == "-quiet") 1386 { 1387 // Ignore 1388 } 1389 else if (arg == "-release") // https://dlang.org/dmd.html#switch-release 1390 params.release = true; 1391 else if (arg == "-betterC") // https://dlang.org/dmd.html#switch-betterC 1392 { 1393 params.betterC = true; 1394 params.allInst = true; 1395 } 1396 else if (arg == "-noboundscheck") // https://dlang.org/dmd.html#switch-noboundscheck 1397 { 1398 params.boundscheck = CHECKENABLE.off; 1399 } 1400 else if (startsWith(p + 1, "boundscheck")) // https://dlang.org/dmd.html#switch-boundscheck 1401 { 1402 // Parse: 1403 // -boundscheck=[on|safeonly|off] 1404 if (p[12] == '=') 1405 { 1406 const(char)[] boundscheck = arg[13 .. $]; 1407 1408 switch (boundscheck) 1409 { 1410 case "on": 1411 params.boundscheck = CHECKENABLE.on; 1412 break; 1413 case "safeonly": 1414 params.boundscheck = CHECKENABLE.safeonly; 1415 break; 1416 case "off": 1417 params.boundscheck = CHECKENABLE.off; 1418 break; 1419 default: 1420 goto Lerror; 1421 } 1422 } 1423 else 1424 goto Lerror; 1425 } 1426 else if (arg == "-nothrow") // https://dlang.org/dmd.html#switch-nothrow 1427 { 1428 params.useExceptions = false; 1429 } 1430 else if (arg == "-unittest") 1431 params.useUnitTests = true; 1432 else if (p[1] == 'I') // https://dlang.org/dmd.html#switch-I 1433 { 1434 if (!params.imppath) 1435 params.imppath = new Strings(); 1436 params.imppath.push(p + 2 + (p[2] == '=')); 1437 } 1438 else if (p[1] == 'm' && p[2] == 'v' && p[3] == '=') // https://dlang.org/dmd.html#switch-mv 1439 { 1440 if (p[4] && strchr(p + 5, '=')) 1441 { 1442 params.modFileAliasStrings.push(p + 4); 1443 } 1444 else 1445 goto Lerror; 1446 } 1447 else if (p[1] == 'J') // https://dlang.org/dmd.html#switch-J 1448 { 1449 if (!params.fileImppath) 1450 params.fileImppath = new Strings(); 1451 params.fileImppath.push(p + 2 + (p[2] == '=')); 1452 } 1453 else if (startsWith(p + 1, "debug") && p[6] != 'l') // https://dlang.org/dmd.html#switch-debug 1454 { 1455 // Parse: 1456 // -debug 1457 // -debug=number 1458 // -debug=identifier 1459 if (p[6] == '=') 1460 { 1461 if (isdigit(cast(char)p[7])) 1462 { 1463 if (!params.debuglevel.parseDigits(p.toDString()[7 .. $])) 1464 goto Lerror; 1465 1466 // @@@DEPRECATED_2.111@@@ 1467 // Deprecated in 2.101, remove in 2.111 1468 deprecation(Loc.initial, "`-debug=number` is deprecated, use debug identifiers instead"); 1469 } 1470 else if (Identifier.isValidIdentifier(p + 7)) 1471 { 1472 DebugCondition.addGlobalIdent((p + 7).toDString()); 1473 } 1474 else 1475 goto Lerror; 1476 } 1477 else if (p[6]) 1478 goto Lerror; 1479 else 1480 params.debuglevel = 1; 1481 } 1482 else if (startsWith(p + 1, "version")) // https://dlang.org/dmd.html#switch-version 1483 { 1484 // Parse: 1485 // -version=number 1486 // -version=identifier 1487 if (p[8] == '=') 1488 { 1489 if (isdigit(cast(char)p[9])) 1490 { 1491 if (!params.versionlevel.parseDigits(p.toDString()[9 .. $])) 1492 goto Lerror; 1493 1494 // @@@DEPRECATED_2.111@@@ 1495 // Deprecated in 2.101, remove in 2.111 1496 deprecation(Loc.initial, "`-version=number` is deprecated, use version identifiers instead"); 1497 } 1498 else if (Identifier.isValidIdentifier(p + 9)) 1499 { 1500 VersionCondition.addGlobalIdent((p+9).toDString()); 1501 } 1502 else 1503 goto Lerror; 1504 } 1505 else 1506 goto Lerror; 1507 } 1508 else if (arg == "--b") 1509 driverParams.debugb = true; 1510 else if (arg == "--c") 1511 driverParams.debugc = true; 1512 else if (arg == "--f") 1513 driverParams.debugf = true; 1514 else if (arg == "--help" || 1515 arg == "-h") 1516 { 1517 params.help.usage = true; 1518 return false; 1519 } 1520 else if (arg == "--r") 1521 driverParams.debugr = true; 1522 else if (arg == "--version") 1523 { 1524 params.v.logo = true; 1525 return false; 1526 } 1527 else if (arg == "--x") 1528 driverParams.debugx = true; 1529 else if (arg == "--y") 1530 driverParams.debugy = true; 1531 else if (p[1] == 'L') // https://dlang.org/dmd.html#switch-L 1532 { 1533 params.linkswitches.push(p + 2 + (p[2] == '=')); 1534 params.linkswitchIsForCC.push(false); 1535 } 1536 else if (p[1] == 'P') // https://dlang.org/dmd.html#switch-P 1537 { 1538 params.cppswitches.push(p + 2 + (p[2] == '=')); 1539 } 1540 else if (startsWith(p + 1, "defaultlib=")) // https://dlang.org/dmd.html#switch-defaultlib 1541 { 1542 driverParams.defaultlibname = (p + 1 + 11).toDString; 1543 } 1544 else if (startsWith(p + 1, "debuglib=")) // https://dlang.org/dmd.html#switch-debuglib 1545 { 1546 driverParams.debuglibname = (p + 1 + 9).toDString; 1547 } 1548 else if (startsWith(p + 1, "deps")) // https://dlang.org/dmd.html#switch-deps 1549 { 1550 if (params.moduleDeps.doOutput) 1551 { 1552 error("-deps[=file] can only be provided once!"); 1553 break; 1554 } 1555 if (p[5] == '=') 1556 { 1557 params.moduleDeps.name = (p + 1 + 5).toDString; 1558 if (!params.moduleDeps.name[0]) 1559 goto Lnoarg; 1560 } 1561 else if (p[5] != '\0') 1562 { 1563 // Else output to stdout. 1564 goto Lerror; 1565 } 1566 params.moduleDeps.buffer = new OutBuffer(); 1567 } 1568 else if (startsWith(p + 1, "makedeps")) // https://dlang.org/dmd.html#switch-makedeps 1569 { 1570 if (params.makeDeps.name) 1571 { 1572 error("-makedeps[=file] can only be provided once!"); 1573 break; 1574 } 1575 if (p[9] == '=') 1576 { 1577 if (p[10] == '\0') 1578 { 1579 error("expected filename after -makedeps="); 1580 break; 1581 } 1582 params.makeDeps.name = (p + 10).toDString; 1583 } 1584 else if (p[9] != '\0') 1585 { 1586 goto Lerror; 1587 } 1588 // Else output to stdout. 1589 params.makeDeps.doOutput = true; 1590 } 1591 else if (arg == "-main") // https://dlang.org/dmd.html#switch-main 1592 { 1593 params.addMain = true; 1594 } 1595 else if (startsWith(p + 1, "man")) // https://dlang.org/dmd.html#switch-man 1596 { 1597 params.help.manual = true; 1598 return false; 1599 } 1600 else if (arg == "-run") // https://dlang.org/dmd.html#switch-run 1601 { 1602 params.run = true; 1603 size_t length = argc - i - 1; 1604 if (length) 1605 { 1606 const(char)[] runarg = arguments[i + 1].toDString(); 1607 const(char)[] ext = FileName.ext(runarg); 1608 if (ext && 1609 FileName.equals(ext, mars_ext) == 0 && 1610 FileName.equals(ext, hdr_ext) == 0 && 1611 FileName.equals(ext, i_ext) == 0 && 1612 FileName.equals(ext, c_ext) == 0) 1613 { 1614 error("-run must be followed by a source file, not '%s'", arguments[i + 1]); 1615 break; 1616 } 1617 if (runarg == "-") 1618 files.push("__stdin.d"); 1619 else 1620 files.push(arguments[i + 1]); 1621 params.runargs.setDim(length - 1); 1622 for (size_t j = 0; j < length - 1; ++j) 1623 { 1624 params.runargs[j] = arguments[i + 2 + j]; 1625 } 1626 i += length; 1627 } 1628 else 1629 { 1630 params.run = false; 1631 goto Lnoarg; 1632 } 1633 } 1634 else if (p[1] == '\0') 1635 files.push("__stdin.d"); 1636 else 1637 { 1638 Lerror: 1639 error("unrecognized switch '%s'", arguments[i]); 1640 continue; 1641 Lnoarg: 1642 error("argument expected for switch '%s'", arguments[i]); 1643 continue; 1644 } 1645 } 1646 return errors; 1647 } 1648 1649 /// Sets the boolean for a flag with the given name 1650 private static void setFlagFor(string name, ref bool b) @safe 1651 { 1652 b = name != "revert"; 1653 } 1654 1655 /// Sets the FeatureState for a flag with the given name 1656 private static void setFlagFor(string name, ref FeatureState s) @safe 1657 { 1658 s = name != "revert" ? FeatureState.enabled : FeatureState.disabled; 1659 } 1660 1661 /** 1662 Creates the module based on the file provided 1663 1664 The file is dispatched in one of the various arrays 1665 (global.params.{ddoc.files,dllfiles,jsonfiles,etc...}) 1666 according to its extension. 1667 If it is a binary file, it is added to libmodules. 1668 1669 Params: 1670 file = File name to dispatch 1671 libmodules = Array to which binaries (shared/static libs and object files) 1672 will be appended 1673 target = target system 1674 1675 Returns: 1676 A D module 1677 */ 1678 private 1679 Module createModule(const(char)* file, ref Strings libmodules, const ref Target target) 1680 { 1681 const(char)[] name; 1682 version (Windows) 1683 { 1684 file = toWinPath(file); 1685 } 1686 const(char)[] p = file.toDString(); 1687 p = FileName.name(p); // strip path 1688 const(char)[] ext = FileName.ext(p); 1689 if (!ext) 1690 { 1691 if (!p.length) 1692 { 1693 error(Loc.initial, "invalid file name '%s'", file); 1694 fatal(); 1695 } 1696 auto id = Identifier.idPool(p); 1697 return new Module(file.toDString, id, global.params.ddoc.doOutput, global.params.dihdr.doOutput); 1698 } 1699 1700 /* Deduce what to do with a file based on its extension 1701 */ 1702 if (FileName.equals(ext, target.obj_ext)) 1703 { 1704 global.params.objfiles.push(file); 1705 libmodules.push(file); 1706 return null; 1707 } 1708 if (FileName.equals(ext, target.lib_ext)) 1709 { 1710 global.params.libfiles.push(file); 1711 libmodules.push(file); 1712 return null; 1713 } 1714 if (target.os & (Target.OS.linux | Target.OS.OSX| Target.OS.FreeBSD | Target.OS.OpenBSD | Target.OS.Solaris | Target.OS.DragonFlyBSD)) 1715 { 1716 if (FileName.equals(ext, target.dll_ext)) 1717 { 1718 global.params.dllfiles.push(file); 1719 libmodules.push(file); 1720 return null; 1721 } 1722 } 1723 if (FileName.equals(ext, ddoc_ext)) 1724 { 1725 global.params.ddoc.files.push(file); 1726 return null; 1727 } 1728 if (FileName.equals(ext, json_ext)) 1729 { 1730 global.params.json.doOutput = true; 1731 global.params.json.name = file.toDString; 1732 return null; 1733 } 1734 if (FileName.equals(ext, map_ext)) 1735 { 1736 global.params.mapfile = file.toDString; 1737 return null; 1738 } 1739 if (target.os == Target.OS.Windows) 1740 { 1741 if (FileName.equals(ext, "res")) 1742 { 1743 global.params.resfile = file.toDString; 1744 return null; 1745 } 1746 if (FileName.equals(ext, "def")) 1747 { 1748 global.params.deffile = file.toDString; 1749 return null; 1750 } 1751 if (FileName.equals(ext, "exe")) 1752 { 1753 assert(0); // should have already been handled 1754 } 1755 } 1756 /* Examine extension to see if it is a valid 1757 * D, Ddoc or C source file extension 1758 */ 1759 if (FileName.equals(ext, mars_ext) || 1760 FileName.equals(ext, hdr_ext ) || 1761 FileName.equals(ext, dd_ext ) || 1762 FileName.equals(ext, c_ext ) || 1763 FileName.equals(ext, i_ext )) 1764 { 1765 name = FileName.removeExt(p); 1766 if (!name.length || name == ".." || name == ".") 1767 { 1768 error(Loc.initial, "invalid file name '%s'", file); 1769 fatal(); 1770 } 1771 } 1772 else 1773 { 1774 error(Loc.initial, "unrecognized file extension %.*s", cast(int)ext.length, ext.ptr); 1775 fatal(); 1776 } 1777 1778 /* At this point, name is the D source file name stripped of 1779 * its path and extension. 1780 */ 1781 auto id = Identifier.idPool(name); 1782 1783 return new Module(file.toDString, id, global.params.ddoc.doOutput, global.params.dihdr.doOutput); 1784 } 1785 1786 /** 1787 Creates the list of modules based on the files provided 1788 1789 Files are dispatched in the various arrays 1790 (global.params.{ddocfiles,dllfiles,jsonfiles,etc...}) 1791 according to their extension. 1792 Binary files are added to libmodules. 1793 1794 Params: 1795 files = File names to dispatch 1796 libmodules = Array to which binaries (shared/static libs and object files) 1797 will be appended 1798 target = target system 1799 1800 Returns: 1801 An array of path to D modules 1802 */ 1803 Modules createModules(ref Strings files, ref Strings libmodules, const ref Target target) 1804 { 1805 Modules modules; 1806 modules.reserve(files.length); 1807 bool firstmodule = true; 1808 foreach(file; files) 1809 { 1810 auto m = createModule(file, libmodules, target); 1811 1812 if (m is null) 1813 continue; 1814 1815 modules.push(m); 1816 if (firstmodule) 1817 { 1818 global.params.objfiles.push(m.objfile.toChars()); 1819 firstmodule = false; 1820 } 1821 } 1822 return modules; 1823 } 1824 1825 /// Returns: a compiled module (semantic3) containing an empty main() function, for the -main flag 1826 Module moduleWithEmptyMain() 1827 { 1828 auto result = new Module("__main.d", Identifier.idPool("__main"), false, false); 1829 // need 2 trailing nulls for sentinel and 2 for lexer 1830 auto data = arraydup("version(D_BetterC)extern(C)int main(){return 0;}else int main(){return 0;}\0\0\0\0"); 1831 result.src = cast(ubyte[]) data[0 .. $-4]; 1832 result.parse(); 1833 result.importedFrom = result; 1834 result.importAll(null); 1835 result.dsymbolSemantic(null); 1836 result.semantic2(null); 1837 result.semantic3(null); 1838 return result; 1839 }