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 dub.internal.configy.Attributes;
13 
14 import std.array : array;
15 import std.algorithm : filter, any;
16 import std.path : globMatch;
17 import std.typecons : BitFlags;
18 import std.algorithm.iteration : uniq;
19 import std.range : chain;
20 
21 /// BuildPlatform specific settings, like needed libraries or additional
22 /// include paths.
23 struct BuildSettings {
24 	import dub.internal.vibecompat.data.serialization : byName;
25 
26 	TargetType targetType;
27 	string targetPath;
28 	string targetName;
29 	string workingDirectory;
30 	string mainSourceFile;
31 	string[] dflags;
32 	string[] lflags;
33 	string[] libs;
34 	string[] linkerFiles;
35 	string[] sourceFiles;
36 	string[] injectSourceFiles;
37 	string[] copyFiles;
38 	string[] extraDependencyFiles;
39 	string[] versions;
40 	string[] debugVersions;
41 	string[] versionFilters;
42 	string[] debugVersionFilters;
43 	string[] importPaths;
44 	string[] cImportPaths;
45 	string[] stringImportPaths;
46 	string[] importFiles;
47 	string[] stringImportFiles;
48 	string[] preGenerateCommands;
49 	string[] postGenerateCommands;
50 	string[] preBuildCommands;
51 	string[] postBuildCommands;
52 	string[] preRunCommands;
53 	string[] postRunCommands;
54 	string[string] environments;
55 	string[string] buildEnvironments;
56 	string[string] runEnvironments;
57 	string[string] preGenerateEnvironments;
58 	string[string] postGenerateEnvironments;
59 	string[string] preBuildEnvironments;
60 	string[string] postBuildEnvironments;
61 	string[string] preRunEnvironments;
62 	string[string] postRunEnvironments;
63 	@byName Flags!BuildRequirement requirements;
64 	@byName Flags!BuildOption options;
65 
66 	BuildSettings dup()
67 	const {
68 		import std.traits: FieldNameTuple;
69 		import std.algorithm: map;
70 		import std.typecons: tuple;
71 		import std.array: assocArray;
72 		BuildSettings ret;
73 		foreach (m; FieldNameTuple!BuildSettings) {
74 			static if (is(typeof(__traits(getMember, ret, m) = __traits(getMember, this, m).dup)))
75 				__traits(getMember, ret, m) = __traits(getMember, this, m).dup;
76 			else static if (is(typeof(add(__traits(getMember, ret, m), __traits(getMember, this, m)))))
77 				add(__traits(getMember, ret, m), __traits(getMember, this, m));
78 			else static if (is(typeof(__traits(getMember, ret, m) = __traits(getMember, this, m))))
79 				__traits(getMember, ret, m) = __traits(getMember, this, m);
80 			else static assert(0, "Cannot duplicate BuildSettings." ~ m);
81 		}
82 		assert(ret.targetType == targetType);
83 		assert(ret.targetName == targetName);
84 		assert(ret.importPaths == importPaths);
85 		assert(ret.cImportPaths == cImportPaths);
86 		return ret;
87 	}
88 
89 	/**
90 	 * Merges $(LREF bs) onto `this` BuildSettings instance. This is called for
91 	 * sourceLibrary dependencies when they are included in the build to be
92 	 * merged into the root package build settings as well as configuring
93 	 * targets for different build types such as `release` or `unittest-cov`.
94 	 */
95 	void add(in BuildSettings bs)
96 	{
97 		addDFlags(bs.dflags);
98 		addLFlags(bs.lflags);
99 		addLibs(bs.libs);
100 		addLinkerFiles(bs.linkerFiles);
101 		addSourceFiles(bs.sourceFiles);
102 		addInjectSourceFiles(bs.injectSourceFiles);
103 		addCopyFiles(bs.copyFiles);
104 		addExtraDependencyFiles(bs.extraDependencyFiles);
105 		addVersions(bs.versions);
106 		addDebugVersions(bs.debugVersions);
107 		addVersionFilters(bs.versionFilters);
108 		addDebugVersionFilters(bs.debugVersionFilters);
109 		addImportPaths(bs.importPaths);
110 		addCImportPaths(bs.cImportPaths);
111 		addStringImportPaths(bs.stringImportPaths);
112 		addImportFiles(bs.importFiles);
113 		addStringImportFiles(bs.stringImportFiles);
114 		addPreGenerateCommands(bs.preGenerateCommands);
115 		addPostGenerateCommands(bs.postGenerateCommands);
116 		addPreBuildCommands(bs.preBuildCommands);
117 		addPostBuildCommands(bs.postBuildCommands);
118 		addPreRunCommands(bs.preRunCommands);
119 		addPostRunCommands(bs.postRunCommands);
120 		addEnvironments(bs.environments);
121 		addBuildEnvironments(bs.buildEnvironments);
122 		addRunEnvironments(bs.runEnvironments);
123 		addPreGenerateEnvironments(bs.preGenerateEnvironments);
124 		addPostGenerateEnvironments(bs.postGenerateEnvironments);
125 		addPreBuildEnvironments(bs.preBuildEnvironments);
126 		addPostBuildEnvironments(bs.postBuildEnvironments);
127 		addPreRunEnvironments(bs.preRunEnvironments);
128 		addPostRunEnvironments(bs.postRunEnvironments);
129 		addRequirements(bs.requirements);
130 		addOptions(bs.options);
131 	}
132 
133 	void addDFlags(in string[] value...) { dflags = chain(dflags, value.dup).uniq.array; }
134 	void prependDFlags(in string[] value...) { prepend(dflags, value); }
135 	void removeDFlags(in string[] value...) { remove(dflags, value); }
136 	void addLFlags(in string[] value...) { lflags ~= value; }
137 	void prependLFlags(in string[] value...) { prepend(lflags, value, false); }
138 	void addLibs(in string[] value...) { add(libs, value); }
139 	void addLinkerFiles(in string[] value...) { add(linkerFiles, value); }
140 	void addSourceFiles(in string[] value...) { add(sourceFiles, value); }
141 	void prependSourceFiles(in string[] value...) { prepend(sourceFiles, value); }
142 	void removeSourceFiles(in string[] value...) { removePaths(sourceFiles, value); }
143 	void addInjectSourceFiles(in string[] value...) { add(injectSourceFiles, value); }
144 	void addCopyFiles(in string[] value...) { add(copyFiles, value); }
145 	void addExtraDependencyFiles(in string[] value...) { add(extraDependencyFiles, value); }
146 	void addVersions(in string[] value...) { add(versions, value); }
147 	void addDebugVersions(in string[] value...) { add(debugVersions, value); }
148 	void addVersionFilters(in string[] value...) { add(versionFilters, value); }
149 	void addDebugVersionFilters(in string[] value...) { add(debugVersionFilters, value); }
150 	void addImportPaths(in string[] value...) { add(importPaths, value); }
151 	void addCImportPaths(in string[] value...) { add(cImportPaths, value); }
152 	void addStringImportPaths(in string[] value...) { add(stringImportPaths, value); }
153 	void prependStringImportPaths(in string[] value...) { prepend(stringImportPaths, value); }
154 	void addImportFiles(in string[] value...) { add(importFiles, value); }
155 	void addStringImportFiles(in string[] value...) { addSI(stringImportFiles, value); }
156 	void addPreGenerateCommands(in string[] value...) { add(preGenerateCommands, value, false); }
157 	void addPostGenerateCommands(in string[] value...) { add(postGenerateCommands, value, false); }
158 	void addPreBuildCommands(in string[] value...) { add(preBuildCommands, value, false); }
159 	void addPostBuildCommands(in string[] value...) { add(postBuildCommands, value, false); }
160 	void addPreRunCommands(in string[] value...) { add(preRunCommands, value, false); }
161 	void addPostRunCommands(in string[] value...) { add(postRunCommands, value, false); }
162 	void addEnvironments(in string[string] value) { add(environments, value); }
163 	void updateEnvironments(in string[string] value) { update(environments, value); }
164 	void addBuildEnvironments(in string[string] value) { add(buildEnvironments, value); }
165 	void updateBuildEnvironments(in string[string] value) { update(buildEnvironments, value); }
166 	void addRunEnvironments(in string[string] value) { add(runEnvironments, value); }
167 	void updateRunEnvironments(in string[string] value) { update(runEnvironments, value); }
168 	void addPreGenerateEnvironments(in string[string] value) { add(preGenerateEnvironments, value); }
169 	void updatePreGenerateEnvironments(in string[string] value) { update(preGenerateEnvironments, value); }
170 	void addPostGenerateEnvironments(in string[string] value) { add(postGenerateEnvironments, value); }
171 	void updatePostGenerateEnvironments(in string[string] value) { update(postGenerateEnvironments, value); }
172 	void addPreBuildEnvironments(in string[string] value) { add(preBuildEnvironments, value); }
173 	void updatePreBuildEnvironments(in string[string] value) { update(preBuildEnvironments, value); }
174 	void addPostBuildEnvironments(in string[string] value) { add(postBuildEnvironments, value); }
175 	void updatePostBuildEnvironments(in string[string] value) { update(postBuildEnvironments, value); }
176 	void addPreRunEnvironments(in string[string] value) { add(preRunEnvironments, value); }
177 	void updatePreRunEnvironments(in string[string] value) { update(preRunEnvironments, value); }
178 	void addPostRunEnvironments(in string[string] value) { add(postRunEnvironments, value); }
179 	void updatePostRunEnvironments(in string[string] value) { update(postRunEnvironments, value); }
180 	void addRequirements(in BuildRequirement[] value...) { foreach (v; value) this.requirements |= v; }
181 	void addRequirements(in Flags!BuildRequirement value) { this.requirements |= value; }
182 	void addOptions(in BuildOption[] value...) { foreach (v; value) this.options |= v; }
183 	void addOptions(in Flags!BuildOption value) { this.options |= value; }
184 	void removeOptions(in BuildOption[] value...) { foreach (v; value) this.options &= ~v; }
185 	void removeOptions(in Flags!BuildOption value) { this.options &= ~value; }
186 
187 private:
188 	static auto filterDuplicates(T)(ref string[] arr, in T vals, bool noDuplicates = true)
189 	{
190 		return noDuplicates
191 			? vals.filter!(filtered => !arr.any!(item => item == filtered)).array
192 			: vals;
193 	}
194 
195 	// Append `vals` to `arr` without adding duplicates.
196 	static void add(ref string[] arr, in string[] vals, bool noDuplicates = true)
197 	{
198 		// vals might contain duplicates, add each val individually
199 		foreach (val; vals)
200 			arr ~= filterDuplicates(arr, [val], noDuplicates);
201 	}
202 	// Append `vals` to `aa`
203 	static void add(ref string[string] aa, in string[string] vals)
204 	{
205 		// vals might contain duplicated keys, add each val individually
206 		foreach (key, val; vals)
207 			if (key !in aa)
208 				aa[key] = val;
209 	}
210 	// Update `vals` to `aa`
211 	static void update(ref string[string] aa, in string[string] vals)
212 	{
213 		// If there are duplicate keys, they will be ignored and overwritten.
214 		foreach (key, val; vals)
215 			aa[key] = val;
216 	}
217 
218 	unittest
219 	{
220 		auto ary = ["-dip1000", "-vgc"];
221 		BuildSettings.add(ary, ["-dip1000", "-vgc"]);
222 		assert(ary == ["-dip1000", "-vgc"]);
223 		BuildSettings.add(ary, ["-dip1001", "-vgc"], false);
224 		assert(ary == ["-dip1000", "-vgc", "-dip1001", "-vgc"]);
225 		BuildSettings.add(ary, ["-dupflag", "-notdupflag", "-dupflag"]);
226 		assert(ary == ["-dip1000", "-vgc", "-dip1001", "-vgc", "-dupflag", "-notdupflag"]);
227 	}
228 
229 	// Prepend `arr` by `vals` without adding duplicates.
230 	static void prepend(ref string[] arr, in string[] vals, bool noDuplicates = true)
231 	{
232 		import std.range : retro;
233 		// vals might contain duplicates, add each val individually
234 		foreach (val; vals.retro)
235 			arr = filterDuplicates(arr, [val], noDuplicates) ~ arr;
236 	}
237 
238 	unittest
239 	{
240 		auto ary = ["-dip1000", "-vgc"];
241 		BuildSettings.prepend(ary, ["-dip1000", "-vgc"]);
242 		assert(ary == ["-dip1000", "-vgc"]);
243 		BuildSettings.prepend(ary, ["-dip1001", "-vgc"], false);
244 		assert(ary == ["-dip1001", "-vgc", "-dip1000", "-vgc"]);
245 		BuildSettings.prepend(ary, ["-dupflag", "-notdupflag", "-dupflag"]);
246 		assert(ary == ["-notdupflag", "-dupflag", "-dip1001", "-vgc", "-dip1000", "-vgc"]);
247 	}
248 
249 	// add string import files (avoids file name duplicates in addition to path duplicates)
250 	static void addSI(ref string[] arr, in string[] vals)
251 	{
252 		bool[string] existing;
253 		foreach (v; arr) existing[NativePath(v).head.name] = true;
254 		foreach (v; vals) {
255 			auto s = NativePath(v).head.name;
256 			if (s !in existing) {
257 				existing[s] = true;
258 				arr ~= v;
259 			}
260 		}
261 	}
262 
263 	unittest
264 	{
265 		auto ary = ["path/foo.txt"];
266 		BuildSettings.addSI(ary, ["path2/foo2.txt"]);
267 		assert(ary == ["path/foo.txt", "path2/foo2.txt"]);
268 		BuildSettings.addSI(ary, ["path2/foo.txt"]); // no duplicate basenames
269 		assert(ary == ["path/foo.txt", "path2/foo2.txt"]);
270 	}
271 
272 	static bool pathMatch(string path, string pattern)
273 	{
274 		import std.functional : memoize;
275 
276 		alias nativePath = memoize!((string stringPath) => NativePath(stringPath));
277 
278 		return nativePath(path) == nativePath(pattern) || globMatch(path, pattern);
279 	}
280 
281 	static void removeValuesFromArray(alias Match)(ref string[] arr, in string[] vals)
282 	{
283 		bool matches(string s)
284 		{
285 			return vals.any!(item => Match(s, item));
286 		}
287 		arr = arr.filter!(s => !matches(s)).array;
288 	}
289 
290 	static void removePaths(ref string[] arr, in string[] vals)
291 	{
292 		removeValuesFromArray!(pathMatch)(arr, vals);
293 	}
294 
295 	unittest
296 	{
297 		auto ary = ["path1", "root/path1", "root/path2", "root2/path1"];
298 		BuildSettings.removePaths(ary, ["path1"]);
299 		assert(ary == ["root/path1", "root/path2", "root2/path1"]);
300 		BuildSettings.removePaths(ary, ["*/path1"]);
301 		assert(ary == ["root/path2"]);
302 		BuildSettings.removePaths(ary, ["foo", "bar", "root/path2"]);
303 		assert(ary == []);
304 	}
305 
306 	static void remove(ref string[] arr, in string[] vals)
307 	{
308 		removeValuesFromArray!((a, b) => a == b)(arr, vals);
309 	}
310 
311 	unittest
312 	{
313 		import std.string : join;
314 
315 		auto ary = ["path1", "root/path1", "root/path2", "root2/path1"];
316 		BuildSettings.remove(ary, ["path1"]);
317 		assert(ary == ["root/path1", "root/path2", "root2/path1"]);
318 		BuildSettings.remove(ary, ["root/path*"]);
319 		assert(ary == ["root/path1", "root/path2", "root2/path1"]);
320 		BuildSettings.removePaths(ary, ["foo", "root/path2", "bar", "root2/path1"]);
321 		assert(ary == ["root/path1"]);
322 		BuildSettings.remove(ary, ["root/path1", "foo"]);
323 		assert(ary == []);
324 	}
325 }
326 
327 enum BuildSetting {
328 	dflags            = 1<<0,
329 	lflags            = 1<<1,
330 	libs              = 1<<2,
331 	sourceFiles       = 1<<3,
332 	copyFiles         = 1<<4,
333 	versions          = 1<<5,
334 	debugVersions     = 1<<6,
335 	importPaths       = 1<<7,
336 	cImportPaths      = 1<<8,
337 	stringImportPaths = 1<<9,
338 	options           = 1<<10,
339 	none = 0,
340 	commandLine = dflags|copyFiles,
341 	commandLineSeparate = commandLine|lflags,
342 	all = dflags|lflags|libs|sourceFiles|copyFiles|versions|debugVersions|importPaths|cImportPaths|stringImportPaths|options,
343 	noOptions = all & ~options
344 }
345 
346 enum TargetType {
347 	autodetect,
348 	none,
349 	executable,
350 	library,
351 	sourceLibrary,
352 	dynamicLibrary,
353 	staticLibrary,
354 	object
355 }
356 
357 enum BuildRequirement {
358 	none = 0,                     /// No special requirements
359 	allowWarnings        = 1<<0,  /// Warnings do not abort compilation
360 	silenceWarnings      = 1<<1,  /// Don't show warnings
361 	disallowDeprecations = 1<<2,  /// Using deprecated features aborts compilation
362 	silenceDeprecations  = 1<<3,  /// Don't show deprecation warnings
363 	disallowInlining     = 1<<4,  /// Avoid function inlining, even in release builds
364 	disallowOptimization = 1<<5,  /// Avoid optimizations, even in release builds
365 	requireBoundsCheck   = 1<<6,  /// Always perform bounds checks
366 	requireContracts     = 1<<7,  /// Leave assertions and contracts enabled in release builds
367 	relaxProperties      = 1<<8,  /// DEPRECATED: Do not enforce strict property handling (-property)
368 	noDefaultFlags       = 1<<9,  /// Do not issue any of the default build flags (e.g. -debug, -w, -property etc.) - use only for development purposes
369 }
370 
371 enum BuildOption {
372 	none = 0,                     /// Use compiler defaults
373 	debugMode = 1<<0,             /// Compile in debug mode (enables contracts, -debug)
374 	releaseMode = 1<<1,           /// Compile in release mode (disables assertions and bounds checks, -release)
375 	coverage = 1<<2,              /// Enable code coverage analysis (-cov)
376 	debugInfo = 1<<3,             /// Enable symbolic debug information (-g)
377 	debugInfoC = 1<<4,            /// Enable symbolic debug information in C compatible form (-gc)
378 	alwaysStackFrame = 1<<5,      /// Always generate a stack frame (-gs)
379 	stackStomping = 1<<6,         /// Perform stack stomping (-gx)
380 	inline = 1<<7,                /// Perform function inlining (-inline)
381 	noBoundsCheck = 1<<8,         /// Disable all bounds checking (-noboundscheck)
382 	optimize = 1<<9,              /// Enable optimizations (-O)
383 	profile = 1<<10,              /// Emit profiling code (-profile)
384 	unittests = 1<<11,            /// Compile unit tests (-unittest)
385 	verbose = 1<<12,              /// Verbose compiler output (-v)
386 	ignoreUnknownPragmas = 1<<13, /// Ignores unknown pragmas during compilation (-ignore)
387 	syntaxOnly = 1<<14,           /// Don't generate object files (-o-)
388 	warnings = 1<<15,             /// Enable warnings (-wi)
389 	warningsAsErrors = 1<<16,     /// Treat warnings as errors (-w)
390 	ignoreDeprecations = 1<<17,   /// Do not warn about using deprecated features (-d)
391 	deprecationWarnings = 1<<18,  /// Warn about using deprecated features (-dw)
392 	deprecationErrors = 1<<19,    /// Stop compilation upon usage of deprecated features (-de)
393 	property = 1<<20,             /// DEPRECATED: Enforce property syntax (-property)
394 	profileGC = 1<<21,            /// Profile runtime allocations
395 	pic = 1<<22,                  /// Generate position independent code
396 	betterC = 1<<23,              /// Compile in betterC mode (-betterC)
397 	lowmem = 1<<24,               /// Compile in low-memory mode (-lowmem)
398 	coverageCTFE = 1<<25,         /// Enable code coverage analysis including at compile-time (-cov=ctfe)
399 	color = 1<<26,                /// Colorize output (-color)
400 
401 	// for internal usage
402 	_docs = 1<<27,                // Write ddoc to docs
403 	_ddox = 1<<28,                // Compile docs.json
404 }
405 
406 struct Flags (T) {
407 	import dub.internal.vibecompat.data.serialization : ignore;
408 	import dub.internal.vibecompat.data.json : Json;
409 
410 	@ignore BitFlags!T values;
411 
412 	public this(T opt) @safe pure nothrow @nogc
413 	{
414 		this.values = opt;
415 	}
416 
417 	public this(BitFlags!T v) @safe pure nothrow @nogc
418 	{
419 		this.values = v;
420 	}
421 
422 	alias values this;
423 
424 	public Json toJson() const
425 	{
426 		import std.conv : to;
427 		import std.traits : EnumMembers;
428 
429 		auto json = Json.emptyArray;
430 
431 		static foreach (em; EnumMembers!T) {
432 			static if (em != 0) {
433 				if (values & em) {
434 					json ~= em.to!string;
435 				}
436 			}
437 		}
438 
439 		return json;
440 	}
441 
442 	public static Flags!T fromJson(Json json)
443 	{
444 		import std.conv : to;
445 		import std.exception : enforce;
446 
447 		BitFlags!T flags;
448 
449 		enforce(json.type == Json.Type.array, "Should be an array");
450 		foreach (jval; json) {
451 			flags |= jval.get!string.to!T;
452 		}
453 
454 		return Flags!T(flags);
455 	}
456 
457 	/**
458 	 * Reads a list of flags from a JSON/YAML document and converts them
459 	 * to our internal representation.
460 	 *
461 	 * Flags inside of dub code are stored as a `BitFlags`,
462 	 * but they are specified in the recipe using an array of their name.
463 	 * This routine handles the conversion from `string[]` to `BitFlags!T`.
464 	 */
465 	public static Flags!T fromYAML (scope ConfigParser!(Flags!T) p)
466 	{
467 		import dub.internal.dyaml.node;
468 		import std.exception;
469 		import std.conv;
470 
471 		enforce(p.node.nodeID == NodeID.sequence, "Should be a sequence");
472 		typeof(return) res;
473 		foreach (str; p.node.sequence)
474 			res |= str.as!string.to!T;
475 		return res;
476 	}
477 }
478 
479 unittest
480 {
481 	import dub.internal.vibecompat.data.json;
482 
483 	auto opts = Flags!BuildOption(BuildOption.debugMode | BuildOption.debugInfo | BuildOption.warningsAsErrors);
484 	const str = serializeToJsonString(opts);
485 	assert(str == `["debugMode","debugInfo","warningsAsErrors"]`);
486 	assert(deserializeJson!(typeof(opts))(str) == opts);
487 }
488 
489 unittest
490 {
491 	import dub.internal.configy.Read;
492 
493 	static struct Config
494 	{
495 		Flags!BuildRequirement flags;
496 	}
497 
498 	auto c = parseConfigString!Config(`
499 {
500 	"flags": [ "allowWarnings", "noDefaultFlags", "disallowInlining" ]
501 }
502 `, __FILE__);
503 	assert(c.flags.allowWarnings);
504 	c.flags.allowWarnings = false;
505 	assert(c.flags.noDefaultFlags);
506 	c.flags.noDefaultFlags = false;
507 	assert(c.flags.disallowInlining);
508 	c.flags.disallowInlining = false;
509 	assert(c.flags == c.flags.init);
510 }
511 
512 /**
513 	All build options that will be inherited upwards in the dependency graph
514 
515 	Build options in this category fulfill one of the following properties:
516 	$(UL
517 		$(LI The option affects the semantics of the generated code)
518 		$(LI The option affects if a certain piece of code is valid or not)
519 		$(LI The option enabled meta information in dependent projects that are useful for the dependee (e.g. debug information))
520 	)
521 */
522 enum Flags!BuildOption inheritedBuildOptions =
523 	BuildOption.debugMode | BuildOption.releaseMode
524 	| BuildOption.coverage | BuildOption.coverageCTFE | BuildOption.debugInfo | BuildOption.debugInfoC
525 	| BuildOption.alwaysStackFrame | BuildOption.stackStomping | BuildOption.inline
526 	| BuildOption.noBoundsCheck | BuildOption.profile | BuildOption.ignoreUnknownPragmas
527 	| BuildOption.syntaxOnly | BuildOption.warnings	| BuildOption.warningsAsErrors
528 	| BuildOption.ignoreDeprecations | BuildOption.deprecationWarnings
529 	| BuildOption.deprecationErrors | BuildOption.property | BuildOption.profileGC
530 	| BuildOption.pic;
531 
532 deprecated("Use `Flags!BuildOption` instead")
533 public alias BuildOptions = Flags!BuildOption;
534 
535 deprecated("Use `Flags!BuildRequirement` instead")
536 public alias BuildRequirements = Flags!BuildRequirement;