1 /** 2 Build settings definitions. 3 4 Copyright: © 2013-2014 rejectedsoftware e.K. 5 License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 6 Authors: Sönke Ludwig 7 */ 8 module dub.compilers.buildsettings; 9 10 import dub.internal.configy.attributes; 11 import dub.internal.logging; 12 import dub.internal.vibecompat.core.file; 13 import dub.internal.vibecompat.inet.path; 14 import dub.platform : BuildPlatform, matchesSpecification; 15 import dub.recipe.packagerecipe; 16 17 import std.array : appender, array; 18 import std.algorithm : filter, any, sort; 19 import std.path : globMatch; 20 import std.typecons : BitFlags; 21 import std.algorithm.iteration : uniq; 22 import std.exception : enforce; 23 import std.file; 24 import std.process : environment; 25 import std.range : empty, chain; 26 27 /// BuildPlatform specific settings, like needed libraries or additional 28 /// include paths. 29 struct BuildSettings { 30 import dub.internal.vibecompat.data.serialization : byName; 31 32 TargetType targetType; 33 string targetPath; 34 string targetName; 35 string workingDirectory; 36 string mainSourceFile; 37 string[] dflags; 38 string[] lflags; 39 string[] libs; 40 string[] frameworks; 41 string[] linkerFiles; 42 string[] sourceFiles; 43 string[] injectSourceFiles; 44 string[] copyFiles; 45 string[] extraDependencyFiles; 46 string[] versions; 47 string[] debugVersions; 48 string[] versionFilters; 49 string[] debugVersionFilters; 50 string[] importPaths; 51 string[] cImportPaths; 52 string[] stringImportPaths; 53 string[] importFiles; 54 string[] stringImportFiles; 55 string[] preGenerateCommands; 56 string[] postGenerateCommands; 57 string[] preBuildCommands; 58 string[] postBuildCommands; 59 string[] preRunCommands; 60 string[] postRunCommands; 61 string[string] environments; 62 string[string] buildEnvironments; 63 string[string] runEnvironments; 64 string[string] preGenerateEnvironments; 65 string[string] postGenerateEnvironments; 66 string[string] preBuildEnvironments; 67 string[string] postBuildEnvironments; 68 string[string] preRunEnvironments; 69 string[string] postRunEnvironments; 70 @byName Flags!BuildRequirement requirements; 71 @byName Flags!BuildOption options; 72 73 BuildSettings dup() const { 74 // Forwards to `add`, but `add` doesn't handle the first 5 fields 75 // as they are not additive, hence the `tupleof` call. 76 return typeof(return)(this.tupleof[0 .. /* dflags, not included */ 5]) 77 .add(this); 78 } 79 80 /** 81 * Merges $(LREF bs) onto `this` BuildSettings instance. This is called for 82 * sourceLibrary dependencies when they are included in the build to be 83 * merged into the root package build settings as well as configuring 84 * targets for different build types such as `release` or `unittest-cov`. 85 */ 86 ref BuildSettings add(in BuildSettings bs) 87 { 88 addDFlags(bs.dflags); 89 addLFlags(bs.lflags); 90 addLibs(bs.libs); 91 addFrameworks(bs.frameworks); 92 addLinkerFiles(bs.linkerFiles); 93 addSourceFiles(bs.sourceFiles); 94 addInjectSourceFiles(bs.injectSourceFiles); 95 addCopyFiles(bs.copyFiles); 96 addExtraDependencyFiles(bs.extraDependencyFiles); 97 addVersions(bs.versions); 98 addDebugVersions(bs.debugVersions); 99 addVersionFilters(bs.versionFilters); 100 addDebugVersionFilters(bs.debugVersionFilters); 101 addImportPaths(bs.importPaths); 102 addCImportPaths(bs.cImportPaths); 103 addStringImportPaths(bs.stringImportPaths); 104 addImportFiles(bs.importFiles); 105 addStringImportFiles(bs.stringImportFiles); 106 addPreGenerateCommands(bs.preGenerateCommands); 107 addPostGenerateCommands(bs.postGenerateCommands); 108 addPreBuildCommands(bs.preBuildCommands); 109 addPostBuildCommands(bs.postBuildCommands); 110 addPreRunCommands(bs.preRunCommands); 111 addPostRunCommands(bs.postRunCommands); 112 addEnvironments(bs.environments); 113 addBuildEnvironments(bs.buildEnvironments); 114 addRunEnvironments(bs.runEnvironments); 115 addPreGenerateEnvironments(bs.preGenerateEnvironments); 116 addPostGenerateEnvironments(bs.postGenerateEnvironments); 117 addPreBuildEnvironments(bs.preBuildEnvironments); 118 addPostBuildEnvironments(bs.postBuildEnvironments); 119 addPreRunEnvironments(bs.preRunEnvironments); 120 addPostRunEnvironments(bs.postRunEnvironments); 121 addRequirements(bs.requirements); 122 addOptions(bs.options); 123 return this; 124 } 125 126 void addDFlags(in string[] value...) { dflags = chain(dflags, value.dup).uniq.array; } 127 void prependDFlags(in string[] value...) { prepend(dflags, value); } 128 void removeDFlags(in string[] value...) { remove(dflags, value); } 129 void addLFlags(in string[] value...) { lflags ~= value; } 130 void prependLFlags(in string[] value...) { prepend(lflags, value, false); } 131 void addLibs(in string[] value...) { add(libs, value); } 132 void addFrameworks(in string[] value...) { add(frameworks, value); } 133 void addLinkerFiles(in string[] value...) { add(linkerFiles, value); } 134 void addSourceFiles(in string[] value...) { add(sourceFiles, value); } 135 void prependSourceFiles(in string[] value...) { prepend(sourceFiles, value); } 136 void removeSourceFiles(in string[] value...) { removePaths(sourceFiles, value); } 137 void addInjectSourceFiles(in string[] value...) { add(injectSourceFiles, value); } 138 void addCopyFiles(in string[] value...) { add(copyFiles, value); } 139 void addExtraDependencyFiles(in string[] value...) { add(extraDependencyFiles, value); } 140 void addVersions(in string[] value...) { add(versions, value); } 141 void addDebugVersions(in string[] value...) { add(debugVersions, value); } 142 void addVersionFilters(in string[] value...) { add(versionFilters, value); } 143 void addDebugVersionFilters(in string[] value...) { add(debugVersionFilters, value); } 144 void addImportPaths(in string[] value...) { add(importPaths, value); } 145 void addCImportPaths(in string[] value...) { add(cImportPaths, value); } 146 void addStringImportPaths(in string[] value...) { add(stringImportPaths, value); } 147 void prependStringImportPaths(in string[] value...) { prepend(stringImportPaths, value); } 148 void addImportFiles(in string[] value...) { add(importFiles, value); } 149 void addStringImportFiles(in string[] value...) { addSI(stringImportFiles, value); } 150 void addPreGenerateCommands(in string[] value...) { add(preGenerateCommands, value, false); } 151 void addPostGenerateCommands(in string[] value...) { add(postGenerateCommands, value, false); } 152 void addPreBuildCommands(in string[] value...) { add(preBuildCommands, value, false); } 153 void addPostBuildCommands(in string[] value...) { add(postBuildCommands, value, false); } 154 void addPreRunCommands(in string[] value...) { add(preRunCommands, value, false); } 155 void addPostRunCommands(in string[] value...) { add(postRunCommands, value, false); } 156 void addEnvironments(in string[string] value) { add(environments, value); } 157 void updateEnvironments(in string[string] value) { update(environments, value); } 158 void addBuildEnvironments(in string[string] value) { add(buildEnvironments, value); } 159 void updateBuildEnvironments(in string[string] value) { update(buildEnvironments, value); } 160 void addRunEnvironments(in string[string] value) { add(runEnvironments, value); } 161 void updateRunEnvironments(in string[string] value) { update(runEnvironments, value); } 162 void addPreGenerateEnvironments(in string[string] value) { add(preGenerateEnvironments, value); } 163 void updatePreGenerateEnvironments(in string[string] value) { update(preGenerateEnvironments, value); } 164 void addPostGenerateEnvironments(in string[string] value) { add(postGenerateEnvironments, value); } 165 void updatePostGenerateEnvironments(in string[string] value) { update(postGenerateEnvironments, value); } 166 void addPreBuildEnvironments(in string[string] value) { add(preBuildEnvironments, value); } 167 void updatePreBuildEnvironments(in string[string] value) { update(preBuildEnvironments, value); } 168 void addPostBuildEnvironments(in string[string] value) { add(postBuildEnvironments, value); } 169 void updatePostBuildEnvironments(in string[string] value) { update(postBuildEnvironments, value); } 170 void addPreRunEnvironments(in string[string] value) { add(preRunEnvironments, value); } 171 void updatePreRunEnvironments(in string[string] value) { update(preRunEnvironments, value); } 172 void addPostRunEnvironments(in string[string] value) { add(postRunEnvironments, value); } 173 void updatePostRunEnvironments(in string[string] value) { update(postRunEnvironments, value); } 174 void addRequirements(in BuildRequirement[] value...) { foreach (v; value) this.requirements |= v; } 175 void addRequirements(in Flags!BuildRequirement value) { this.requirements |= value; } 176 void addOptions(in BuildOption[] value...) { foreach (v; value) this.options |= v; } 177 void addOptions(in Flags!BuildOption value) { this.options |= value; } 178 void removeOptions(in BuildOption[] value...) { foreach (v; value) this.options &= ~v; } 179 void removeOptions(in Flags!BuildOption value) { this.options &= ~value; } 180 181 private: 182 static auto filterDuplicates(T)(ref string[] arr, in T vals, bool noDuplicates = true) 183 { 184 return noDuplicates 185 ? vals.filter!(filtered => !arr.any!(item => item == filtered)).array 186 : vals; 187 } 188 189 // Append `vals` to `arr` without adding duplicates. 190 static void add(ref string[] arr, in string[] vals, bool noDuplicates = true) 191 { 192 // vals might contain duplicates, add each val individually 193 foreach (val; vals) 194 arr ~= filterDuplicates(arr, [val], noDuplicates); 195 } 196 // Append `vals` to `aa` 197 static void add(ref string[string] aa, in string[string] vals) 198 { 199 // vals might contain duplicated keys, add each val individually 200 foreach (key, val; vals) 201 if (key !in aa) 202 aa[key] = val; 203 } 204 // Update `vals` to `aa` 205 static void update(ref string[string] aa, in string[string] vals) 206 { 207 // If there are duplicate keys, they will be ignored and overwritten. 208 foreach (key, val; vals) 209 aa[key] = val; 210 } 211 212 unittest 213 { 214 auto ary = ["-dip1000", "-vgc"]; 215 BuildSettings.add(ary, ["-dip1000", "-vgc"]); 216 assert(ary == ["-dip1000", "-vgc"]); 217 BuildSettings.add(ary, ["-dip1001", "-vgc"], false); 218 assert(ary == ["-dip1000", "-vgc", "-dip1001", "-vgc"]); 219 BuildSettings.add(ary, ["-dupflag", "-notdupflag", "-dupflag"]); 220 assert(ary == ["-dip1000", "-vgc", "-dip1001", "-vgc", "-dupflag", "-notdupflag"]); 221 } 222 223 // Prepend `arr` by `vals` without adding duplicates. 224 static void prepend(ref string[] arr, in string[] vals, bool noDuplicates = true) 225 { 226 import std.range : retro; 227 // vals might contain duplicates, add each val individually 228 foreach (val; vals.retro) 229 arr = filterDuplicates(arr, [val], noDuplicates) ~ arr; 230 } 231 232 unittest 233 { 234 auto ary = ["-dip1000", "-vgc"]; 235 BuildSettings.prepend(ary, ["-dip1000", "-vgc"]); 236 assert(ary == ["-dip1000", "-vgc"]); 237 BuildSettings.prepend(ary, ["-dip1001", "-vgc"], false); 238 assert(ary == ["-dip1001", "-vgc", "-dip1000", "-vgc"]); 239 BuildSettings.prepend(ary, ["-dupflag", "-notdupflag", "-dupflag"]); 240 assert(ary == ["-notdupflag", "-dupflag", "-dip1001", "-vgc", "-dip1000", "-vgc"]); 241 } 242 243 // add string import files (avoids file name duplicates in addition to path duplicates) 244 static void addSI(ref string[] arr, in string[] vals) 245 { 246 bool[string] existing; 247 foreach (v; arr) existing[NativePath(v).head.name] = true; 248 foreach (v; vals) { 249 auto s = NativePath(v).head.name; 250 if (s !in existing) { 251 existing[s] = true; 252 arr ~= v; 253 } 254 } 255 } 256 257 unittest 258 { 259 auto ary = ["path/foo.txt"]; 260 BuildSettings.addSI(ary, ["path2/foo2.txt"]); 261 assert(ary == ["path/foo.txt", "path2/foo2.txt"]); 262 BuildSettings.addSI(ary, ["path2/foo.txt"]); // no duplicate basenames 263 assert(ary == ["path/foo.txt", "path2/foo2.txt"]); 264 } 265 266 static bool pathMatch(string path, string pattern) 267 { 268 import std.functional : memoize; 269 270 alias nativePath = memoize!((string stringPath) => NativePath(stringPath)); 271 272 return nativePath(path) == nativePath(pattern) || globMatch(path, pattern); 273 } 274 275 static void removeValuesFromArray(alias Match)(ref string[] arr, in string[] vals) 276 { 277 bool matches(string s) 278 { 279 return vals.any!(item => Match(s, item)); 280 } 281 arr = arr.filter!(s => !matches(s)).array; 282 } 283 284 static void removePaths(ref string[] arr, in string[] vals) 285 { 286 removeValuesFromArray!(pathMatch)(arr, vals); 287 } 288 289 unittest 290 { 291 auto ary = ["path1", "root/path1", "root/path2", "root2/path1"]; 292 BuildSettings.removePaths(ary, ["path1"]); 293 assert(ary == ["root/path1", "root/path2", "root2/path1"]); 294 BuildSettings.removePaths(ary, ["*/path1"]); 295 assert(ary == ["root/path2"]); 296 BuildSettings.removePaths(ary, ["foo", "bar", "root/path2"]); 297 assert(ary == []); 298 } 299 300 static void remove(ref string[] arr, in string[] vals) 301 { 302 removeValuesFromArray!((a, b) => a == b)(arr, vals); 303 } 304 305 unittest 306 { 307 import std.string : join; 308 309 auto ary = ["path1", "root/path1", "root/path2", "root2/path1"]; 310 BuildSettings.remove(ary, ["path1"]); 311 assert(ary == ["root/path1", "root/path2", "root2/path1"]); 312 BuildSettings.remove(ary, ["root/path*"]); 313 assert(ary == ["root/path1", "root/path2", "root2/path1"]); 314 BuildSettings.removePaths(ary, ["foo", "root/path2", "bar", "root2/path1"]); 315 assert(ary == ["root/path1"]); 316 BuildSettings.remove(ary, ["root/path1", "foo"]); 317 assert(ary == []); 318 } 319 } 320 321 enum BuildSetting { 322 dflags = 1<<0, 323 lflags = 1<<1, 324 libs = 1<<2, 325 sourceFiles = 1<<3, 326 copyFiles = 1<<4, 327 versions = 1<<5, 328 debugVersions = 1<<6, 329 importPaths = 1<<7, 330 cImportPaths = 1<<8, 331 stringImportPaths = 1<<9, 332 options = 1<<10, 333 frameworks = 1<<11, 334 none = 0, 335 commandLine = dflags|copyFiles, 336 commandLineSeparate = commandLine|lflags, 337 all = dflags|lflags|libs|sourceFiles|copyFiles|versions|debugVersions|importPaths|cImportPaths|stringImportPaths|options|frameworks, 338 noOptions = all & ~options 339 } 340 341 enum TargetType { 342 autodetect, 343 none, 344 executable, 345 library, 346 sourceLibrary, 347 dynamicLibrary, 348 staticLibrary, 349 object 350 } 351 352 enum BuildRequirement { 353 none = 0, /// No special requirements 354 allowWarnings = 1<<0, /// Warnings do not abort compilation 355 silenceWarnings = 1<<1, /// Don't show warnings 356 disallowDeprecations = 1<<2, /// Using deprecated features aborts compilation 357 silenceDeprecations = 1<<3, /// Don't show deprecation warnings 358 disallowInlining = 1<<4, /// Avoid function inlining, even in release builds 359 disallowOptimization = 1<<5, /// Avoid optimizations, even in release builds 360 requireBoundsCheck = 1<<6, /// Always perform bounds checks 361 requireContracts = 1<<7, /// Leave assertions and contracts enabled in release builds 362 relaxProperties = 1<<8, /// DEPRECATED: Do not enforce strict property handling (-property) 363 noDefaultFlags = 1<<9, /// Do not issue any of the default build flags (e.g. -debug, -w, -property etc.) - use only for development purposes 364 } 365 366 enum BuildOption { 367 none = 0, /// Use compiler defaults 368 debugMode = 1<<0, /// Enables -debug flag (debug statements and identifiers) 369 releaseMode = 1<<1, /// Compile in release mode (disables assertions and bounds checks, -release) 370 coverage = 1<<2, /// Enable code coverage analysis (-cov) 371 debugInfo = 1<<3, /// Enable symbolic debug information (-g) 372 debugInfoC = 1<<4, /// Enable symbolic debug information in C compatible form (-gc) 373 alwaysStackFrame = 1<<5, /// Always generate a stack frame (-gs) 374 stackStomping = 1<<6, /// Perform stack stomping (-gx) 375 inline = 1<<7, /// Perform function inlining (-inline) 376 noBoundsCheck = 1<<8, /// Disable all bounds checking (-noboundscheck) 377 optimize = 1<<9, /// Enable optimizations (-O) 378 profile = 1<<10, /// Emit profiling code (-profile) 379 unittests = 1<<11, /// Compile unit tests (-unittest) 380 verbose = 1<<12, /// Verbose compiler output (-v) 381 ignoreUnknownPragmas = 1<<13, /// Ignores unknown pragmas during compilation (-ignore) 382 syntaxOnly = 1<<14, /// Don't generate object files (-o-) 383 warnings = 1<<15, /// Enable warnings (-wi) 384 warningsAsErrors = 1<<16, /// Treat warnings as errors (-w) 385 ignoreDeprecations = 1<<17, /// Do not warn about using deprecated features (-d) 386 deprecationWarnings = 1<<18, /// Warn about using deprecated features (-dw) 387 deprecationErrors = 1<<19, /// Stop compilation upon usage of deprecated features (-de) 388 property = 1<<20, /// DEPRECATED: Enforce property syntax (-property) 389 profileGC = 1<<21, /// Profile runtime allocations 390 pic = 1<<22, /// Generate position independent code 391 betterC = 1<<23, /// Compile in betterC mode (-betterC) 392 lowmem = 1<<24, /// Compile in low-memory mode (-lowmem) 393 coverageCTFE = 1<<25, /// Enable code coverage analysis including at compile-time (-cov=ctfe) 394 color = 1<<26, /// Colorize output (-color) 395 396 // for internal usage 397 _docs = 1<<27, // Write ddoc to docs 398 _ddox = 1<<28, // Compile docs.json 399 } 400 401 struct Flags (T) { 402 import dub.internal.vibecompat.data.serialization : ignore; 403 import dub.internal.vibecompat.data.json : Json; 404 405 @ignore BitFlags!T values; 406 407 public this(T opt) @safe pure nothrow @nogc 408 { 409 this.values = opt; 410 } 411 412 public this(BitFlags!T v) @safe pure nothrow @nogc 413 { 414 this.values = v; 415 } 416 417 alias values this; 418 419 public Json toJson() const 420 { 421 import std.conv : to; 422 import std.traits : EnumMembers; 423 424 auto json = Json.emptyArray; 425 426 static foreach (em; EnumMembers!T) { 427 static if (em != 0) { 428 if (values & em) { 429 json ~= em.to!string; 430 } 431 } 432 } 433 434 return json; 435 } 436 437 public static Flags!T fromJson(Json json) 438 { 439 import std.conv : to; 440 import std.exception : enforce; 441 442 BitFlags!T flags; 443 444 enforce(json.type == Json.Type.array, "Should be an array"); 445 foreach (jval; json) { 446 flags |= jval.get!string.to!T; 447 } 448 449 return Flags!T(flags); 450 } 451 452 /** 453 * Reads a list of flags from a JSON/YAML document and converts them 454 * to our internal representation. 455 * 456 * Flags inside of dub code are stored as a `BitFlags`, 457 * but they are specified in the recipe using an array of their name. 458 * This routine handles the conversion from `string[]` to `BitFlags!T`. 459 */ 460 public static Flags!T fromConfig (scope ConfigParser p) 461 { 462 import dub.internal.configy.backend.node; 463 import std.exception; 464 import std.conv; 465 466 auto seq = p.node.asSequence(); 467 enforce(seq !is null, "Should be a sequence"); 468 typeof(return) res; 469 foreach (idx, entry; seq) { 470 if (scope scalar = entry.asScalar()) 471 res |= scalar.str.to!T; 472 } 473 return res; 474 } 475 } 476 477 /// Constructs a BuildSettings object from this template. 478 void getPlatformSettings(in BuildSettingsTemplate* this_, ref BuildSettings dst, 479 in BuildPlatform platform, NativePath base_path) { 480 getPlatformSettings(*this_, dst, platform, base_path); 481 } 482 483 /// Ditto 484 void getPlatformSettings(in BuildSettingsTemplate this_, ref BuildSettings dst, 485 in BuildPlatform platform, NativePath base_path) { 486 dst.targetType = this_.targetType; 487 if (!this_.targetPath.empty) dst.targetPath = this_.targetPath; 488 if (!this_.targetName.empty) dst.targetName = this_.targetName; 489 if (!this_.workingDirectory.empty) dst.workingDirectory = this_.workingDirectory; 490 if (!this_.mainSourceFile.empty) { 491 auto p = NativePath(this_.mainSourceFile); 492 p.normalize(); 493 dst.mainSourceFile = p.toNativeString(); 494 dst.addSourceFiles(dst.mainSourceFile); 495 } 496 497 string[] collectFiles(in string[][string] paths_map, string pattern) 498 { 499 auto files = appender!(string[]); 500 501 import dub.project : buildSettingsVars; 502 import std.typecons : Nullable; 503 504 static Nullable!(string[string]) envVarCache; 505 506 if (envVarCache.isNull) envVarCache = environment.toAA(); 507 508 foreach (suffix, paths; paths_map) { 509 if (!platform.matchesSpecification(suffix)) 510 continue; 511 512 foreach (spath; paths) { 513 enforce(!spath.empty, "Paths must not be empty strings."); 514 auto path = NativePath(spath); 515 if (!path.absolute) path = base_path ~ path; 516 if (!existsDirectory(path)) { 517 import std.algorithm : any, find; 518 const hasVar = chain(buildSettingsVars, envVarCache.get.byKey).any!((string var) { 519 return spath.find("$"~var).length > 0 || spath.find("${"~var~"}").length > 0; 520 }); 521 if (!hasVar) 522 logWarn("Invalid source/import path: %s", path.toNativeString()); 523 continue; 524 } 525 526 auto pstr = path.toNativeString(); 527 foreach (d; dirEntries(pstr, pattern, SpanMode.depth)) { 528 import std.path : baseName, pathSplitter; 529 import std.algorithm.searching : canFind; 530 // eliminate any hidden files, or files in hidden directories. But always include 531 // files that are listed inside hidden directories that are specifically added to 532 // the project. 533 if (d.isDir || pathSplitter(d.name[pstr.length .. $]) 534 .canFind!(name => name.length && name[0] == '.')) 535 continue; 536 auto src = NativePath(d.name).relativeTo(base_path); 537 files ~= src.toNativeString(); 538 } 539 } 540 } 541 542 return files.data; 543 } 544 545 // collect source files. Note: D source from 'sourcePaths' and C sources from 'cSourcePaths' are joint into 'sourceFiles' 546 dst.addSourceFiles(collectFiles(this_.sourcePaths, "*.d")); 547 dst.addSourceFiles(collectFiles(this_.cSourcePaths, "*.{c,i}")); 548 auto sourceFiles = dst.sourceFiles.sort(); 549 550 // collect import files and remove sources 551 import std.algorithm : copy, setDifference; 552 553 auto importFiles = 554 chain(collectFiles(this_.importPaths, "*.{d,di}"), collectFiles(this_.cImportPaths, "*.h")) 555 .array() 556 .sort(); 557 immutable nremoved = importFiles.setDifference(sourceFiles).copy(importFiles.release).length; 558 importFiles = importFiles[0 .. $ - nremoved]; 559 dst.addImportFiles(importFiles.release); 560 561 dst.addStringImportFiles(collectFiles(this_.stringImportPaths, "*")); 562 563 this_.getPlatformSetting_!("dflags", "addDFlags")(dst, platform); 564 this_.getPlatformSetting_!("lflags", "addLFlags")(dst, platform); 565 this_.getPlatformSetting_!("libs", "addLibs")(dst, platform); 566 this_.getPlatformSetting_!("frameworks", "addFrameworks")(dst, platform); 567 this_.getPlatformSetting_!("sourceFiles", "addSourceFiles")(dst, platform); 568 this_.getPlatformSetting_!("excludedSourceFiles", "removeSourceFiles")(dst, platform); 569 this_.getPlatformSetting_!("injectSourceFiles", "addInjectSourceFiles")(dst, platform); 570 this_.getPlatformSetting_!("copyFiles", "addCopyFiles")(dst, platform); 571 this_.getPlatformSetting_!("extraDependencyFiles", "addExtraDependencyFiles")(dst, platform); 572 this_.getPlatformSetting_!("versions", "addVersions")(dst, platform); 573 this_.getPlatformSetting_!("debugVersions", "addDebugVersions")(dst, platform); 574 this_.getPlatformSetting_!("versionFilters", "addVersionFilters")(dst, platform); 575 this_.getPlatformSetting_!("debugVersionFilters", "addDebugVersionFilters")(dst, platform); 576 this_.getPlatformSetting_!("importPaths", "addImportPaths")(dst, platform); 577 this_.getPlatformSetting_!("cImportPaths", "addCImportPaths")(dst, platform); 578 this_.getPlatformSetting_!("stringImportPaths", "addStringImportPaths")(dst, platform); 579 this_.getPlatformSetting_!("preGenerateCommands", "addPreGenerateCommands")(dst, platform); 580 this_.getPlatformSetting_!("postGenerateCommands", "addPostGenerateCommands")(dst, platform); 581 this_.getPlatformSetting_!("preBuildCommands", "addPreBuildCommands")(dst, platform); 582 this_.getPlatformSetting_!("postBuildCommands", "addPostBuildCommands")(dst, platform); 583 this_.getPlatformSetting_!("preRunCommands", "addPreRunCommands")(dst, platform); 584 this_.getPlatformSetting_!("postRunCommands", "addPostRunCommands")(dst, platform); 585 this_.getPlatformSetting_!("environments", "addEnvironments")(dst, platform); 586 this_.getPlatformSetting_!("buildEnvironments", "addBuildEnvironments")(dst, platform); 587 this_.getPlatformSetting_!("runEnvironments", "addRunEnvironments")(dst, platform); 588 this_.getPlatformSetting_!("preGenerateEnvironments", "addPreGenerateEnvironments")(dst, platform); 589 this_.getPlatformSetting_!("postGenerateEnvironments", "addPostGenerateEnvironments")(dst, platform); 590 this_.getPlatformSetting_!("preBuildEnvironments", "addPreBuildEnvironments")(dst, platform); 591 this_.getPlatformSetting_!("postBuildEnvironments", "addPostBuildEnvironments")(dst, platform); 592 this_.getPlatformSetting_!("preRunEnvironments", "addPreRunEnvironments")(dst, platform); 593 this_.getPlatformSetting_!("postRunEnvironments", "addPostRunEnvironments")(dst, platform); 594 this_.getPlatformSetting_!("buildRequirements", "addRequirements")(dst, platform); 595 this_.getPlatformSetting_!("buildOptions", "addOptions")(dst, platform); 596 } 597 598 unittest { // issue #1407 - duplicate main source file 599 { 600 BuildSettingsTemplate t; 601 t.mainSourceFile = "./foo.d"; 602 t.sourceFiles[""] = ["foo.d"]; 603 BuildSettings bs; 604 t.getPlatformSettings(bs, BuildPlatform.init, NativePath("/")); 605 assert(bs.sourceFiles == ["foo.d"]); 606 } 607 608 version (Windows) {{ 609 BuildSettingsTemplate t; 610 t.mainSourceFile = "src/foo.d"; 611 t.sourceFiles[""] = ["src\\foo.d"]; 612 BuildSettings bs; 613 t.getPlatformSettings(bs, BuildPlatform.init, NativePath("/")); 614 assert(bs.sourceFiles == ["src\\foo.d"]); 615 }} 616 } 617 618 unittest 619 { 620 import dub.internal.vibecompat.data.json; 621 622 auto opts = Flags!BuildOption(BuildOption.debugMode | BuildOption.debugInfo | BuildOption.warningsAsErrors); 623 const str = serializeToJsonString(opts); 624 assert(str == `["debugMode","debugInfo","warningsAsErrors"]`); 625 assert(deserializeJson!(typeof(opts))(str) == opts); 626 } 627 628 unittest 629 { 630 import dub.internal.configy.easy; 631 632 static struct Config 633 { 634 Flags!BuildRequirement flags; 635 } 636 637 auto c = parseConfigString!Config(` 638 { 639 "flags": [ "allowWarnings", "noDefaultFlags", "disallowInlining" ] 640 } 641 `, __FILE__); 642 assert(c.flags.allowWarnings); 643 c.flags.allowWarnings = false; 644 assert(c.flags.noDefaultFlags); 645 c.flags.noDefaultFlags = false; 646 assert(c.flags.disallowInlining); 647 c.flags.disallowInlining = false; 648 assert(c.flags == c.flags.init); 649 } 650 651 /** 652 All build options that will be inherited upwards in the dependency graph 653 654 Build options in this category fulfill one of the following properties: 655 $(UL 656 $(LI The option affects the semantics of the generated code) 657 $(LI The option affects if a certain piece of code is valid or not) 658 $(LI The option enabled meta information in dependent projects that are useful for the dependee (e.g. debug information)) 659 ) 660 */ 661 enum Flags!BuildOption inheritedBuildOptions = 662 BuildOption.debugMode | BuildOption.releaseMode 663 | BuildOption.coverage | BuildOption.coverageCTFE | BuildOption.debugInfo | BuildOption.debugInfoC 664 | BuildOption.alwaysStackFrame | BuildOption.stackStomping | BuildOption.inline 665 | BuildOption.noBoundsCheck | BuildOption.profile | BuildOption.ignoreUnknownPragmas 666 | BuildOption.syntaxOnly | BuildOption.warnings | BuildOption.warningsAsErrors 667 | BuildOption.ignoreDeprecations | BuildOption.deprecationWarnings 668 | BuildOption.deprecationErrors | BuildOption.property | BuildOption.profileGC 669 | BuildOption.pic; 670 671 deprecated("Use `Flags!BuildOption` instead") 672 public alias BuildOptions = Flags!BuildOption; 673 674 deprecated("Use `Flags!BuildRequirement` instead") 675 public alias BuildRequirements = Flags!BuildRequirement;