1 /** 2 * DMD-specific parameters. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmdparams.d, _dmdparams.d) 8 * Documentation: https://dlang.org/phobos/dmd_dmdparams.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmdparams.d 10 */ 11 12 module dmd.dmdparams; 13 14 import dmd.target; 15 16 /// Position Indepent Code setting 17 enum PIC : ubyte 18 { 19 fixed, /// located at a specific address 20 pic, /// Position Independent Code 21 pie, /// Position Independent Executable 22 } 23 24 struct DMDparams 25 { 26 bool alwaysframe; // always emit standard stack frame 27 ubyte dwarf; // DWARF version 28 bool map; // generate linker .map file 29 bool vasm; // print generated assembler for each function 30 31 bool dll; // generate shared dynamic library 32 bool lib; // write library file instead of object file(s) 33 bool link = true; // perform link 34 bool oneobj; // write one object file instead of multiple ones 35 36 bool optimize; // run optimizer 37 bool nofloat; // code should not pull in floating point support 38 bool ibt; // generate indirect branch tracking 39 PIC pic = PIC.fixed; // generate fixed, pic or pie code 40 bool stackstomp; // add stack stomping code 41 42 bool symdebug; // insert debug symbolic information 43 bool symdebugref; // insert debug information for all referenced types, too 44 45 const(char)[] defaultlibname; // default library for non-debug builds 46 const(char)[] debuglibname; // default library for debug builds 47 const(char)[] mscrtlib; // MS C runtime library 48 49 // Hidden debug switches 50 bool debugb; 51 bool debugc; 52 bool debugf; 53 bool debugr; 54 bool debugx; 55 bool debugy; 56 } 57 58 /** 59 Sets CPU Operating System, and optionally C/C++ runtime environment from the given triple 60 e.g. 61 x86_64+avx2-apple-darwin20.3.0 62 x86-unknown-linux-musl-clang 63 x64-windows-msvc 64 x64-pc-windows-msvc 65 */ 66 struct Triple 67 { 68 private const(char)[] source; 69 CPU cpu; 70 bool isX86_64; 71 bool isLP64; 72 Target.OS os; 73 ubyte osMajor; 74 TargetC.Runtime cenv; 75 TargetCPP.Runtime cppenv; 76 77 this(const(char)* _triple) 78 { 79 import dmd.root.string : toDString, toCStringThen; 80 const(char)[] triple = _triple.toDString(); 81 const(char)[] next() 82 { 83 size_t i = 0; 84 const tmp = triple; 85 while (triple.length && triple[0] != '-') 86 { 87 triple = triple[1 .. $]; 88 ++i; 89 } 90 if (triple.length && triple[0] == '-') 91 { 92 triple = triple[1 .. $]; 93 } 94 return tmp[0 .. i]; 95 } 96 97 parseArch(next); 98 const(char)[] vendorOrOS = next(); 99 const(char)[] _os; 100 if (tryParseVendor(vendorOrOS)) 101 _os = next(); 102 else 103 _os = vendorOrOS; 104 os = parseOS(_os, osMajor); 105 106 const(char)[] _cenv = next(); 107 if (_cenv.length) 108 cenv = parseCEnv(_cenv); 109 else if (this.os == Target.OS.Windows) 110 cenv = TargetC.Runtime.Microsoft; 111 const(char)[] _cppenv = next(); 112 if (_cppenv.length) 113 cppenv = parseCPPEnv(_cppenv); 114 else if (this.os == Target.OS.Windows) 115 cppenv = TargetCPP.Runtime.Microsoft; 116 } 117 private extern(D): 118 119 void unknown(const(char)[] unk, const(char)* what) 120 { 121 import dmd.errors : error; 122 import dmd.root.string : toCStringThen; 123 import dmd.location; 124 unk.toCStringThen!(p => error(Loc.initial,"unknown %s `%s` for `-target`", what, p.ptr)); 125 } 126 127 void parseArch(const(char)[] arch) 128 { 129 bool matches(const(char)[] str) 130 { 131 import dmd.root.string : startsWith; 132 if (!arch.ptr.startsWith(str)) 133 return false; 134 arch = arch[str.length .. $]; 135 return true; 136 } 137 138 if (matches("x86_64")) 139 isX86_64 = true; 140 else if (matches("x86")) 141 isX86_64 = false; 142 else if (matches("x64")) 143 isX86_64 = true; 144 else if (matches("x32")) 145 { 146 isX86_64 = true; 147 isLP64 = false; 148 } 149 else 150 return unknown(arch, "architecture"); 151 152 if (!arch.length) 153 return; 154 155 switch (arch) 156 { 157 case "+sse2": cpu = CPU.sse2; break; 158 case "+avx": cpu = CPU.avx; break; 159 case "+avx2": cpu = CPU.avx2; break; 160 default: 161 unknown(arch, "architecture feature"); 162 } 163 } 164 165 // try parsing vendor if present 166 bool tryParseVendor(const(char)[] vendor) @safe 167 { 168 switch (vendor) 169 { 170 case "unknown": return true; 171 case "apple": return true; 172 case "pc": return true; 173 case "amd": return true; 174 default: return false; 175 } 176 } 177 178 /******************************** 179 * Parse OS and osMajor version number. 180 * Params: 181 * _os = string to check for operating system followed by version number 182 * osMajor = set to version number (if any), otherwise set to 0. 183 * Set to 255 if version number is 255 or larger and error is generated 184 * Returns: 185 * detected operating system, Target.OS.none if none 186 */ 187 Target.OS parseOS(const(char)[] _os, out ubyte osMajor) 188 { 189 import dmd.errors : error; 190 import dmd.location; 191 192 bool matches(const(char)[] str) 193 { 194 import dmd.root.string : startsWith; 195 if (!_os.ptr.startsWith(str)) 196 return false; 197 _os = _os[str.length .. $]; 198 return true; 199 } 200 Target.OS os; 201 if (matches("darwin")) 202 os = Target.OS.OSX; 203 else if (matches("dragonfly")) 204 os = Target.OS.DragonFlyBSD; 205 else if (matches("freebsd")) 206 os = Target.OS.FreeBSD; 207 else if (matches("openbsd")) 208 os = Target.OS.OpenBSD; 209 else if (matches("linux")) 210 os = Target.OS.linux; 211 else if (matches("windows")) 212 os = Target.OS.Windows; 213 else 214 { 215 unknown(_os, "operating system"); 216 return Target.OS.none; 217 } 218 219 bool overflow; 220 auto major = parseNumber(_os, overflow); 221 if (overflow || major >= 255) 222 { 223 error(Loc.initial, "OS version overflowed max of 254"); 224 major = 255; 225 } 226 osMajor = cast(ubyte)major; 227 228 /* Note that anything after the number up to the end or '-', 229 * such as '.3.4.hello.betty', is ignored 230 */ 231 232 return os; 233 } 234 235 /******************************* 236 * Parses a decimal number out of the str and returns it. 237 * Params: 238 * str = string to parse the number from, updated to text after the number 239 * overflow = set to true iff an overflow happens 240 * Returns: 241 * parsed number 242 */ 243 private pure @safe static 244 uint parseNumber(ref const(char)[] str, ref bool overflow) 245 { 246 auto s = str; 247 ulong n; 248 while (s.length) 249 { 250 const c = s[0]; 251 if (c < '0' || '9' < c) 252 break; 253 n = n * 10 + (c - '0'); 254 overflow |= (n > uint.max); // sticky overflow check 255 s = s[1 .. $]; // consume digit 256 } 257 str = s; 258 return cast(uint)n; 259 } 260 261 TargetC.Runtime parseCEnv(const(char)[] cenv) 262 { 263 with (TargetC.Runtime) switch (cenv) 264 { 265 case "musl": return Musl; 266 case "msvc": return Microsoft; 267 case "bionic": return Bionic; 268 case "digital_mars": return DigitalMars; 269 case "newlib": return Newlib; 270 case "uclibc": return UClibc; 271 case "glibc": return Glibc; 272 default: 273 { 274 unknown(cenv, "C runtime environment"); 275 return Unspecified; 276 } 277 } 278 } 279 280 TargetCPP.Runtime parseCPPEnv(const(char)[] cppenv) 281 { 282 with (TargetCPP.Runtime) switch (cppenv) 283 { 284 case "clang": return Clang; 285 case "gcc": return Gcc; 286 case "msvc": return Microsoft; 287 case "sun": return Sun; 288 case "digital_mars": return DigitalMars; 289 default: 290 { 291 unknown(cppenv, "C++ runtime environment"); 292 return Unspecified; 293 } 294 } 295 } 296 } 297 298 void setTriple(ref Target target, const ref Triple triple) @safe 299 { 300 target.cpu = triple.cpu; 301 target.isX86_64 = triple.isX86_64; 302 target.isLP64 = triple.isLP64; 303 target.os = triple.os; 304 target.osMajor = triple.osMajor; 305 target.c.runtime = triple.cenv; 306 target.cpp.runtime = triple.cppenv; 307 } 308 309 /** 310 Returns: the final defaultlibname based on the command-line parameters 311 */ 312 extern (D) const(char)[] finalDefaultlibname() 313 { 314 import dmd.globals : global; 315 return global.params.betterC ? null : 316 driverParams.symdebug ? driverParams.debuglibname : driverParams.defaultlibname; 317 } 318 319 __gshared DMDparams driverParams = DMDparams.init;