1 2 /** 3 * Entry point for DMD console version. 4 * 5 * This modules defines the entry point (main) for DMD, as well as related 6 * utilities needed for arguments parsing, path manipulation, etc... 7 * This file is not shared with other compilers which use the DMD front-end. 8 * 9 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 10 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 11 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 12 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/main.d, _main.d) 13 * Documentation: https://dlang.org/phobos/dmd_main.html 14 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/main.d 15 */ 16 17 module dmd.main; 18 19 version (NoMain) {} else 20 { 21 22 import core.stdc.stdio; 23 import core.stdc.stdlib; 24 import core.stdc.string; 25 26 import dmd.arraytypes : Modules, Strings; 27 import dmd.astenums; 28 import dmd.common.outbuffer; 29 import dmd.compiler; 30 import dmd.cond; 31 import dmd.console; 32 import dmd.cpreprocess; 33 import dmd.dinifile; 34 import dmd.dinterpret; 35 import dmd.dmdparams; 36 import dmd.dsymbolsem; 37 import dmd.dtemplate; 38 import dmd.dtoh; 39 import dmd.glue : generateCodeAndWrite; 40 import dmd.dmodule; 41 import dmd.dmsc : backend_init, backend_term; 42 import dmd.doc; 43 import dmd.dsymbol; 44 import dmd.errors; 45 import dmd.expression; 46 import dmd.file_manager; 47 import dmd.hdrgen; 48 import dmd.globals; 49 import dmd.hdrgen; 50 import dmd.id; 51 import dmd.identifier; 52 import dmd.inline; 53 import dmd.link; 54 import dmd.location; 55 import dmd.mars; 56 import dmd.mtype; 57 import dmd.objc; 58 import dmd.root.file; 59 import dmd.root.filename; 60 import dmd.root.man; 61 import dmd.root.response; 62 import dmd.root.rmem; 63 import dmd.root.string; 64 import dmd.root.stringtable; 65 import dmd.semantic2; 66 import dmd.semantic3; 67 import dmd.target; 68 import dmd.utils; 69 import dmd.vsoptions; 70 71 /** 72 * DMD's entry point, C main. 73 * 74 * Without `-lowmem`, we need to switch to the bump-pointer allocation scheme 75 * right from the start, before any module ctors are run, so we need this hook 76 * before druntime is initialized and `_Dmain` is called. 77 * 78 * Returns: 79 * Return code of the application 80 */ extern (C) int main(int argc, char** argv) { 81 bool lowmem = false; 82 foreach (i; 1 .. argc) 83 { 84 if (strcmp(argv[i], "-lowmem") == 0) 85 { 86 lowmem = true; 87 break; 88 } 89 } 90 if (!lowmem) 91 { 92 __gshared string[] disable_options = [ "gcopt=disable:1" ]; 93 rt_options = disable_options; 94 mem.disableGC(); 95 } 96 // initialize druntime and call _Dmain() below 97 return _d_run_main(argc, argv, &_Dmain); 98 } 99 /** 100 * Manual D main (for druntime initialization), which forwards to `tryMain`. 101 * 102 * Returns: 103 * Return code of the application 104 */ extern (C) int _Dmain(char[][]) { 105 // possibly install memory error handler 106 version (DigitalMars) 107 { 108 installMemErrHandler(); 109 } 110 import core.runtime; 111 version(D_Coverage) 112 { 113 // for now we need to manually set the source path 114 string dirName(string path, char separator) 115 { 116 for (size_t i = path.length - 1; i > 0; i--) 117 { 118 if (path[i] == separator) 119 return path[0..i]; 120 } 121 return path; 122 } 123 version (Windows) 124 enum sourcePath = dirName(dirName(dirName(__FILE_FULL_PATH__, '\\'), '\\'), '\\'); 125 else 126 enum sourcePath = dirName(dirName(dirName(__FILE_FULL_PATH__, '/'), '/'), '/'); 127 dmd_coverSourcePath(sourcePath); 128 dmd_coverDestPath(sourcePath); 129 dmd_coverSetMerge(true); 130 } 131 scope(failure) stderr.printInternalFailure; 132 auto args = Runtime.cArgs(); 133 return tryMain(args.argc, cast(const(char)**)args.argv, global.params); 134 } 135 136 /************************************************************************************/ 137 138 private: 139 140 /** 141 * DMD's real entry point 142 * 143 * Parses command line arguments and config file, open and read all 144 * provided source file and do semantic analysis on them. 145 * 146 * Params: 147 * argc = Number of arguments passed via command line 148 * argv = Array of string arguments passed via command line 149 * 150 * Returns: 151 * Application return code 152 */ 153 private int tryMain(size_t argc, const(char)** argv, ref Param params) 154 { 155 Strings files; 156 Strings libmodules; 157 global._init(); 158 159 if (parseCommandlineAndConfig(argc, argv, params, files)) 160 return EXIT_FAILURE; 161 162 global.compileEnv.previewIn = global.params.previewIn; 163 global.compileEnv.ddocOutput = global.params.ddoc.doOutput; 164 165 if (params.help.usage) 166 { 167 usage(); 168 return EXIT_SUCCESS; 169 } 170 171 if (params.v.logo) 172 { 173 logo(); 174 return EXIT_SUCCESS; 175 } 176 177 /* 178 Prints a supplied usage text to the console and 179 returns the exit code for the help usage page. 180 181 Returns: 182 `EXIT_SUCCESS` if no errors occurred, `EXIT_FAILURE` otherwise 183 */ 184 static int printHelpUsage(string help) 185 { 186 printf("%.*s", cast(int)help.length, &help[0]); 187 return global.errors ? EXIT_FAILURE : EXIT_SUCCESS; 188 } 189 190 /* 191 Print a message to make it clear when warnings are treated as errors. 192 */ 193 static void errorOnWarning() 194 { 195 error(Loc.initial, "warnings are treated as errors"); 196 errorSupplemental(Loc.initial, "Use -wi if you wish to treat warnings only as informational."); 197 } 198 199 /* 200 Generates code to check for all `params` whether any usage page 201 has been requested. 202 If so, the generated code will print the help page of the flag 203 and return with an exit code. 204 205 Params: 206 params = parameters with `Usage` suffices in `params` for which 207 their truthness should be checked. 208 209 Returns: generated code for checking the usage pages of the provided `params`. 210 */ 211 static string generateUsageChecks(string[] params) 212 { 213 string s; 214 foreach (n; params) 215 { 216 s ~= q{ 217 if (params.help..}~n~q{) 218 return printHelpUsage(CLIUsage..}~n~q{Usage); 219 }; 220 } 221 return s; 222 } 223 import dmd.cli : CLIUsage; 224 mixin(generateUsageChecks(["mcpu", "transition", "check", "checkAction", 225 "preview", "revert", "externStd", "hc"])); 226 227 if (params.help.manual) 228 { 229 version (Windows) 230 { 231 browse("https://dlang.org/dmd-windows.html"); 232 } 233 version (linux) 234 { 235 browse("https://dlang.org/dmd-linux.html"); 236 } 237 version (OSX) 238 { 239 browse("https://dlang.org/dmd-osx.html"); 240 } 241 version (FreeBSD) 242 { 243 browse("https://dlang.org/dmd-freebsd.html"); 244 } 245 /*NOTE: No regular builds for openbsd/dragonflybsd (yet) */ 246 /* 247 version (OpenBSD) 248 { 249 browse("https://dlang.org/dmd-openbsd.html"); 250 } 251 version (DragonFlyBSD) 252 { 253 browse("https://dlang.org/dmd-dragonflybsd.html"); 254 } 255 */ 256 return EXIT_SUCCESS; 257 } 258 259 if (params.v.color) 260 global.console = cast(void*) createConsole(core.stdc.stdio.stderr); 261 262 target.setCPU(); 263 Loc.set(params.v.showColumns, params.v.messageStyle); 264 265 if (global.errors) 266 { 267 fatal(); 268 } 269 if (files.length == 0) 270 { 271 if (params.jsonFieldFlags) 272 { 273 Modules modules; // empty 274 generateJson(modules); 275 return EXIT_SUCCESS; 276 } 277 usage(); 278 return EXIT_FAILURE; 279 } 280 281 reconcileCommands(params, target); 282 setDefaultLibrary(params, target); 283 284 // Initialization 285 target._init(params); 286 Type._init(); 287 Id.initialize(); 288 Module._init(); 289 Expression._init(); 290 Objc._init(); 291 292 reconcileLinkRunLib(params, files.length, target.obj_ext); 293 version(CRuntime_Microsoft) 294 { 295 import dmd.root.longdouble; 296 initFPU(); 297 } 298 import dmd.root.ctfloat : CTFloat; 299 CTFloat.initialize(); 300 301 // Predefined version identifiers 302 addDefaultVersionIdentifiers(params, target); 303 304 if (params.v.verbose) 305 { 306 stdout.printPredefinedVersions(); 307 stdout.printGlobalConfigs(); 308 } 309 //printf("%d source files\n", cast(int) files.length); 310 311 // Build import search path 312 313 static Strings* buildPath(Strings* imppath) 314 { 315 Strings* result = null; 316 if (imppath) 317 { 318 foreach (const path; *imppath) 319 { 320 Strings* a = FileName.splitPath(path); 321 if (a) 322 { 323 if (!result) 324 result = new Strings(); 325 result.append(a); 326 } 327 } 328 } 329 return result; 330 } 331 332 if (params.mixinOut.doOutput) 333 { 334 params.mixinOut.buffer = cast(OutBuffer*)Mem.check(calloc(1, OutBuffer.sizeof)); 335 atexit(&flushMixins); // see comment for flushMixins 336 } 337 scope(exit) flushMixins(); 338 global.path = buildPath(params.imppath); 339 global.filePath = buildPath(params.fileImppath); 340 341 // Create Modules 342 Modules modules = createModules(files, libmodules, target); 343 // Read files 344 foreach (m; modules) 345 { 346 m.read(Loc.initial); 347 } 348 349 OutBuffer ddocbuf; // buffer for contents of .ddoc files 350 bool ddocbufIsRead; // set when ddocbuf is filled 351 352 /* Read ddoc macro files named by the DDOCFILE environment variable and command line 353 * and concatenate the text into ddocbuf 354 */ 355 void readDdocFiles(ref const Loc loc, ref const Strings ddocfiles, ref OutBuffer ddocbuf) 356 { 357 foreach (file; ddocfiles) 358 { 359 auto buffer = readFile(loc, file.toDString()); 360 // BUG: convert file contents to UTF-8 before use 361 const data = buffer.data; 362 //printf("file: '%.*s'\n", cast(int)data.length, data.ptr); 363 ddocbuf.write(data); 364 } 365 ddocbufIsRead = true; 366 } 367 368 // Parse files 369 bool anydocfiles = false; 370 OutBuffer ddocOutputText; 371 size_t filecount = modules.length; 372 for (size_t filei = 0, modi = 0; filei < filecount; filei++, modi++) 373 { 374 Module m = modules[modi]; 375 if (params.v.verbose) 376 message("parse %s", m.toChars()); 377 if (!Module.rootModule) 378 Module.rootModule = m; 379 m.importedFrom = m; // m.isRoot() == true 380 // if (!driverParams.oneobj || modi == 0 || m.isDocFile) 381 // m.deleteObjFile(); 382 383 m.parse(); 384 if (m.filetype == FileType.dhdr) 385 { 386 // Remove m's object file from list of object files 387 for (size_t j = 0; j < params.objfiles.length; j++) 388 { 389 if (m.objfile.toChars() == params.objfiles[j]) 390 { 391 params.objfiles.remove(j); 392 break; 393 } 394 } 395 if (params.objfiles.length == 0) 396 driverParams.link = false; 397 } 398 if (m.filetype == FileType.ddoc) 399 { 400 anydocfiles = true; 401 if (!ddocbufIsRead) 402 readDdocFiles(m.loc, global.params.ddoc.files, ddocbuf); 403 404 ddocOutputText.setsize(0); 405 gendocfile(m, ddocbuf[], global.datetime.ptr, global.errorSink, ddocOutputText); 406 407 if (!writeFile(m.loc, m.docfile.toString(), ddocOutputText[])) 408 fatal(); 409 410 // Remove m from list of modules 411 modules.remove(modi); 412 modi--; 413 // Remove m's object file from list of object files 414 for (size_t j = 0; j < params.objfiles.length; j++) 415 { 416 if (m.objfile.toChars() == params.objfiles[j]) 417 { 418 params.objfiles.remove(j); 419 break; 420 } 421 } 422 if (params.objfiles.length == 0) 423 driverParams.link = false; 424 } 425 } 426 427 if (anydocfiles && modules.length && (driverParams.oneobj || params.objname)) 428 { 429 error(Loc.initial, "conflicting Ddoc and obj generation options"); 430 fatal(); 431 } 432 if (global.errors) 433 fatal(); 434 435 if (params.dihdr.doOutput) 436 { 437 /* Generate 'header' import files. 438 * Since 'header' import files must be independent of command 439 * line switches and what else is imported, they are generated 440 * before any semantic analysis. 441 */ 442 OutBuffer buf; 443 foreach (m; modules) 444 { 445 if (m.filetype == FileType.dhdr) 446 continue; 447 if (params.v.verbose) 448 message("import %s", m.toChars()); 449 450 buf.reset(); // reuse the buffer 451 genhdrfile(m, buf); 452 if (!writeFile(m.loc, m.hdrfile.toString(), buf[])) 453 fatal(); 454 } 455 } 456 if (global.errors) 457 removeHdrFilesAndFail(params, modules); 458 459 // load all unconditional imports for better symbol resolving 460 foreach (m; modules) 461 { 462 if (params.v.verbose) 463 message("importall %s", m.toChars()); 464 m.importAll(null); 465 } 466 if (global.errors) 467 removeHdrFilesAndFail(params, modules); 468 469 backend_init(); 470 471 // Do semantic analysis 472 foreach (m; modules) 473 { 474 if (params.v.verbose) 475 message("semantic %s", m.toChars()); 476 m.dsymbolSemantic(null); 477 } 478 //if (global.errors) 479 // fatal(); 480 Module.runDeferredSemantic(); 481 if (Module.deferred.length) 482 { 483 for (size_t i = 0; i < Module.deferred.length; i++) 484 { 485 Dsymbol sd = Module.deferred[i]; 486 error(sd.loc, "%s `%s` unable to resolve forward reference in definition", sd.kind(), sd.toPrettyChars()); 487 } 488 //fatal(); 489 } 490 491 // Do pass 2 semantic analysis 492 foreach (m; modules) 493 { 494 if (params.v.verbose) 495 message("semantic2 %s", m.toChars()); 496 m.semantic2(null); 497 } 498 Module.runDeferredSemantic2(); 499 if (global.errors) 500 removeHdrFilesAndFail(params, modules); 501 502 // Do pass 3 semantic analysis 503 foreach (m; modules) 504 { 505 if (params.v.verbose) 506 message("semantic3 %s", m.toChars()); 507 m.semantic3(null); 508 } 509 if (includeImports) 510 { 511 // Note: DO NOT USE foreach here because Module.amodules.length can 512 // change on each iteration of the loop 513 for (size_t i = 0; i < compiledImports.length; i++) 514 { 515 auto m = compiledImports[i]; 516 assert(m.isRoot); 517 if (params.v.verbose) 518 message("semantic3 %s", m.toChars()); 519 m.semantic3(null); 520 modules.push(m); 521 } 522 } 523 Module.runDeferredSemantic3(); 524 if (global.errors) 525 removeHdrFilesAndFail(params, modules); 526 527 // Scan for functions to inline 528 foreach (m; modules) 529 { 530 if (params.useInline || m.hasAlwaysInlines) 531 { 532 if (params.v.verbose) 533 message("inline scan %s", m.toChars()); 534 inlineScanModule(m); 535 } 536 } 537 538 if (global.warnings) 539 errorOnWarning(); 540 541 // Do not attempt to generate output files if errors or warnings occurred 542 if (global.errors || global.warnings) 543 removeHdrFilesAndFail(params, modules); 544 545 // inlineScan incrementally run semantic3 of each expanded functions. 546 // So deps file generation should be moved after the inlining stage. 547 if (OutBuffer* ob = params.moduleDeps.buffer) 548 { 549 foreach (i; 1 .. modules[0].aimports.length) 550 semantic3OnDependencies(modules[0].aimports[i]); 551 Module.runDeferredSemantic3(); 552 553 const data = (*ob)[]; 554 if (params.moduleDeps.name) 555 { 556 if (!writeFile(Loc.initial, params.moduleDeps.name, data)) 557 fatal(); 558 } 559 else 560 printf("%.*s", cast(int)data.length, data.ptr); 561 } 562 563 printCtfePerformanceStats(); 564 printTemplateStats(); 565 566 // Generate output files 567 if (params.json.doOutput) 568 { 569 generateJson(modules); 570 } 571 if (!global.errors && params.ddoc.doOutput) 572 { 573 foreach (m; modules) 574 { 575 if (!ddocbufIsRead) 576 readDdocFiles(m.loc, global.params.ddoc.files, ddocbuf); 577 578 ddocOutputText.setsize(0); 579 gendocfile(m, ddocbuf[], global.datetime.ptr, global.errorSink, ddocOutputText); 580 581 if (!writeFile(m.loc, m.docfile.toString(), ddocOutputText[])) 582 fatal(); 583 } 584 } 585 if (params.vcg_ast) 586 { 587 import dmd.hdrgen; 588 foreach (mod; modules) 589 { 590 auto buf = OutBuffer(); 591 buf.doindent = 1; 592 moduleToBuffer(buf, mod); 593 594 // write the output to $(filename).cg 595 auto cgFilename = FileName.addExt(mod.srcfile.toString(), "cg"); 596 File.write(cgFilename.ptr, buf[]); 597 } 598 } 599 600 if (global.params.cxxhdr.doOutput) 601 genCppHdrFiles(modules); 602 603 if (global.errors) 604 fatal(); 605 606 if (driverParams.lib && params.objfiles.length == 0) 607 { 608 error(Loc.initial, "no input files"); 609 return EXIT_FAILURE; 610 } 611 612 if (params.addMain && !global.hasMainFunction) 613 { 614 auto mainModule = moduleWithEmptyMain(); 615 modules.push(mainModule); 616 if (!driverParams.oneobj || modules.length == 1) 617 params.objfiles.push(mainModule.objfile.toChars()); 618 } 619 620 generateCodeAndWrite(modules[], libmodules[], params.libname, params.objdir, 621 driverParams.lib, params.obj, driverParams.oneobj, params.multiobj, 622 params.v.verbose); 623 624 backend_term(); 625 626 if (global.errors) 627 fatal(); 628 int status = EXIT_SUCCESS; 629 if (!params.objfiles.length) 630 { 631 if (driverParams.link) 632 error(Loc.initial, "no object files to link"); 633 } 634 else 635 { 636 if (driverParams.link) 637 status = runLINK(); 638 if (params.run) 639 { 640 if (!status) 641 { 642 status = runProgram(); 643 /* Delete .obj files and .exe file 644 */ 645 foreach (m; modules) 646 { 647 m.deleteObjFile(); 648 if (driverParams.oneobj) 649 break; 650 } 651 params.exefile.toCStringThen!(ef => File.remove(ef.ptr)); 652 } 653 } 654 } 655 656 // Output the makefile dependencies 657 if (params.makeDeps.doOutput) 658 emitMakeDeps(params); 659 660 if (global.warnings) 661 errorOnWarning(); 662 663 if (global.errors || global.warnings) 664 removeHdrFilesAndFail(params, modules); 665 666 return status; 667 } 668 669 /** 670 * Parses the command line arguments and configuration files 671 * 672 * Params: 673 * argc = Number of arguments passed via command line 674 * argv = Array of string arguments passed via command line 675 * params = parameters from argv 676 * files = files from argv 677 * Returns: true on faiure 678 */ 679 bool parseCommandlineAndConfig(size_t argc, const(char)** argv, ref Param params, ref Strings files) 680 { 681 // Detect malformed input 682 static bool badArgs() 683 { 684 error(Loc.initial, "missing or null command line arguments"); 685 return true; 686 } 687 688 if (argc < 1 || !argv) 689 return badArgs(); 690 // Convert argc/argv into arguments[] for easier handling 691 Strings arguments = Strings(argc); 692 for (size_t i = 0; i < argc; i++) 693 { 694 if (!argv[i]) 695 return badArgs(); 696 arguments[i] = argv[i]; 697 } 698 if (const(char)* missingFile = responseExpand(arguments)) // expand response files 699 error(Loc.initial, "cannot open response file '%s'", missingFile); 700 //for (size_t i = 0; i < arguments.length; ++i) printf("arguments[%d] = '%s'\n", i, arguments[i]); 701 // Set default values 702 params.argv0 = arguments[0].toDString; 703 704 version (Windows) 705 enum iniName = "sc.ini"; 706 else version (Posix) 707 enum iniName = "dmd.conf"; 708 else 709 static assert(0, "fix this"); 710 711 global.inifilename = parse_conf_arg(&arguments); 712 if (global.inifilename) 713 { 714 // can be empty as in -conf= 715 if (global.inifilename.length && !FileName.exists(global.inifilename)) 716 error(Loc.initial, "config file '%.*s' does not exist.", 717 cast(int)global.inifilename.length, global.inifilename.ptr); 718 } 719 else 720 { 721 global.inifilename = findConfFile(params.argv0, iniName); 722 } 723 // Read the configuration file 724 const iniReadResult = File.read(global.inifilename); 725 const inifileBuffer = iniReadResult.buffer.data; 726 /* Need path of configuration file, for use in expanding @P macro 727 */ 728 const(char)[] inifilepath = FileName.path(global.inifilename); 729 Strings sections; 730 StringTable!(char*) environment; 731 environment._init(7); 732 /* Read the [Environment] section, so we can later 733 * pick up any DFLAGS settings. 734 */ 735 sections.push("Environment"); 736 parseConfFile(environment, global.inifilename, inifilepath, inifileBuffer, §ions); 737 738 const(char)[] arch = target.isX86_64 ? "64" : "32"; // use default 739 arch = parse_arch_arg(&arguments, arch); 740 741 // parse architecture from DFLAGS read from [Environment] section 742 { 743 Strings dflags; 744 getenv_setargv(readFromEnv(environment, "DFLAGS"), &dflags); 745 environment.reset(7); // erase cached environment updates 746 arch = parse_arch_arg(&dflags, arch); 747 } 748 749 bool isX86_64 = arch[0] == '6'; 750 751 version(Windows) // delete LIB entry in [Environment] (necessary for optlink) to allow inheriting environment for MS-COFF 752 if (arch != "32omf") 753 environment.update("LIB", 3).value = null; 754 755 // read from DFLAGS in [Environment{arch}] section 756 char[80] envsection = void; 757 snprintf(envsection.ptr, envsection.length, "Environment%.*s", cast(int) arch.length, arch.ptr); 758 sections.push(envsection.ptr); 759 parseConfFile(environment, global.inifilename, inifilepath, inifileBuffer, §ions); 760 getenv_setargv(readFromEnv(environment, "DFLAGS"), &arguments); 761 updateRealEnvironment(environment); 762 environment.reset(1); // don't need environment cache any more 763 764 if (parseCommandLine(arguments, argc, params, files, target)) 765 { 766 Loc loc; 767 errorSupplemental(loc, "run `dmd` to print the compiler manual"); 768 errorSupplemental(loc, "run `dmd -man` to open browser on manual"); 769 return true; 770 } 771 772 // DDOCFILE specified in the sc.ini file comes first and gets overridden by user specified files 773 if (char* p = getenv("DDOCFILE")) 774 global.params.ddoc.files.shift(p); 775 776 if (target.isX86_64 != isX86_64) 777 error(Loc.initial, "the architecture must not be changed in the %s section of %.*s", 778 envsection.ptr, cast(int)global.inifilename.length, global.inifilename.ptr); 779 780 global.preprocess = &preprocess; 781 return false; 782 } 783 784 /// Emit the makefile dependencies for the -makedeps switch 785 void emitMakeDeps(ref Param params) 786 { 787 assert(params.makeDeps.doOutput); 788 789 OutBuffer buf; 790 791 // start by resolving and writing the target (which is sometimes resolved during link phase) 792 if (driverParams.link && params.exefile) 793 { 794 buf.writeEscapedMakePath(¶ms.exefile[0]); 795 } 796 else if (driverParams.lib) 797 { 798 const(char)[] libname = params.libname ? params.libname : FileName.name(params.objfiles[0].toDString); 799 libname = FileName.forceExt(libname,target.lib_ext); 800 801 buf.writeEscapedMakePath(&libname[0]); 802 } 803 else if (params.objname) 804 { 805 buf.writeEscapedMakePath(¶ms.objname[0]); 806 } 807 else if (params.objfiles.length) 808 { 809 buf.writeEscapedMakePath(params.objfiles[0]); 810 foreach (of; params.objfiles[1 .. $]) 811 { 812 buf.writestring(" "); 813 buf.writeEscapedMakePath(of); 814 } 815 } 816 else 817 { 818 assert(false, "cannot resolve makedeps target"); 819 } 820 821 buf.writestring(":"); 822 823 // then output every dependency 824 foreach (dep; params.makeDeps.files) 825 { 826 buf.writestringln(" \\"); 827 buf.writestring(" "); 828 buf.writeEscapedMakePath(dep); 829 } 830 buf.writenl(); 831 832 const data = buf[]; 833 if (params.makeDeps.name) 834 { 835 if (!writeFile(Loc.initial, params.makeDeps.name, data)) 836 fatal(); 837 } 838 else 839 printf("%.*s", cast(int) data.length, data.ptr); 840 } 841 842 // in druntime: 843 alias MainFunc = extern(C) int function(char[][] args); 844 extern (C) int _d_run_main(int argc, char** argv, MainFunc dMain); 845 846 847 // When using a C main, host DMD may not link against host druntime by default. 848 version (DigitalMars) 849 { 850 version (Win64) 851 pragma(lib, "phobos64"); 852 else version (Win32) 853 { 854 version (CRuntime_Microsoft) 855 pragma(lib, "phobos32mscoff"); 856 else 857 pragma(lib, "phobos"); 858 } 859 } 860 861 extern extern(C) __gshared string[] rt_options; 862 863 /*********************************************** 864 * Adjust gathered command line switches and reconcile them. 865 * Params: 866 * params = switches gathered from command line, 867 * and update in place 868 * target = more switches from the command line, 869 * update in place 870 * numSrcFiles = number of source files 871 */ 872 void reconcileCommands(ref Param params, ref Target target) 873 { 874 if (target.os == Target.OS.OSX) 875 { 876 driverParams.pic = PIC.pic; 877 } 878 else if (target.os == Target.OS.Windows) 879 { 880 if (driverParams.pic) 881 error(Loc.initial, "`-fPIC` and `-fPIE` cannot be used when targetting windows"); 882 if (driverParams.dwarf) 883 error(Loc.initial, "`-gdwarf` cannot be used when targetting windows"); 884 } 885 else if (target.os == Target.OS.DragonFlyBSD) 886 { 887 if (!target.isX86_64) 888 error(Loc.initial, "`-m32` is not supported on DragonFlyBSD, it is 64-bit only"); 889 } 890 891 if (target.os & (Target.OS.linux | Target.OS.FreeBSD | Target.OS.OpenBSD | Target.OS.Solaris | Target.OS.DragonFlyBSD)) 892 { 893 if (driverParams.lib && driverParams.dll) 894 error(Loc.initial, "cannot mix `-lib` and `-shared`"); 895 } 896 if (target.os == Target.OS.Windows) 897 { 898 foreach(b; params.linkswitchIsForCC[]) 899 { 900 if (b) 901 { 902 // Linking code is guarded by version (Posix): 903 error(Loc.initial, "`Xcc=` link switches not available for this operating system"); 904 break; 905 } 906 } 907 } 908 else 909 { 910 if (target.omfobj) 911 error(Loc.initial, "`-m32omf` can only be used when targetting windows"); 912 if (driverParams.mscrtlib) 913 error(Loc.initial, "`-mscrtlib` can only be used when targetting windows"); 914 } 915 916 if (params.boundscheck != CHECKENABLE._default) 917 { 918 if (params.useArrayBounds == CHECKENABLE._default) 919 params.useArrayBounds = params.boundscheck; 920 } 921 922 if (params.useUnitTests) 923 { 924 if (params.useAssert == CHECKENABLE._default) 925 params.useAssert = CHECKENABLE.on; 926 } 927 928 if (params.release) 929 { 930 if (params.useInvariants == CHECKENABLE._default) 931 params.useInvariants = CHECKENABLE.off; 932 933 if (params.useIn == CHECKENABLE._default) 934 params.useIn = CHECKENABLE.off; 935 936 if (params.useOut == CHECKENABLE._default) 937 params.useOut = CHECKENABLE.off; 938 939 if (params.useArrayBounds == CHECKENABLE._default) 940 params.useArrayBounds = CHECKENABLE.safeonly; 941 942 if (params.useAssert == CHECKENABLE._default) 943 params.useAssert = CHECKENABLE.off; 944 945 if (params.useSwitchError == CHECKENABLE._default) 946 params.useSwitchError = CHECKENABLE.off; 947 } 948 else 949 { 950 if (params.useInvariants == CHECKENABLE._default) 951 params.useInvariants = CHECKENABLE.on; 952 953 if (params.useIn == CHECKENABLE._default) 954 params.useIn = CHECKENABLE.on; 955 956 if (params.useOut == CHECKENABLE._default) 957 params.useOut = CHECKENABLE.on; 958 959 if (params.useArrayBounds == CHECKENABLE._default) 960 params.useArrayBounds = CHECKENABLE.on; 961 962 if (params.useAssert == CHECKENABLE._default) 963 params.useAssert = CHECKENABLE.on; 964 965 if (params.useSwitchError == CHECKENABLE._default) 966 params.useSwitchError = CHECKENABLE.on; 967 } 968 969 if (params.betterC) 970 { 971 if (params.checkAction != CHECKACTION.halt) 972 params.checkAction = CHECKACTION.C; 973 974 params.useModuleInfo = false; 975 params.useTypeInfo = false; 976 params.useExceptions = false; 977 params.useGC = false; 978 } 979 } 980 981 /*********************************************** 982 * Adjust link, run and lib line switches and reconcile them. 983 * Params: 984 * params = switches gathered from command line, 985 * and update in place 986 * numSrcFiles = number of source files 987 * obj_ext = object file extension 988 */ 989 void reconcileLinkRunLib(ref Param params, size_t numSrcFiles, const char[] obj_ext) 990 { 991 if (!params.obj || driverParams.lib) 992 driverParams.link = false; 993 994 if (target.os == Target.OS.Windows) 995 { 996 if (!driverParams.mscrtlib) 997 { 998 version (Windows) 999 { 1000 VSOptions vsopt; 1001 vsopt.initialize(); 1002 driverParams.mscrtlib = vsopt.defaultRuntimeLibrary(target.isX86_64).toDString; 1003 } 1004 else 1005 { 1006 if (driverParams.link) 1007 error(Loc.initial, "must supply `-mscrtlib` manually when cross compiling to windows"); 1008 } 1009 } 1010 } 1011 1012 if (driverParams.link) 1013 { 1014 params.exefile = params.objname; 1015 driverParams.oneobj = true; 1016 if (params.objname) 1017 { 1018 /* Use this to name the one object file with the same 1019 * name as the exe file. 1020 */ 1021 params.objname = FileName.forceExt(params.objname, obj_ext); 1022 /* If output directory is given, use that path rather than 1023 * the exe file path. 1024 */ 1025 if (params.objdir) 1026 { 1027 const(char)[] name = FileName.name(params.objname); 1028 params.objname = FileName.combine(params.objdir, name); 1029 } 1030 } 1031 } 1032 else if (params.run) 1033 { 1034 error(Loc.initial, "flags conflict with -run"); 1035 fatal(); 1036 } 1037 else if (driverParams.lib) 1038 { 1039 params.libname = params.objname; 1040 params.objname = null; 1041 // Haven't investigated handling these options with multiobj 1042 if (!params.cov && !params.trace) 1043 params.multiobj = true; 1044 } 1045 else 1046 { 1047 if (params.objname && numSrcFiles) 1048 { 1049 driverParams.oneobj = true; 1050 //error("multiple source files, but only one .obj name"); 1051 //fatal(); 1052 } 1053 } 1054 } 1055 1056 }