@@ -12,6 +12,13 @@ enum AcceptedCompiler
1212 gxx
1313}
1414
15+ enum UsesGnuLinker
16+ {
17+ unknown,
18+ yes,
19+ no
20+ }
21+
1522AcceptedCompiler acceptedCompilerfromString (string str)
1623{
1724 switch (str)
@@ -51,6 +58,8 @@ struct Compiler
5158
5259 bool usesIncremental = false ;
5360
61+ bool usesGnuLinker = false ;
62+
5463
5564 string getCompilerString () const
5665 {
@@ -156,69 +165,133 @@ private string getActualCompilerToUse(string preferredCompiler, ref string actua
156165 return compVersionRes.output;
157166}
158167
168+ string tryGetStr (JSONValue v, string key)
169+ {
170+ JSONValue* ret = key in v;
171+ return ret ? ret.str : null ;
172+ }
159173
160174/**
161175 * Use this function to get extensive information about the Compiler to use.
162176 * Params:
163177 * compilerOrPath = Can be used both as a global, such as `dmd` or a complete path to a compiler. If null, defaults to DMD
164178 * compilerAssumption = Optinal version string, such as `dmd v[2.105.0] f[2.106.0]`, v being its version, f being frontend version
179+ * arch = Used mainly for identifying which ldc.conf to take, and by using it, it is possible to detect the default linker for the specific arch
165180 * Returns: The Compiler information that was found, or inferred if compilerAssumption was used.
166181 */
167- Compiler getCompiler (string compilerOrPath = " dmd" , string compilerAssumption = null )
182+ Compiler getCompiler (string compilerOrPath = " dmd" , string compilerAssumption = null , string arch = null )
168183{
169- import std.process ;
170184 import std.algorithm.comparison :either;
171185 import redub.misc.find_executable;
172186 import redub.meta;
173- import std.exception ;
174187 import std.path ;
175188
176189
177190 JSONValue compilersInfo = getRedubMeta();
178- bool isDefault;
179- if (compilerOrPath == null )
180- {
181- if (" defaultCompiler" in compilersInfo)
182- compilerOrPath = compilersInfo[" defaultCompiler" ].str;
183- isDefault = true ;
184- }
185- if (compilerOrPath == null )
186- compilerOrPath = " dmd" ;
191+ bool isDefault = compilerOrPath == null ;
192+ compilerOrPath = either(compilerOrPath, tryGetStr(compilersInfo, " defaultCompiler" ), " dmd" );
193+ bool isGlobal = false ;
187194
188- bool isGlobal;
195+ Compiler ret;
196+ // Try get compiler on global cache with global cached paths
189197 if (! isAbsolute(compilerOrPath))
190198 {
191199 string locCompiler = tryGetCompilerOnCwd(compilerOrPath);
192- isGlobal = locCompiler == compilerOrPath;
193-
194- if (! isGlobal)
200+ if (locCompiler != compilerOrPath)
195201 compilerOrPath = locCompiler;
196202 else
197203 {
198- if (JSONValue* globalPaths = " globalPaths" in compilersInfo)
199- {
200- if (JSONValue* cachedPath = compilerOrPath in * globalPaths)
201- {
202- Compiler ret = getCompilerFromCache(compilersInfo, cachedPath.str);
203- if (ret != Compiler.init)
204- return ret;
205- }
206- }
207- compilerOrPath = findExecutable(compilerOrPath);
204+ ret = getCompilerFromGlobalPath(compilerOrPath, compilersInfo);
205+ isGlobal = true ;
208206 }
209207 }
208+ // Try finding the compiler globally and getting it from cache
209+ if (ret == Compiler.init)
210+ {
211+ compilerOrPath = findExecutable(compilerOrPath);
212+ ret = getCompilerFromCache(compilersInfo, compilerOrPath);
213+ }
214+ // Try inferring the compiler and saving its infos
215+ if (ret == Compiler.init)
216+ ret = inferCompiler(compilerOrPath, compilerAssumption, compilersInfo, isDefault, isGlobal);
210217
211- Compiler ret = getCompilerFromCache(compilersInfo, compilerOrPath);
212- if (ret != Compiler.init)
213- return ret;
218+ ret.usesGnuLinker = compilersInfo[" defaultsToGnuLd" ].boolean;
214219
220+ // Checks for ldc.conf switches to see if it is using gnu linker by default
221+ if (ret.compiler == AcceptedCompiler.ldc2)
222+ {
223+ int res = isUsingGnuLinker(ret.binOrPath, arch);
224+ if (res != UsesGnuLinker.unknown)
225+ ret.usesGnuLinker = res == UsesGnuLinker.yes ? true : false ;
226+ }
227+
228+
229+ return ret;
230+ }
215231
232+ /**
233+ * Used for determining whether it is running on gnu ld or not
234+ * Params:
235+ * ldcPath = Ldc path for finding the ldc.conf file
236+ * arch = Which architecture this compiler run is running with
237+ * Returns: -1 for can't tell. 0 if false and 1 if true
238+ */
239+ private UsesGnuLinker isUsingGnuLinker (string ldcPath, string arch)
240+ {
241+ import redub.misc.ldc_conf_parser;
242+ import std.file ;
243+ import std.algorithm.searching ;
244+ ConfigSection section = getLdcConfig(std.file.getcwd (), ldcPath, arch);
245+ if (section == ConfigSection.init)
246+ return UsesGnuLinker.unknown;
247+ string * switches = " switches" in section.values ;
248+ if (! switches)
249+ return UsesGnuLinker.unknown;
250+ string s = * switches;
251+ ptrdiff_t linkerStart = s.countUntil(" -link" );
252+ if (linkerStart == - 1 )
253+ return UsesGnuLinker.unknown;
254+ s = s[linkerStart.. $];
255+
256+ if (countUntil(s, " -link-internally" ) != - 1 || countUntil(s, " -linker=lld" ))
257+ return UsesGnuLinker.no;
258+
259+ return countUntil (s, " -linker=ld" ) != - 1 ? UsesGnuLinker.yes : UsesGnuLinker.unknown;
260+ }
261+
262+
263+ private Compiler getCompilerFromGlobalPath (string compilerOrPath, JSONValue compilersInfo)
264+ {
265+ if (JSONValue* globalPaths = " globalPaths" in compilersInfo)
266+ {
267+ if (JSONValue* cachedPath = compilerOrPath in * globalPaths)
268+ return getCompilerFromCache (compilersInfo, cachedPath.str);
269+ }
270+ return Compiler.init;
271+ }
272+
273+ /**
274+ *
275+ * Params:
276+ * compilerOrPath = The path where the compiler is
277+ * compilerAssumption = Assumption that will make skip --version call
278+ * compilersInfo = Used for saving metadata
279+ * isDefault = Used for metadata
280+ * isGlobal = Used for metadata
281+ * Returns: The compiler that was inferrred from the given info
282+ */
283+ private Compiler inferCompiler (string compilerOrPath, string compilerAssumption, JSONValue compilersInfo, bool isDefault, bool isGlobal)
284+ {
285+ import redub.misc.find_executable;
286+ import std.array ;
216287 immutable inference = [
217288 &tryInferDmd,
218289 &tryInferLdc,
219290 &tryInferGcc,
220291 &tryInferGxx
221- ];
292+ ].staticArray;
293+
294+ Compiler ret;
222295
223296 if (compilerAssumption == null )
224297 {
@@ -278,7 +351,7 @@ private Compiler getCompilerFromCache(JSONValue allCompilersInfo, string compile
278351 SemVer(arr[VERSION_ ].str),
279352 SemVer(arr[FRONTEND_VERSION ].str),
280353 arr[VERSION_STRING ].str,
281- key
354+ key, null , false , allCompilersInfo[ " defaultsToGnuLd " ].boolean
282355 );
283356 }
284357 }
@@ -296,11 +369,11 @@ private Compiler getCompilerFromCache(JSONValue allCompilersInfo, string compile
296369```
297370 * Params:
298371 * allCompilersInfo = The JSON value of the current redub compilers info
299- * compiler = The new compiler to add
372+ * compiler = The new compiler to add. It will also save usesGnuLinker inside compiler
300373 * isDefault = saves the compiler as the default compiler
301374 * isGlobal = Saves the compiler as a globalPath. For example, it will use the path whenever expected to find in global path when "dmd" is sent or "ldc2" (i.e: no real path)
302375 */
303- private void saveCompilerInfo (JSONValue allCompilersInfo, Compiler compiler, bool isDefault, bool isGlobal)
376+ private void saveCompilerInfo (JSONValue allCompilersInfo, ref Compiler compiler, bool isDefault, bool isGlobal)
304377{
305378 import redub.meta;
306379 import std.conv :to;
@@ -320,6 +393,11 @@ private void saveCompilerInfo(JSONValue allCompilersInfo, Compiler compiler, boo
320393 if (! (" version" in allCompilersInfo))
321394 allCompilersInfo[" version" ] = JSONValue(RedubVersionOnly);
322395
396+ if (! (" defaultsToGnuLd" in allCompilersInfo))
397+ allCompilersInfo[" defaultsToGnuLd" ] = JSONValue(isDefaultLinkerGnuLd());
398+
399+ compiler.usesGnuLinker = allCompilersInfo[" defaultsToGnuLd" ].boolean;
400+
323401 if (! (" compilers" in allCompilersInfo))
324402 allCompilersInfo[" compilers" ] = JSONValue.emptyObject;
325403
@@ -372,6 +450,19 @@ private Compiler assumeCompiler(string compilerOrPath, string compilerAssumption
372450}
373451
374452
453+ bool isDefaultLinkerGnuLd ()
454+ {
455+ version (linux )
456+ {
457+ import std.process ;
458+ import std.string ;
459+ auto res = executeShell(" ld -v" );
460+ return res.status == 0 && res.output.startsWith(" GNU ld" );
461+ }
462+ else
463+ return false ;
464+ }
465+
375466private bool tryInferLdc (string compilerOrPath, string vString, out Compiler comp)
376467{
377468 import std.exception ;
0 commit comments