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