Skip to content

Commit c7231c0

Browse files
committed
llvmPackages_15.llvm: run the tests on macOS
there are a few parts to this: - adding darwin specific check deps - working around referencing LLVM dylibs during the checkPhase in a way that supports darwin + previously we just set `$LD_LIBRARY_PATH` and/or made some strategic symlinks + now we have LLVM's `lit` config set the appropriate env vars as needed (as is done for other LLVM subprojects) + in retrospect switching to `installCheckPhase` might have been the better move.. - patching `lit` to deal with `$DYLD_LIBRARY_PATH` being purged for new "protected" processes more details within.
1 parent 6d0c876 commit c7231c0

4 files changed

Lines changed: 180 additions & 18 deletions

File tree

pkgs/development/compilers/llvm/15/llvm/default.nix

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
, release_version
1616
, zlib
1717
, which
18+
, sysctl
1819
, buildLlvmTools
1920
, debugVersion ? false
20-
, doCheck ? true
21+
, doCheck ? (!stdenv.isx86_32 /* TODO: why */) && (!stdenv.hostPlatform.isMusl)
22+
&& (stdenv.hostPlatform == stdenv.buildPlatform)
2123
, enableManpages ? false
2224
, enableSharedLibraries ? !stdenv.hostPlatform.isStatic
2325
, enablePFM ? stdenv.isLinux /* PFM only supports Linux */
@@ -89,7 +91,53 @@ in stdenv.mkDerivation (rec {
8991

9092
patches = [
9193
./gnu-install-dirs.patch
92-
] ++ lib.optional enablePolly ./gnu-install-dirs-polly.patch;
94+
95+
# Running the tests involves invoking binaries (like `opt`) that depend on
96+
# the LLVM dylibs and reference them by absolute install path (i.e. their
97+
# nix store path).
98+
#
99+
# Because we have not yet run the install phase (we're running these tests
100+
# as part of `checkPhase` instead of `installCheckPhase`) these absolute
101+
# paths do not exist yet; to work around this we point the loader (`ld` on
102+
# unix, `dyld` on macOS) at the `lib` directory which will later become this
103+
# package's `lib` output.
104+
#
105+
# Previously we would just set `LD_LIBRARY_PATH` to include the build `lib`
106+
# dir but:
107+
# - this doesn't generalize well to other platforms; `lit` doesn't forward
108+
# `DYLD_LIBRARY_PATH` (macOS):
109+
# + https://github.com/llvm/llvm-project/blob/0d89963df354ee309c15f67dc47c8ab3cb5d0fb2/llvm/utils/lit/lit/TestingConfig.py#L26
110+
# - even if `lit` forwarded this env var, we actually cannot set
111+
# `DYLD_LIBRARY_PATH` in the child processes `lit` launches because
112+
# `DYLD_LIBRARY_PATH` (and `DYLD_FALLBACK_LIBRARY_PATH`) is cleared for
113+
# "protected processes" (i.e. the python interpreter that runs `lit`):
114+
# https://stackoverflow.com/a/35570229
115+
# - other LLVM subprojects deal with this issue by having their `lit`
116+
# configuration set these env vars for us; it makes sense to do the same
117+
# for LLVM:
118+
# + https://github.com/llvm/llvm-project/blob/4c106cfdf7cf7eec861ad3983a3dd9a9e8f3a8ae/clang-tools-extra/test/Unit/lit.cfg.py#L22-L31
119+
#
120+
# !!! TODO: look into upstreaming this patch
121+
./llvm-lit-cfg-add-libs-to-dylib-path.patch
122+
123+
# `lit` has a mode where it executes run lines as a shell script which is
124+
# constructs; this is problematic for macOS because it means that there's
125+
# another process in between `lit` and the binaries being tested. As noted
126+
# above, this means that `DYLD_LIBRARY_PATH` is cleared which means that our
127+
# tests fail with dyld errors.
128+
#
129+
# To get around this we patch `lit` to reintroduce `DYLD_LIBRARY_PATH`, when
130+
# present in the test configuration.
131+
#
132+
# It's not clear to me why this isn't an issue for LLVM developers running
133+
# on macOS (nothing about this _seems_ nix specific)..
134+
./lit-shell-script-runner-set-dyld-library-path.patch
135+
] ++ lib.optionals enablePolly [
136+
./gnu-install-dirs-polly.patch
137+
138+
# Just like the `llvm-lit-cfg` patch, but for `polly`.
139+
./polly-lit-cfg-add-libs-to-dylib-path.patch
140+
];
93141

94142
postPatch = optionalString stdenv.isDarwin ''
95143
substituteInPlace cmake/modules/AddLLVM.cmake \
@@ -134,12 +182,6 @@ in stdenv.mkDerivation (rec {
134182
)
135183
'';
136184

137-
# hacky fix: created binaries need to be run before installation
138-
preBuild = ''
139-
mkdir -p $out/
140-
ln -sv $PWD/lib $out
141-
'';
142-
143185
# E.g. mesa.drivers use the build-id as a cache key (see #93946):
144186
LDFLAGS = optionalString (enableSharedLibraries && !stdenv.isDarwin) "-Wl,--build-id=sha1";
145187

@@ -217,14 +259,6 @@ in stdenv.mkDerivation (rec {
217259
)
218260
];
219261

220-
postBuild = ''
221-
rm -fR $out
222-
'';
223-
224-
preCheck = ''
225-
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}$PWD/lib
226-
'';
227-
228262
postInstall = ''
229263
mkdir -p $python/share
230264
mv $out/share/opt-viewer $python/share/opt-viewer
@@ -243,8 +277,7 @@ in stdenv.mkDerivation (rec {
243277
cp NATIVE/bin/llvm-config $dev/bin/llvm-config-native
244278
'';
245279

246-
doCheck = stdenv.isLinux && (!stdenv.isx86_32) && (!stdenv.hostPlatform.isMusl)
247-
&& (stdenv.hostPlatform == stdenv.buildPlatform);
280+
inherit doCheck;
248281

249282
checkTarget = "check-all";
250283

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py
2+
index 0242e0b75af3..d732011306f7 100644
3+
--- a/utils/lit/lit/TestRunner.py
4+
+++ b/utils/lit/lit/TestRunner.py
5+
@@ -1029,6 +1029,12 @@ def executeScript(test, litConfig, tmpBase, commands, cwd):
6+
f.write('@echo off\n')
7+
f.write('\n@if %ERRORLEVEL% NEQ 0 EXIT\n'.join(commands))
8+
else:
9+
+ # This env var is *purged* when invoking subprocesses so we have to
10+
+ # manually set it from within the bash script in order for the commands
11+
+ # in run lines to see this var:
12+
+ if "DYLD_LIBRARY_PATH" in test.config.environment:
13+
+ f.write(f'export DYLD_LIBRARY_PATH="{test.config.environment["DYLD_LIBRARY_PATH"]}"\n')
14+
+
15+
for i, ln in enumerate(commands):
16+
match = re.match(kPdbgRegex, ln)
17+
if match:
18+
@@ -1363,7 +1369,7 @@ def applySubstitutions(script, substitutions, conditions={},
19+
return processed
20+
21+
process = processLine if recursion_limit is None else processLineToFixedPoint
22+
-
23+
+
24+
return [unescapePercents(process(ln)) for ln in script]
25+
26+
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
diff --git a/test/Unit/lit.cfg.py b/test/Unit/lit.cfg.py
2+
index 81e8dc04acea..479ff95681e2 100644
3+
--- a/test/Unit/lit.cfg.py
4+
+++ b/test/Unit/lit.cfg.py
5+
@@ -3,6 +3,7 @@
6+
# Configuration file for the 'lit' test runner.
7+
8+
import os
9+
+import platform
10+
import subprocess
11+
12+
import lit.formats
13+
@@ -55,3 +56,26 @@ if sys.platform in ['win32', 'cygwin'] and os.path.isdir(config.shlibdir):
14+
# Win32 may use %SYSTEMDRIVE% during file system shell operations, so propogate.
15+
if sys.platform == 'win32' and 'SYSTEMDRIVE' in os.environ:
16+
config.environment['SYSTEMDRIVE'] = os.environ['SYSTEMDRIVE']
17+
+
18+
+# Add the LLVM dynamic libs to the platform-specific loader search path env var:
19+
+#
20+
+# TODO: this is copied from `clang`'s `lit.cfg.py`; should unify..
21+
+def find_shlibpath_var():
22+
+ if platform.system() in ['Linux', 'FreeBSD', 'NetBSD', 'OpenBSD', 'SunOS']:
23+
+ yield 'LD_LIBRARY_PATH'
24+
+ elif platform.system() == 'Darwin':
25+
+ yield 'DYLD_LIBRARY_PATH'
26+
+ elif platform.system() == 'Windows':
27+
+ yield 'PATH'
28+
+ elif platform.system() == 'AIX':
29+
+ yield 'LIBPATH'
30+
+
31+
+for shlibpath_var in find_shlibpath_var():
32+
+ shlibpath = os.path.pathsep.join(
33+
+ (config.shlibdir,
34+
+ config.environment.get(shlibpath_var, '')))
35+
+ config.environment[shlibpath_var] = shlibpath
36+
+ break
37+
+else:
38+
+ lit_config.warning("unable to inject shared library path on '{}'"
39+
+ .format(platform.system()))
40+
diff --git a/test/lit.cfg.py b/test/lit.cfg.py
41+
index 75a38b4c5dad..856fc75c9d74 100644
42+
--- a/test/lit.cfg.py
43+
+++ b/test/lit.cfg.py
44+
@@ -42,6 +42,26 @@ llvm_config.with_environment('PATH', config.llvm_tools_dir, append_path=True)
45+
llvm_config.with_system_environment(
46+
['HOME', 'INCLUDE', 'LIB', 'TMP', 'TEMP'])
47+
48+
+# Add the LLVM dynamic libs to the platform-specific loader search path env var:
49+
+#
50+
+# TODO: this is copied from `clang`'s `lit.cfg.py`; should unify..
51+
+def find_shlibpath_var():
52+
+ if platform.system() in ['Linux', 'FreeBSD', 'NetBSD', 'OpenBSD', 'SunOS']:
53+
+ yield 'LD_LIBRARY_PATH'
54+
+ elif platform.system() == 'Darwin':
55+
+ yield 'DYLD_LIBRARY_PATH'
56+
+ elif platform.system() == 'Windows':
57+
+ yield 'PATH'
58+
+ elif platform.system() == 'AIX':
59+
+ yield 'LIBPATH'
60+
+
61+
+for shlibpath_var in find_shlibpath_var():
62+
+ shlibpath = config.llvm_shlib_dir
63+
+ llvm_config.with_environment(shlibpath_var, shlibpath, append_path = True)
64+
+ break
65+
+else:
66+
+ lit_config.warning("unable to inject shared library path on '{}'"
67+
+ .format(platform.system()))
68+
69+
# Set up OCAMLPATH to include newly built OCaml libraries.
70+
top_ocaml_lib = os.path.join(config.llvm_lib_dir, 'ocaml')
71+
@@ -318,7 +338,7 @@ def have_cxx_shared_library():
72+
73+
try:
74+
readobj_cmd = subprocess.Popen(
75+
- [readobj_exe, '--needed-libs', readobj_exe], stdout=subprocess.PIPE)
76+
+ [readobj_exe, '--needed-libs', readobj_exe], stdout=subprocess.PIPE, env=config.environment)
77+
except OSError:
78+
print('could not exec llvm-readobj')
79+
return False
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
diff --git a/tools/polly/test/lit.cfg b/tools/polly/test/lit.cfg
2+
index 41e3a589c61e..09f3b17498b0 100644
3+
--- a/tools/polly/test/lit.cfg
4+
+++ b/tools/polly/test/lit.cfg
5+
@@ -36,9 +36,17 @@ base_paths = [config.llvm_tools_dir, config.environment['PATH']]
6+
path = os.path.pathsep.join(base_paths + config.extra_paths)
7+
config.environment['PATH'] = path
8+
9+
+# (Copied from polly/test/Unit/lit.cfg)
10+
+if platform.system() == 'Darwin':
11+
+ shlibpath_var = 'DYLD_LIBRARY_PATH'
12+
+elif platform.system() == 'Windows':
13+
+ shlibpath_var = 'PATH'
14+
+else:
15+
+ shlibpath_var = 'LD_LIBRARY_PATH'
16+
+
17+
path = os.path.pathsep.join((config.llvm_libs_dir,
18+
- config.environment.get('LD_LIBRARY_PATH','')))
19+
-config.environment['LD_LIBRARY_PATH'] = path
20+
+ config.environment.get(shlibpath_var,'')))
21+
+config.environment[shlibpath_var] = path
22+
23+
llvm_config.use_default_substitutions()
24+

0 commit comments

Comments
 (0)