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