1 /** 2 * Stores command line options and contains other miscellaneous declarations. 3 * 4 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/globals.d, _globals.d) 8 * Documentation: https://dlang.org/phobos/dmd_globals.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/globals.d 10 */ 11 12 module dmd.globals; 13 14 import core.stdc.stdint; 15 import dmd.root.array; 16 import dmd.root.filename; 17 import dmd.root.outbuffer; 18 import dmd.identifier; 19 20 template xversion(string s) 21 { 22 enum xversion = mixin(`{ version (` ~ s ~ `) return true; else return false; }`)(); 23 } 24 25 enum TARGET : bool 26 { 27 Linux = xversion!`linux`, 28 OSX = xversion!`OSX`, 29 FreeBSD = xversion!`FreeBSD`, 30 OpenBSD = xversion!`OpenBSD`, 31 Solaris = xversion!`Solaris`, 32 Windows = xversion!`Windows`, 33 DragonFlyBSD = xversion!`DragonFlyBSD`, 34 } 35 36 enum DiagnosticReporting : ubyte 37 { 38 error, // generate an error 39 inform, // generate a warning 40 off, // disable diagnostic 41 } 42 43 enum MessageStyle : ubyte 44 { 45 digitalmars, // filename.d(line): message 46 gnu, // filename.d:line: message, see https://www.gnu.org/prep/standards/html_node/Errors.html 47 } 48 49 enum CHECKENABLE : ubyte 50 { 51 _default, // initial value 52 off, // never do checking 53 on, // always do checking 54 safeonly, // do checking only in @safe functions 55 } 56 57 enum CHECKACTION : ubyte 58 { 59 D, // call D assert on failure 60 C, // call C assert on failure 61 halt, // cause program halt on failure 62 context, // call D assert with the error context on failure 63 } 64 65 enum CPU 66 { 67 x87, 68 mmx, 69 sse, 70 sse2, 71 sse3, 72 ssse3, 73 sse4_1, 74 sse4_2, 75 avx, // AVX1 instruction set 76 avx2, // AVX2 instruction set 77 avx512, // AVX-512 instruction set 78 79 // Special values that don't survive past the command line processing 80 baseline, // (default) the minimum capability CPU 81 native // the machine the compiler is being run on 82 } 83 84 enum PIC : ubyte 85 { 86 fixed, /// located at a specific address 87 pic, /// Position Independent Code 88 pie, /// Position Independent Executable 89 } 90 91 /** 92 Each flag represents a field that can be included in the JSON output. 93 94 NOTE: set type to uint so its size matches C++ unsigned type 95 */ 96 enum JsonFieldFlags : uint 97 { 98 none = 0, 99 compilerInfo = (1 << 0), 100 buildInfo = (1 << 1), 101 modules = (1 << 2), 102 semantics = (1 << 3), 103 } 104 105 enum CppStdRevision : uint 106 { 107 cpp98 = 1997_11, 108 cpp11 = 2011_03, 109 cpp14 = 2014_02, 110 cpp17 = 2017_03 111 } 112 113 /// Configuration for the C++ header generator 114 enum CxxHeaderMode : uint 115 { 116 none, /// Don't generate headers 117 silent, /// Generate headers 118 verbose /// Generate headers and add comments for hidden declarations 119 } 120 121 // Put command line switches in here 122 extern (C++) struct Param 123 { 124 bool obj = true; // write object file 125 bool link = true; // perform link 126 bool dll; // generate shared dynamic library 127 bool lib; // write library file instead of object file(s) 128 bool multiobj; // break one object file into multiple ones 129 bool oneobj; // write one object file instead of multiple ones 130 bool trace; // insert profiling hooks 131 bool tracegc; // instrument calls to 'new' 132 bool verbose; // verbose compile 133 bool vcg_ast; // write-out codegen-ast 134 bool showColumns; // print character (column) numbers in diagnostics 135 bool vtls; // identify thread local variables 136 bool vtemplates; // collect and list statistics on template instantiations 137 bool vtemplatesListInstances; // collect and list statistics on template instantiations origins. TODO: make this an enum when we want to list other kinds of instances 138 bool vgc; // identify gc usage 139 bool vfield; // identify non-mutable field variables 140 bool vcomplex; // identify complex/imaginary type usage 141 ubyte symdebug; // insert debug symbolic information 142 bool symdebugref; // insert debug information for all referenced types, too 143 bool alwaysframe; // always emit standard stack frame 144 bool optimize; // run optimizer 145 bool map; // generate linker .map file 146 bool is64bit = (size_t.sizeof == 8); // generate 64 bit code; true by default for 64 bit dmd 147 bool isLP64; // generate code for LP64 148 bool isLinux; // generate code for linux 149 bool isOSX; // generate code for Mac OSX 150 bool isWindows; // generate code for Windows 151 bool isFreeBSD; // generate code for FreeBSD 152 bool isOpenBSD; // generate code for OpenBSD 153 bool isDragonFlyBSD; // generate code for DragonFlyBSD 154 bool isSolaris; // generate code for Solaris 155 bool hasObjectiveC; // target supports Objective-C 156 bool mscoff = false; // for Win32: write MsCoff object files instead of OMF 157 DiagnosticReporting useDeprecated = DiagnosticReporting.inform; // how use of deprecated features are handled 158 bool stackstomp; // add stack stomping code 159 bool useUnitTests; // generate unittest code 160 bool useInline = false; // inline expand functions 161 bool useDIP25; // implement http://wiki.dlang.org/DIP25 162 bool noDIP25; // revert to pre-DIP25 behavior 163 bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/DIP1021.md 164 bool release; // build release version 165 bool preservePaths; // true means don't strip path from source file 166 DiagnosticReporting warnings = DiagnosticReporting.off; // how compiler warnings are handled 167 PIC pic = PIC.fixed; // generate fixed, pic or pie code 168 bool color; // use ANSI colors in console output 169 bool cov; // generate code coverage data 170 ubyte covPercent; // 0..100 code coverage percentage required 171 bool ctfe_cov = false; // generate coverage data for ctfe 172 bool nofloat; // code should not pull in floating point support 173 bool ignoreUnsupportedPragmas; // rather than error on them 174 bool useModuleInfo = true; // generate runtime module information 175 bool useTypeInfo = true; // generate runtime type information 176 bool useExceptions = true; // support exception handling 177 bool noSharedAccess; // read/write access to shared memory objects 178 bool previewIn; // `in` means `[ref] scope const`, accepts rvalues 179 bool betterC; // be a "better C" compiler; no dependency on D runtime 180 bool addMain; // add a default main() function 181 bool allInst; // generate code for all template instantiations 182 bool fix16997; // fix integral promotions for unary + - ~ operators 183 // https://issues.dlang.org/show_bug.cgi?id=16997 184 bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes 185 /** The --transition=safe switch should only be used to show code with 186 * silent semantics changes related to @safe improvements. It should not be 187 * used to hide a feature that will have to go through deprecate-then-error 188 * before becoming default. 189 */ 190 bool vsafe; // use enhanced @safe checking 191 bool ehnogc; // use @nogc exception handling 192 bool dtorFields; // destruct fields of partially constructed objects 193 // https://issues.dlang.org/show_bug.cgi?id=14246 194 bool fieldwise; // do struct equality testing field-wise rather than by memcmp() 195 bool rvalueRefParam; // allow rvalues to be arguments to ref parameters 196 // http://dconf.org/2019/talks/alexandrescu.html 197 // https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a 198 // https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html 199 // Implementation: https://github.com/dlang/dmd/pull/9817 200 201 CppStdRevision cplusplus = CppStdRevision.cpp98; // version of C++ standard to support 202 203 bool markdown = true; // enable Markdown replacements in Ddoc 204 bool vmarkdown; // list instances of Markdown replacements in Ddoc 205 206 bool showGaggedErrors; // print gagged errors anyway 207 bool printErrorContext; // print errors with the error context (the error line in the source file) 208 bool manual; // open browser on compiler manual 209 bool usage; // print usage and exit 210 bool mcpuUsage; // print help on -mcpu switch 211 bool transitionUsage; // print help on -transition switch 212 bool checkUsage; // print help on -check switch 213 bool checkActionUsage; // print help on -checkaction switch 214 bool revertUsage; // print help on -revert switch 215 bool previewUsage; // print help on -preview switch 216 bool externStdUsage; // print help on -extern-std switch 217 bool hcUsage; // print help on -HC switch 218 bool logo; // print compiler logo 219 220 CPU cpu = CPU.baseline; // CPU instruction set to target 221 222 CHECKENABLE useInvariants = CHECKENABLE._default; // generate class invariant checks 223 CHECKENABLE useIn = CHECKENABLE._default; // generate precondition checks 224 CHECKENABLE useOut = CHECKENABLE._default; // generate postcondition checks 225 CHECKENABLE useArrayBounds = CHECKENABLE._default; // when to generate code for array bounds checks 226 CHECKENABLE useAssert = CHECKENABLE._default; // when to generate code for assert()'s 227 CHECKENABLE useSwitchError = CHECKENABLE._default; // check for switches without a default 228 CHECKENABLE boundscheck = CHECKENABLE._default; // state of -boundscheck switch 229 230 CHECKACTION checkAction = CHECKACTION.D; // action to take when bounds, asserts or switch defaults are violated 231 232 uint errorLimit = 20; 233 234 const(char)[] argv0; // program name 235 Array!(const(char)*) modFileAliasStrings; // array of char*'s of -I module filename alias strings 236 Array!(const(char)*)* imppath; // array of char*'s of where to look for import modules 237 Array!(const(char)*)* fileImppath; // array of char*'s of where to look for file import modules 238 const(char)[] objdir; // .obj/.lib file output directory 239 const(char)[] objname; // .obj file output name 240 const(char)[] libname; // .lib file output name 241 242 bool doDocComments; // process embedded documentation comments 243 const(char)[] docdir; // write documentation file to docdir directory 244 const(char)[] docname; // write documentation file to docname 245 Array!(const(char)*) ddocfiles; // macro include files for Ddoc 246 247 bool doHdrGeneration; // process embedded documentation comments 248 const(char)[] hdrdir; // write 'header' file to docdir directory 249 const(char)[] hdrname; // write 'header' file to docname 250 bool hdrStripPlainFunctions = true; // strip the bodies of plain (non-template) functions 251 252 CxxHeaderMode doCxxHdrGeneration; /// Generate 'Cxx header' file 253 const(char)[] cxxhdrdir; // write 'header' file to docdir directory 254 const(char)[] cxxhdrname; // write 'header' file to docname 255 256 bool doJsonGeneration; // write JSON file 257 const(char)[] jsonfilename; // write JSON file to jsonfilename 258 JsonFieldFlags jsonFieldFlags; // JSON field flags to include 259 260 OutBuffer* mixinOut; // write expanded mixins for debugging 261 const(char)* mixinFile; // .mixin file output name 262 int mixinLines; // Number of lines in writeMixins 263 264 uint debuglevel; // debug level 265 Array!(const(char)*)* debugids; // debug identifiers 266 267 uint versionlevel; // version level 268 Array!(const(char)*)* versionids; // version identifiers 269 270 const(char)[] defaultlibname; // default library for non-debug builds 271 const(char)[] debuglibname; // default library for debug builds 272 const(char)[] mscrtlib; // MS C runtime library 273 274 const(char)[] moduleDepsFile; // filename for deps output 275 OutBuffer* moduleDeps; // contents to be written to deps file 276 MessageStyle messageStyle = MessageStyle.digitalmars; // style of file/line annotations on messages 277 278 // Hidden debug switches 279 bool debugb; 280 bool debugc; 281 bool debugf; 282 bool debugr; 283 bool debugx; 284 bool debugy; 285 286 bool run; // run resulting executable 287 Strings runargs; // arguments for executable 288 289 // Linker stuff 290 Array!(const(char)*) objfiles; 291 Array!(const(char)*) linkswitches; 292 Array!bool linkswitchIsForCC; 293 Array!(const(char)*) libfiles; 294 Array!(const(char)*) dllfiles; 295 const(char)[] deffile; 296 const(char)[] resfile; 297 const(char)[] exefile; 298 const(char)[] mapfile; 299 } 300 301 alias structalign_t = uint; 302 303 // magic value means "match whatever the underlying C compiler does" 304 // other values are all powers of 2 305 enum STRUCTALIGN_DEFAULT = (cast(structalign_t)~0); 306 307 extern (C++) struct Global 308 { 309 const(char)[] inifilename; 310 string mars_ext = "d"; 311 const(char)[] obj_ext; 312 const(char)[] lib_ext; 313 const(char)[] dll_ext; 314 string doc_ext = "html"; // for Ddoc generated files 315 string ddoc_ext = "ddoc"; // for Ddoc macro include files 316 string hdr_ext = "di"; // for D 'header' import files 317 string cxxhdr_ext = "h"; // for C/C++ 'header' files 318 string json_ext = "json"; // for JSON files 319 string map_ext = "map"; // for .map files 320 bool run_noext; // allow -run sources without extensions. 321 322 string copyright = "Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved"; 323 string written = "written by Walter Bright"; 324 325 Array!(const(char)*)* path; // Array of char*'s which form the import lookup path 326 Array!(const(char)*)* filePath; // Array of char*'s which form the file import lookup path 327 328 private enum string _version = import("VERSION"); 329 private enum uint _versionNumber = parseVersionNumber(_version); 330 331 const(char)[] vendor; // Compiler backend name 332 333 Param params; 334 uint errors; // number of errors reported so far 335 uint warnings; // number of warnings reported so far 336 uint gag; // !=0 means gag reporting of errors & warnings 337 uint gaggedErrors; // number of errors reported while gagged 338 uint gaggedWarnings; // number of warnings reported while gagged 339 340 void* console; // opaque pointer to console for controlling text attributes 341 342 Array!Identifier* versionids; // command line versions and predefined versions 343 Array!Identifier* debugids; // command line debug versions and predefined versions 344 345 enum recursionLimit = 500; // number of recursive template expansions before abort 346 347 nothrow: 348 349 /* Start gagging. Return the current number of gagged errors 350 */ 351 extern (C++) uint startGagging() 352 { 353 ++gag; 354 gaggedWarnings = 0; 355 return gaggedErrors; 356 } 357 358 /* End gagging, restoring the old gagged state. 359 * Return true if errors occurred while gagged. 360 */ 361 extern (C++) bool endGagging(uint oldGagged) 362 { 363 bool anyErrs = (gaggedErrors != oldGagged); 364 --gag; 365 // Restore the original state of gagged errors; set total errors 366 // to be original errors + new ungagged errors. 367 errors -= (gaggedErrors - oldGagged); 368 gaggedErrors = oldGagged; 369 return anyErrs; 370 } 371 372 /* Increment the error count to record that an error 373 * has occurred in the current context. An error message 374 * may or may not have been printed. 375 */ 376 extern (C++) void increaseErrorCount() 377 { 378 if (gag) 379 ++gaggedErrors; 380 ++errors; 381 } 382 383 extern (C++) void _init() 384 { 385 version (MARS) 386 { 387 vendor = "Digital Mars D"; 388 static if (TARGET.Windows) 389 { 390 obj_ext = "obj"; 391 } 392 else static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) 393 { 394 obj_ext = "o"; 395 } 396 else 397 { 398 static assert(0, "fix this"); 399 } 400 static if (TARGET.Windows) 401 { 402 lib_ext = "lib"; 403 } 404 else static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) 405 { 406 lib_ext = "a"; 407 } 408 else 409 { 410 static assert(0, "fix this"); 411 } 412 static if (TARGET.Windows) 413 { 414 dll_ext = "dll"; 415 } 416 else static if (TARGET.Linux || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) 417 { 418 dll_ext = "so"; 419 } 420 else static if (TARGET.OSX) 421 { 422 dll_ext = "dylib"; 423 } 424 else 425 { 426 static assert(0, "fix this"); 427 } 428 static if (TARGET.Windows) 429 { 430 run_noext = false; 431 } 432 else static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) 433 { 434 // Allow 'script' D source files to have no extension. 435 run_noext = true; 436 } 437 else 438 { 439 static assert(0, "fix this"); 440 } 441 static if (TARGET.Windows) 442 { 443 params.mscoff = params.is64bit; 444 } 445 446 // -color=auto is the default value 447 import dmd.console : Console; 448 params.color = Console.detectTerminal(); 449 } 450 else version (IN_GCC) 451 { 452 vendor = "GNU D"; 453 obj_ext = "o"; 454 lib_ext = "a"; 455 dll_ext = "so"; 456 run_noext = true; 457 } 458 } 459 460 /** 461 * Deinitializes the global state of the compiler. 462 * 463 * This can be used to restore the state set by `_init` to its original 464 * state. 465 */ 466 extern (D) void deinitialize() 467 { 468 this = this.init; 469 } 470 471 /** 472 * Computes the version number __VERSION__ from the compiler version string. 473 */ 474 extern (D) private static uint parseVersionNumber(string version_) 475 { 476 // 477 // parse _version 478 // 479 uint major = 0; 480 uint minor = 0; 481 bool point = false; 482 // skip initial 'v' 483 foreach (const c; version_[1..$]) 484 { 485 if ('0' <= c && c <= '9') // isdigit 486 { 487 minor = minor * 10 + c - '0'; 488 } 489 else if (c == '.') 490 { 491 if (point) 492 break; // ignore everything after second '.' 493 point = true; 494 major = minor; 495 minor = 0; 496 } 497 else 498 break; 499 } 500 return major * 1000 + minor; 501 } 502 503 /** 504 Returns: the version as the number that would be returned for __VERSION__ 505 */ 506 extern(C++) uint versionNumber() 507 { 508 return _versionNumber; 509 } 510 511 /** 512 Returns: compiler version string. 513 */ 514 extern(D) string versionString() 515 { 516 return _version; 517 } 518 519 /** 520 Returns: compiler version as char string. 521 */ 522 extern(C++) const(char*) versionChars() 523 { 524 return _version.ptr; 525 } 526 527 /** 528 Returns: the final defaultlibname based on the command-line parameters 529 */ 530 extern (D) const(char)[] finalDefaultlibname() const 531 { 532 return params.betterC ? null : 533 params.symdebug ? params.debuglibname : params.defaultlibname; 534 } 535 } 536 537 // Because int64_t and friends may be any integral type of the 538 // correct size, we have to explicitly ask for the correct 539 // integer type to get the correct mangling with dmd 540 541 // Be careful not to care about sign when using dinteger_t 542 // use this instead of integer_t to 543 // avoid conflicts with system #include's 544 alias dinteger_t = ulong; 545 // Signed and unsigned variants 546 alias sinteger_t = long; 547 alias uinteger_t = ulong; 548 549 alias d_int8 = int8_t; 550 alias d_uns8 = uint8_t; 551 alias d_int16 = int16_t; 552 alias d_uns16 = uint16_t; 553 alias d_int32 = int32_t; 554 alias d_uns32 = uint32_t; 555 alias d_int64 = int64_t; 556 alias d_uns64 = uint64_t; 557 558 // file location 559 struct Loc 560 { 561 const(char)* filename; // either absolute or relative to cwd 562 uint linnum; 563 uint charnum; 564 565 static immutable Loc initial; /// use for default initialization of const ref Loc's 566 567 nothrow: 568 extern (D) this(const(char)* filename, uint linnum, uint charnum) pure 569 { 570 this.linnum = linnum; 571 this.charnum = charnum; 572 this.filename = filename; 573 } 574 575 extern (C++) const(char)* toChars( 576 bool showColumns = global.params.showColumns, 577 ubyte messageStyle = global.params.messageStyle) const pure nothrow 578 { 579 OutBuffer buf; 580 if (filename) 581 { 582 buf.writestring(filename); 583 } 584 if (linnum) 585 { 586 final switch (messageStyle) 587 { 588 case MessageStyle.digitalmars: 589 buf.writeByte('('); 590 buf.print(linnum); 591 if (showColumns && charnum) 592 { 593 buf.writeByte(','); 594 buf.print(charnum); 595 } 596 buf.writeByte(')'); 597 break; 598 case MessageStyle.gnu: // https://www.gnu.org/prep/standards/html_node/Errors.html 599 buf.writeByte(':'); 600 buf.print(linnum); 601 if (showColumns && charnum) 602 { 603 buf.writeByte(':'); 604 buf.print(charnum); 605 } 606 break; 607 } 608 } 609 return buf.extractChars(); 610 } 611 612 /* Checks for equivalence, 613 * a) comparing the filename contents (not the pointer), case- 614 * insensitively on Windows, and 615 * b) ignoring charnum if `global.params.showColumns` is false. 616 */ 617 extern (C++) bool equals(ref const(Loc) loc) const 618 { 619 return (!global.params.showColumns || charnum == loc.charnum) && 620 linnum == loc.linnum && 621 FileName.equals(filename, loc.filename); 622 } 623 624 /* opEquals() / toHash() for AA key usage: 625 * 626 * Compare filename contents (case-sensitively on Windows too), not 627 * the pointer - a static foreach loop repeatedly mixing in a mixin 628 * may lead to multiple equivalent filenames (`foo.d-mixin-<line>`), 629 * e.g., for test/runnable/test18880.d. 630 */ 631 extern (D) bool opEquals(ref const(Loc) loc) const @trusted pure nothrow @nogc 632 { 633 import core.stdc.string : strcmp; 634 635 return charnum == loc.charnum && 636 linnum == loc.linnum && 637 (filename == loc.filename || 638 (filename && loc.filename && strcmp(filename, loc.filename) == 0)); 639 } 640 641 extern (D) size_t toHash() const @trusted pure nothrow 642 { 643 import dmd.root.string : toDString; 644 645 auto hash = hashOf(linnum); 646 hash = hashOf(charnum, hash); 647 hash = hashOf(filename.toDString, hash); 648 return hash; 649 } 650 651 /****************** 652 * Returns: 653 * true if Loc has been set to other than the default initialization 654 */ 655 bool isValid() const pure 656 { 657 return filename !is null; 658 } 659 } 660 661 enum LINK : int 662 { 663 default_, 664 d, 665 c, 666 cpp, 667 windows, 668 pascal, 669 objc, 670 system, 671 } 672 673 enum CPPMANGLE : int 674 { 675 def, 676 asStruct, 677 asClass, 678 } 679 680 enum MATCH : int 681 { 682 nomatch, // no match 683 convert, // match with conversions 684 constant, // match with conversion to const 685 exact, // exact match 686 } 687 688 enum PINLINE : int 689 { 690 default_, // as specified on the command line 691 never, // never inline 692 always, // always inline 693 } 694 695 alias StorageClass = uinteger_t; 696 697 extern (C++) __gshared Global global;