1+ load (
2+ "@rules_haskell//haskell:cabal.bzl" ,
3+ "haskell_cabal_binary" ,
4+ )
15load (
26 "//tests:inline_tests.bzl" ,
37 "py_inline_test" ,
@@ -19,12 +23,23 @@ dynamic_libraries(
1923 tags = ["requires_zlib" ],
2024)
2125
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.
2843#
2944# It uses :libz_soname generated above to determine the expected RUNPATH entry
3045# for the libz dependency. The :libz_soname file will contain the file names of
@@ -33,17 +48,22 @@ dynamic_libraries(
3348# It uses :libHSzlib to access the dynamic library output of
3449# haskell_cabal_library and read the RUNPATH entries.
3550#
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.
4058py_inline_test (
4159 name = "stackage_zlib_runpath" ,
4260 args = [
4361 "$(rootpath :libz_soname)" ,
4462 "$(rootpath :libHSzlib)" ,
63+ "$(rootpath :cabal-binary)" ,
4564 ],
4665 data = [
66+ ":cabal-binary" ,
4767 ":libHSzlib" ,
4868 ":libz_soname" ,
4969 ],
@@ -65,57 +85,71 @@ with open(libz_soname) as fh:
6585 sofile = fh.read().splitlines()[1]
6686 sodir = os.path.dirname(sofile)
6787
68- # Determine libHSzlib RUNPATH
88+ # Locate test artifacts.
6989libHSzlib = r.Rlocation(os.path.join(
7090 os.environ["TEST_WORKSPACE"],
7191 sys.argv[2],
7292))
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+ #
88109 for line in dynamic_section:
89- if line.strip().startswith("path"):
110+ # Find LC_RPATH entry
111+ if line.find("cmd LC_RPATH") != -1:
90112 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:
102139 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))
104149
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
116151
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]):
119153 sys.exit(1)
120154""" ,
121155 tags = ["requires_zlib" ],
0 commit comments