1
+ load (
2
+ "@rules_haskell//haskell:cabal.bzl" ,
3
+ "haskell_cabal_binary" ,
4
+ )
1
5
load (
2
6
"//tests:inline_tests.bzl" ,
3
7
"py_inline_test" ,
@@ -19,12 +23,23 @@ dynamic_libraries(
19
23
tags = ["requires_zlib" ],
20
24
)
21
25
22
- # Tests that haskell_cabal_library will generate a relative RUNPATH entry for
23
- # the dependency on the nixpkgs provided libz. Relative meaning an entry that
24
- # starts with $ORIGIN (Linux) or @loader_path (MacOS). The alternative is an
25
- # absolute path, which would be wrong for the nixpkgs provided libz, as we want
26
- # the RUNPATH entry to point to Bazel's _solib_<cpu> directory and its absolute
27
- # path depends on the output root or execroot.
26
+ haskell_cabal_binary (
27
+ name = "cabal-binary" ,
28
+ srcs = glob (["cabal-binary/**" ]),
29
+ tags = ["requires_zlib" ],
30
+ deps = [
31
+ "//tests/hackage:base" ,
32
+ # Depend transitively on libz.
33
+ "@stackage-zlib//:zlib" ,
34
+ ],
35
+ )
36
+
37
+ # Tests that haskell_cabal_library|binary will generate a relative RUNPATH
38
+ # entry for the dependency on the nixpkgs provided libz. Relative meaning an
39
+ # entry that starts with $ORIGIN (Linux) or @loader_path (MacOS). The
40
+ # alternative is an absolute path, which would be wrong for the nixpkgs
41
+ # provided libz, as we want the RUNPATH entry to point to Bazel's _solib_<cpu>
42
+ # directory and its absolute path depends on the output root or execroot.
28
43
#
29
44
# It uses :libz_soname generated above to determine the expected RUNPATH entry
30
45
# for the libz dependency. The :libz_soname file will contain the file names of
@@ -33,17 +48,22 @@ dynamic_libraries(
33
48
# It uses :libHSzlib to access the dynamic library output of
34
49
# haskell_cabal_library and read the RUNPATH entries.
35
50
#
36
- # Note, ideally we would test that haskell_cabal_library _only_ generates a
37
- # relative RUNPATH entry and no absolute entries that leak the execroot into
38
- # the cache. Unfortunately, haskell_cabal_library generates such an entry at
39
- # the moment. See https://github.com/tweag/rules_haskell/issues/1130.
51
+ # It uses :cabal-binary to access a binary that transitively depends on libz.
52
+ #
53
+ # Note, ideally we would test that haskell_cabal_library|binary _only_
54
+ # generates a relative RUNPATH entry and no absolute entries that leak the
55
+ # execroot into the cache. Unfortunately, haskell_cabal_library|binary
56
+ # generates such an entry at the moment. See
57
+ # https://github.com/tweag/rules_haskell/issues/1130.
40
58
py_inline_test (
41
59
name = "stackage_zlib_runpath" ,
42
60
args = [
43
61
"$(rootpath :libz_soname)" ,
44
62
"$(rootpath :libHSzlib)" ,
63
+ "$(rootpath :cabal-binary)" ,
45
64
],
46
65
data = [
66
+ ":cabal-binary" ,
47
67
":libHSzlib" ,
48
68
":libz_soname" ,
49
69
],
@@ -65,57 +85,71 @@ with open(libz_soname) as fh:
65
85
sofile = fh.read().splitlines()[1]
66
86
sodir = os.path.dirname(sofile)
67
87
68
- # Determine libHSzlib RUNPATH
88
+ # Locate test artifacts.
69
89
libHSzlib = r.Rlocation(os.path.join(
70
90
os.environ["TEST_WORKSPACE"],
71
91
sys.argv[2],
72
92
))
73
- runpaths = []
74
- if platform.system() == "Darwin":
75
- dynamic_section = iter(subprocess.check_output(["otool", "-l", libHSzlib]).decode().splitlines())
76
- # otool produces lines of the form
77
- #
78
- # Load command ...
79
- # cmd LC_RPATH
80
- # cmdsize ...
81
- # path ...
82
- #
83
- for line in dynamic_section:
84
- # Find LC_RPATH entry
85
- if line.find("cmd LC_RPATH") != -1:
86
- break
87
- # Skip until path field
93
+ cabal_binary = r.Rlocation(os.path.join(
94
+ os.environ["TEST_WORKSPACE"],
95
+ sys.argv[3],
96
+ ))
97
+
98
+ def read_runpaths(binary):
99
+ runpaths = []
100
+ if platform.system() == "Darwin":
101
+ dynamic_section = iter(subprocess.check_output(["otool", "-l", binary]).decode().splitlines())
102
+ # otool produces lines of the form
103
+ #
104
+ # Load command ...
105
+ # cmd LC_RPATH
106
+ # cmdsize ...
107
+ # path ...
108
+ #
88
109
for line in dynamic_section:
89
- if line.strip().startswith("path"):
110
+ # Find LC_RPATH entry
111
+ if line.find("cmd LC_RPATH") != -1:
90
112
break
91
- runpaths.append(line.split()[1])
92
- else:
93
- dynamic_section = subprocess.check_output(["objdump", "--private-headers", libHSzlib]).decode().splitlines()
94
- # objdump produces lines of the form
95
- #
96
- # Dynamic Section:
97
- # ...
98
- # RUNPATH ...
99
- # ...
100
- for line in dynamic_section:
101
- if not line.strip().startswith("RUNPATH"):
113
+ # Skip until path field
114
+ for line in dynamic_section:
115
+ if line.strip().startswith("path"):
116
+ break
117
+ runpaths.append(line.split()[1])
118
+ else:
119
+ dynamic_section = subprocess.check_output(["objdump", "--private-headers", binary]).decode().splitlines()
120
+ # objdump produces lines of the form
121
+ #
122
+ # Dynamic Section:
123
+ # ...
124
+ # RUNPATH ...
125
+ # ...
126
+ for line in dynamic_section:
127
+ if not line.strip().startswith("RUNPATH"):
128
+ continue
129
+ runpaths.extend(line.split()[1].split(":"))
130
+
131
+ return runpaths
132
+
133
+ def test_binary(binary, sodir):
134
+ runpaths = read_runpaths(binary)
135
+ # Check that the binary contains a relative RUNPATH for sodir.
136
+ found = False
137
+ for runpath in runpaths:
138
+ if runpath.find(sodir) == -1:
102
139
continue
103
- runpaths.extend(line.split()[1].split(":"))
140
+ if runpath.startswith("$ORIGIN") or runpath.startswith("@loader_path"):
141
+ found = True
142
+ # XXX: Enable once #1130 is fixed.
143
+ #if os.path.isabs(runpath):
144
+ # print("Absolute RUNPATH entry discovered for %s: %s" % (sodir, runpath))
145
+ # sys.exit(1)
146
+
147
+ if not found:
148
+ print("Did not find a relative RUNPATH entry for %s among %s." % (sodir, runpaths))
104
149
105
- # Check that the binary contains a relative RUNPATH for sodir.
106
- found = False
107
- for runpath in runpaths:
108
- if runpath.find(sodir) == -1:
109
- continue
110
- if runpath.startswith("$ORIGIN") or runpath.startswith("@loader_path"):
111
- found = True
112
- # XXX: Enable once #1130 is fixed.
113
- #if os.path.isabs(runpath):
114
- # print("Absolute RUNPATH entry discovered for %s: %s" % (sodir, runpath))
115
- # sys.exit(1)
150
+ return found
116
151
117
- if not found:
118
- print("Did not find a relative RUNPATH entry for %s among %s." % (sodir, runpaths))
152
+ if not all(test_binary(binary, sodir) for binary in [libHSzlib, cabal_binary]):
119
153
sys.exit(1)
120
154
""" ,
121
155
tags = ["requires_zlib" ],
0 commit comments