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