Skip to content

Commit 3704fc4

Browse files
committed
Improve brand detection for ld
1 parent ba8d96d commit 3704fc4

5 files changed

Lines changed: 52 additions & 15 deletions

File tree

‎bfg9000/platforms/core.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import importlib_metadata as metadata
2+
import os
23
import platform
34
import re
45
import subprocess
@@ -49,6 +50,8 @@ def _result(arch, vendor_sys, abi=None):
4950

5051
@memoize
5152
def platform_name():
53+
if 'BFG_FORCE_PLATFORM' in os.environ:
54+
return os.environ['BFG_FORCE_PLATFORM']
5255
system = platform.system().lower()
5356
if system.startswith('cygwin'):
5457
return 'cygwin'

‎bfg9000/tools/cc/__init__.py‎

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,26 @@ def __init__(self, env, langinfo, command, found, version_output):
5858
arflags_name = arinfo.var('flags').lower()
5959
arflags = shell.split(env.getvar(arinfo.var('flags'), 'cr'))
6060

61-
# macOS's ld doesn't support --version, but we can still try it out and
62-
# grab the command line.
6361
ld_command = None
6462
try:
65-
stdout, stderr = env.execute(
66-
command + ldflags + ['-v', '-Wl,--version'],
67-
stdout=shell.Mode.pipe, stderr=shell.Mode.pipe,
63+
# Pass a sentinel flag to the linker so we can examine the verbose
64+
# compiler output and try to determine which linker we're using.
65+
output = env.execute(
66+
command + ldflags + ['-v', '-Wl,-v', '-Wl,--not-a-real-flag'],
67+
stdout=shell.Mode.pipe, stderr=shell.Mode.stdout,
6868
returncode='any'
6969
)
7070

71-
for line in stderr.split('\n'):
72-
if '--version' in line:
73-
ld_command = shell.split(line)[0:1]
74-
if os.path.basename(ld_command[0]) != 'collect2':
75-
break
71+
for line in output.split('\n'):
72+
if '--not-a-real-flag' in line:
73+
args = shell.split(line)
74+
if os.path.basename(args[0]) != 'collect2':
75+
try:
76+
shell.which(args[0])
77+
ld_command = args[0:1]
78+
break
79+
except FileNotFoundError:
80+
pass
7681
except (OSError, shell.CalledProcessError):
7782
pass
7883

@@ -96,7 +101,7 @@ def __init__(self, env, langinfo, command, found, version_output):
96101
),
97102
}
98103
if ld_command:
99-
self._linkers['raw'] = LdLinker(self, env, ld_command, stdout)
104+
self._linkers['raw'] = LdLinker(self, env, ld_command)
100105

101106
self.packages = CcPackageResolver(self, env, command, ldflags)
102107
self.runner = None

‎bfg9000/tools/ld.py‎

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,40 @@
66

77

88
class LdLinker:
9-
def __init__(self, builder, env, command, version_output):
9+
def __init__(self, builder, env, command):
1010
self.builder = builder
1111
self.env = env
1212
self.command = command
1313
# Currently, if we're constructing this object, we know the command has
1414
# been found.
1515
self.found = True
1616

17+
version_output = self.check_command(env, command)
1718
if 'GNU ld' in version_output:
1819
self.brand = 'bfd'
1920
self.version = detect_version(version_output)
2021
elif 'GNU gold' in version_output:
2122
self.brand = 'gold'
22-
self.version = detect_version(version_output, post='$',
23-
flags=re.MULTILINE)
23+
self.version = detect_version(version_output, post='$', flags=re.M)
24+
elif 'LLD' in version_output:
25+
self.brand = 'lld'
26+
self.version = detect_version(version_output)
27+
elif '@(#)PROGRAM:ld' in version_output:
28+
self.brand = 'apple'
29+
self.version = detect_version(version_output)
2430
else:
2531
self.brand = 'unknown'
2632
self.version = None
2733

34+
@staticmethod
35+
def check_command(env, command):
36+
try:
37+
return env.execute(command + ['--version'], stdout=shell.Mode.pipe,
38+
stderr=shell.Mode.devnull)
39+
except shell.CalledProcessError:
40+
return env.execute(command + ['-v'], stdout=shell.Mode.pipe,
41+
stderr=shell.Mode.devnull)
42+
2843
@property
2944
def lang(self):
3045
return self.builder.lang

‎bfg9000/tools/yacc.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def __init__(self, env, langinfo, command, found, version_output):
4040

4141
@staticmethod
4242
def _parse_brand(version_output):
43-
if 'bison' in version_output:
43+
if 'GNU Bison' in version_output:
4444
return 'bison', detect_version(version_output)
4545
return 'unknown', None
4646

‎test/unit/tools/test_ld.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,20 @@ def test_gnu_gold(self):
4747
self.assertEqual(ld.brand, 'gold')
4848
self.assertEqual(ld.version, Version('1.11'))
4949

50+
def test_lld(self):
51+
version = 'LLD 10.0.0 (compatible with GNU linkers)'
52+
ld = LdLinker(None, self.env, ['ld'], version)
53+
54+
self.assertEqual(ld.brand, 'lld')
55+
self.assertEqual(ld.version, Version('10.0.0'))
56+
57+
def test_apple(self):
58+
version = '@(#)PROGRAM:ld PROJECT:ld-1167.5'
59+
ld = LdLinker(None, self.env, ['ld'], version)
60+
61+
self.assertEqual(ld.brand, 'apple')
62+
self.assertEqual(ld.version, Version('1167.5'))
63+
5064
def test_unknown_brand(self):
5165
version = 'unknown'
5266
ld = LdLinker(None, self.env, ['ld'], version)

0 commit comments

Comments
 (0)