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.vibecompat.inet.path; 11 12 import std.array : array; 13 import std.algorithm : filter; 14 import std.path : globMatch; 15 static if (__VERSION__ >= 2067) 16 import std.typecons : BitFlags; 17 18 19 /// BuildPlatform specific settings, like needed libraries or additional 20 /// include paths. 21 struct BuildSettings { 22 import dub.internal.vibecompat.data.serialization : byName; 23 24 TargetType targetType; 25 string targetPath; 26 string targetName; 27 string workingDirectory; 28 string mainSourceFile; 29 string[] dflags; 30 string[] lflags; 31 string[] libs; 32 string[] linkerFiles; 33 string[] sourceFiles; 34 string[] copyFiles; 35 string[] versions; 36 string[] debugVersions; 37 string[] importPaths; 38 string[] stringImportPaths; 39 string[] importFiles; 40 string[] stringImportFiles; 41 string[] preGenerateCommands; 42 string[] postGenerateCommands; 43 string[] preBuildCommands; 44 string[] postBuildCommands; 45 @byName BuildRequirements requirements; 46 @byName BuildOptions options; 47 48 BuildSettings dup() 49 const { 50 BuildSettings ret; 51 foreach (m; __traits(allMembers, BuildSettings)) { 52 static if (is(typeof(__traits(getMember, ret, m) = __traits(getMember, this, m).dup))) 53 __traits(getMember, ret, m) = __traits(getMember, this, m).dup; 54 else static if (is(typeof(__traits(getMember, ret, m) = __traits(getMember, this, m)))) 55 __traits(getMember, ret, m) = __traits(getMember, this, m); 56 } 57 assert(ret.targetType == targetType); 58 assert(ret.targetName == targetName); 59 assert(ret.importPaths == importPaths); 60 return ret; 61 } 62 63 void add(in BuildSettings bs) 64 { 65 addDFlags(bs.dflags); 66 addLFlags(bs.lflags); 67 addLibs(bs.libs); 68 addLinkerFiles(bs.linkerFiles); 69 addSourceFiles(bs.sourceFiles); 70 addCopyFiles(bs.copyFiles); 71 addVersions(bs.versions); 72 addDebugVersions(bs.debugVersions); 73 addImportPaths(bs.importPaths); 74 addStringImportPaths(bs.stringImportPaths); 75 addImportFiles(bs.importFiles); 76 addStringImportFiles(bs.stringImportFiles); 77 addPreGenerateCommands(bs.preGenerateCommands); 78 addPostGenerateCommands(bs.postGenerateCommands); 79 addPreBuildCommands(bs.preBuildCommands); 80 addPostBuildCommands(bs.postBuildCommands); 81 } 82 83 void addDFlags(in string[] value...) { dflags ~= value; } 84 void prependDFlags(in string[] value...) { prepend(dflags, value); } 85 void removeDFlags(in string[] value...) { remove(dflags, value); } 86 void addLFlags(in string[] value...) { lflags ~= value; } 87 void addLibs(in string[] value...) { add(libs, value); } 88 void addLinkerFiles(in string[] value...) { add(linkerFiles, value); } 89 void addSourceFiles(in string[] value...) { add(sourceFiles, value); } 90 void prependSourceFiles(in string[] value...) { prepend(sourceFiles, value); } 91 void removeSourceFiles(in string[] value...) { removePaths(sourceFiles, value); } 92 void addCopyFiles(in string[] value...) { add(copyFiles, value); } 93 void addVersions(in string[] value...) { add(versions, value); } 94 void addDebugVersions(in string[] value...) { add(debugVersions, value); } 95 void addImportPaths(in string[] value...) { add(importPaths, value); } 96 void addStringImportPaths(in string[] value...) { add(stringImportPaths, value); } 97 void prependStringImportPaths(in string[] value...) { prepend(stringImportPaths, value); } 98 void addImportFiles(in string[] value...) { add(importFiles, value); } 99 void removeImportFiles(in string[] value...) { removePaths(importFiles, value); } 100 void addStringImportFiles(in string[] value...) { addSI(stringImportFiles, value); } 101 void addPreGenerateCommands(in string[] value...) { add(preGenerateCommands, value, false); } 102 void addPostGenerateCommands(in string[] value...) { add(postGenerateCommands, value, false); } 103 void addPreBuildCommands(in string[] value...) { add(preBuildCommands, value, false); } 104 void addPostBuildCommands(in string[] value...) { add(postBuildCommands, value, false); } 105 void addRequirements(in BuildRequirement[] value...) { foreach (v; value) this.requirements |= v; } 106 void addRequirements(in BuildRequirements value) { this.requirements |= value; } 107 void addOptions(in BuildOption[] value...) { foreach (v; value) this.options |= v; } 108 void addOptions(in BuildOptions value) { this.options |= value; } 109 void removeOptions(in BuildOption[] value...) { foreach (v; value) this.options &= ~v; } 110 void removeOptions(in BuildOptions value) { this.options &= ~value; } 111 112 // Adds vals to arr without adding duplicates. 113 private void add(ref string[] arr, in string[] vals, bool no_duplicates = true) 114 { 115 if (!no_duplicates) { 116 arr ~= vals; 117 return; 118 } 119 120 foreach (v; vals) { 121 bool found = false; 122 foreach (i; 0 .. arr.length) 123 if (arr[i] == v) { 124 found = true; 125 break; 126 } 127 if (!found) arr ~= v; 128 } 129 } 130 131 private void prepend(ref string[] arr, in string[] vals, bool no_duplicates = true) 132 { 133 if (!no_duplicates) { 134 arr = vals ~ arr; 135 return; 136 } 137 138 foreach_reverse (v; vals) { 139 bool found = false; 140 foreach (i; 0 .. arr.length) 141 if (arr[i] == v) { 142 found = true; 143 break; 144 } 145 if (!found) arr = v ~ arr; 146 } 147 } 148 149 // add string import files (avoids file name duplicates in addition to path duplicates) 150 private void addSI(ref string[] arr, in string[] vals) 151 { 152 outer: 153 foreach (v; vals) { 154 auto vh = Path(v).head; 155 foreach (ve; arr) { 156 if (Path(ve).head == vh) 157 continue outer; 158 } 159 arr ~= v; 160 } 161 } 162 163 private void removePaths(ref string[] arr, in string[] vals) 164 { 165 bool matches(string s) 166 { 167 foreach (p; vals) 168 if (Path(s) == Path(p) || globMatch(s, p)) 169 return true; 170 return false; 171 } 172 arr = arr.filter!(s => !matches(s))().array(); 173 } 174 175 private void remove(ref string[] arr, in string[] vals) 176 { 177 bool matches(string s) 178 { 179 foreach (p; vals) 180 if (s == p) 181 return true; 182 return false; 183 } 184 arr = arr.filter!(s => !matches(s))().array(); 185 } 186 } 187 188 enum BuildSetting { 189 dflags = 1<<0, 190 lflags = 1<<1, 191 libs = 1<<2, 192 sourceFiles = 1<<3, 193 copyFiles = 1<<4, 194 versions = 1<<5, 195 debugVersions = 1<<6, 196 importPaths = 1<<7, 197 stringImportPaths = 1<<8, 198 options = 1<<9, 199 none = 0, 200 commandLine = dflags|copyFiles, 201 commandLineSeparate = commandLine|lflags, 202 all = dflags|lflags|libs|sourceFiles|copyFiles|versions|debugVersions|importPaths|stringImportPaths|options, 203 noOptions = all & ~options 204 } 205 206 enum TargetType { 207 autodetect, 208 none, 209 executable, 210 library, 211 sourceLibrary, 212 dynamicLibrary, 213 staticLibrary, 214 object 215 } 216 217 enum BuildRequirement { 218 none = 0, /// No special requirements 219 allowWarnings = 1<<0, /// Warnings do not abort compilation 220 silenceWarnings = 1<<1, /// Don't show warnings 221 disallowDeprecations = 1<<2, /// Using deprecated features aborts compilation 222 silenceDeprecations = 1<<3, /// Don't show deprecation warnings 223 disallowInlining = 1<<4, /// Avoid function inlining, even in release builds 224 disallowOptimization = 1<<5, /// Avoid optimizations, even in release builds 225 requireBoundsCheck = 1<<6, /// Always perform bounds checks 226 requireContracts = 1<<7, /// Leave assertions and contracts enabled in release builds 227 relaxProperties = 1<<8, /// DEPRECATED: Do not enforce strict property handling (-property) 228 noDefaultFlags = 1<<9, /// Do not issue any of the default build flags (e.g. -debug, -w, -property etc.) - use only for development purposes 229 } 230 231 struct BuildRequirements { 232 import dub.internal.vibecompat.data.serialization : ignore; 233 234 static if (__VERSION__ >= 2067) { 235 @ignore BitFlags!BuildRequirement values; 236 this(BuildRequirement req) { values = req; } 237 } else { 238 @ignore BuildRequirement values; 239 this(BuildRequirement req) { values = req; } 240 BuildRequirement[] toRepresentation() 241 const { 242 BuildRequirement[] ret; 243 for (int f = 1; f <= BuildRequirement.max; f *= 2) 244 if (values & f) ret ~= cast(BuildRequirement)f; 245 return ret; 246 } 247 static BuildRequirements fromRepresentation(BuildRequirement[] v) 248 { 249 BuildRequirements ret; 250 foreach (f; v) ret.values |= f; 251 return ret; 252 } 253 } 254 alias values this; 255 } 256 257 enum BuildOption { 258 none = 0, /// Use compiler defaults 259 debugMode = 1<<0, /// Compile in debug mode (enables contracts, -debug) 260 releaseMode = 1<<1, /// Compile in release mode (disables assertions and bounds checks, -release) 261 coverage = 1<<2, /// Enable code coverage analysis (-cov) 262 debugInfo = 1<<3, /// Enable symbolic debug information (-g) 263 debugInfoC = 1<<4, /// Enable symbolic debug information in C compatible form (-gc) 264 alwaysStackFrame = 1<<5, /// Always generate a stack frame (-gs) 265 stackStomping = 1<<6, /// Perform stack stomping (-gx) 266 inline = 1<<7, /// Perform function inlining (-inline) 267 noBoundsCheck = 1<<8, /// Disable all bounds checking (-noboundscheck) 268 optimize = 1<<9, /// Enable optimizations (-O) 269 profile = 1<<10, /// Emit profiling code (-profile) 270 unittests = 1<<11, /// Compile unit tests (-unittest) 271 verbose = 1<<12, /// Verbose compiler output (-v) 272 ignoreUnknownPragmas = 1<<13, /// Ignores unknown pragmas during compilation (-ignore) 273 syntaxOnly = 1<<14, /// Don't generate object files (-o-) 274 warnings = 1<<15, /// Enable warnings (-wi) 275 warningsAsErrors = 1<<16, /// Treat warnings as errors (-w) 276 ignoreDeprecations = 1<<17, /// Do not warn about using deprecated features (-d) 277 deprecationWarnings = 1<<18, /// Warn about using deprecated features (-dw) 278 deprecationErrors = 1<<19, /// Stop compilation upon usage of deprecated features (-de) 279 property = 1<<20, /// DEPRECATED: Enforce property syntax (-property) 280 profileGC = 1<<21, /// Profile runtime allocations 281 // for internal usage 282 _docs = 1<<22, // Write ddoc to docs 283 _ddox = 1<<23, // Compile docs.json 284 } 285 286 struct BuildOptions { 287 import dub.internal.vibecompat.data.serialization : ignore; 288 289 static if (__VERSION__ >= 2067) { 290 @ignore BitFlags!BuildOption values; 291 this(BuildOption opt) { values = opt; } 292 this(BitFlags!BuildOption v) { values = v; } 293 } else { 294 @ignore BuildOption values; 295 this(BuildOption opt) { values = opt; } 296 BuildOption[] toRepresentation() 297 const { 298 BuildOption[] ret; 299 for (int f = 1; f <= BuildOption.max; f *= 2) 300 if (values & f) ret ~= cast(BuildOption)f; 301 return ret; 302 } 303 static BuildOptions fromRepresentation(BuildOption[] v) 304 { 305 BuildOptions ret; 306 foreach (f; v) ret.values |= f; 307 return ret; 308 } 309 } 310 311 alias values this; 312 } 313 314 /** 315 All build options that will be inherited upwards in the dependency graph 316 317 Build options in this category fulfill one of the following properties: 318 $(UL 319 $(LI The option affects the semantics of the generated code) 320 $(LI The option affects if a certain piece of code is valid or not) 321 $(LI The option enabled meta information in dependent projects that are useful for the dependee (e.g. debug information)) 322 ) 323 */ 324 enum BuildOptions inheritedBuildOptions = BuildOption.debugMode | BuildOption.releaseMode 325 | BuildOption.coverage | BuildOption.debugInfo | BuildOption.debugInfoC 326 | BuildOption.alwaysStackFrame | BuildOption.stackStomping | BuildOption.inline 327 | BuildOption.noBoundsCheck | BuildOption.profile | BuildOption.ignoreUnknownPragmas 328 | BuildOption.syntaxOnly | BuildOption.warnings | BuildOption.warningsAsErrors 329 | BuildOption.ignoreDeprecations | BuildOption.deprecationWarnings 330 | BuildOption.deprecationErrors | BuildOption.property | BuildOption.profileGC;