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