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