Skip to content

Commit 5c9aaa8

Browse files
committed
Added: Gnu LD detector for being able to build without --start-group and --end-group when having a -link-internally
1 parent 4570621 commit 5c9aaa8

File tree

7 files changed

+555
-42
lines changed

7 files changed

+555
-42
lines changed

source/redub/api.d

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ ProjectDetails buildProject(ProjectDetails d)
197197
if(!d.tree)
198198
return d;
199199

200-
CompilingSession session = CompilingSession(d.compiler, osFromArch(d.cDetails.arch), isaFromArch(d.tree.requirements.cfg.arch));
200+
CompilingSession session = CompilingSession(d.compiler, d.cDetails.arch);
201201

202202
AdvCacheFormula sharedFormula;
203203
if(d.forceRebuild)
@@ -211,6 +211,9 @@ ProjectDetails buildProject(ProjectDetails d)
211211
ProjectNode tree = d.tree;
212212
if(d.useExistingObjFiles)
213213
tree.requirements.cfg.changedBuildFiles = getChangedBuildFiles(tree, session);
214+
int uses = tree.isUsingGnuLinker();
215+
if(uses != -1)
216+
session.compiler.usesGnuLinker = uses ? true : false;
214217
startHandlingConsoleControl();
215218

216219
auto result = timed(()
@@ -354,7 +357,7 @@ ProjectDetails resolveDependencies(
354357
static import redub.parsers.build_type;
355358

356359
StopWatch st = StopWatch(AutoStart.yes);
357-
Compiler compiler = getCompiler(cDetails.compilerOrPath, cDetails.assumption);
360+
Compiler compiler = getCompiler(cDetails.compilerOrPath, cDetails.assumption, cDetails.arch);
358361

359362
with(dubVars)
360363
{

source/redub/buildapi.d

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import redub.package_searching.api;
88

99

1010
///vX.X.X
11-
enum RedubVersionOnly = "v1.20.3";
11+
enum RedubVersionOnly = "v1.21.0";
1212
///Redub vX.X.X
1313
enum RedubVersionShort = "Redub "~RedubVersionOnly;
1414
///Redub vX.X.X - Description
@@ -30,6 +30,21 @@ struct CompilingSession
3030
Compiler compiler;
3131
OS os;
3232
ISA isa;
33+
34+
this(Compiler compiler, OS os, ISA isa)
35+
{
36+
this.compiler = compiler;
37+
this.os = os;
38+
this.isa = isa;
39+
}
40+
41+
this(Compiler compiler, string arch)
42+
{
43+
import redub.command_generators.commons;
44+
this.compiler = compiler;
45+
this.os = osFromArch(arch);
46+
this.isa = isaFromArch(arch);
47+
}
3348
}
3449

3550
enum TargetType
@@ -760,6 +775,34 @@ class ProjectNode
760775
return parallelizable;
761776
}
762777

778+
/**
779+
*
780+
* Returns: Values being either -1, 0 or 1
781+
*
782+
* -1: The linker flags doesn't say anything
783+
* 0: Linker flags explicitly set to not use (-link-internally or other linker)
784+
* 1: Explicitly set to use gnu ld. (-linker=ld)
785+
*
786+
*/
787+
int isUsingGnuLinker() const
788+
{
789+
import std.string:startsWith;
790+
foreach(lFlag; requirements.cfg.linkFlags)
791+
{
792+
if(lFlag.startsWith("-link"))
793+
{
794+
string temp = lFlag["-link".length..$];
795+
switch(temp) //-link-internally
796+
{
797+
case "-internally": return false;
798+
case "-er=ld": return true;
799+
default: return false;
800+
}
801+
}
802+
}
803+
return false;
804+
}
805+
763806
/**
764807
* This function will iterate recursively, from bottom to top, and it:
765808
* - Fixes the name if it is using subPackage name type.

source/redub/command_generators/linkers.d

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@ string[] parseLinkConfiguration(const ThreadBuildData data, CompilingSession s,
1010
import redub.misc.path;
1111
import redub.building.cache;
1212
string[] commands;
13-
14-
version(linux)
15-
bool isUsingGNULinker = true;
16-
else
17-
bool isUsingGNULinker = false;
13+
bool isUsingGNULinker = s.compiler.usesGnuLinker;
1814

1915
const BuildConfiguration b = data.cfg;
2016
with(b)

source/redub/compiler_identification.d

Lines changed: 124 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ enum AcceptedCompiler
1212
gxx
1313
}
1414

15+
enum UsesGnuLinker
16+
{
17+
unknown,
18+
yes,
19+
no
20+
}
21+
1522
AcceptedCompiler 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+
375466
private bool tryInferLdc(string compilerOrPath, string vString, out Compiler comp)
376467
{
377468
import std.exception;

0 commit comments

Comments
 (0)