Skip to content

Commit 4a89236

Browse files
committed
Remove use of system patchelf
Replace with set_runpath & set_runpath_tree CMK-31095 Change-Id: I245ccc33ccb8f272a022e811d5034069b66f0c9a (cherry picked from commit 65969ff)
1 parent 06e0bce commit 4a89236

20 files changed

Lines changed: 439 additions & 368 deletions

File tree

bazel/rules/make_deployable.bzl

Lines changed: 2 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,6 @@
1-
# Rules to fix binaries for deployment.
2-
# For example setting the RPATH
3-
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
4-
5-
# Set RPATH for a whole directory with unknown file names
6-
def _make_deployable_dir_impl(ctx):
7-
output_dir = ctx.actions.declare_directory(ctx.attr.input_dir)
8-
9-
ctx.actions.run_shell(
10-
inputs = [ctx.file.src],
11-
outputs = [output_dir],
12-
command = """
13-
mkdir -p {output_path}
14-
cp -r -L {src_path}/{input_dir}/* {output_path}
15-
16-
chmod u+w -R {output_path}
17-
18-
file -L {output_path}/* \\
19-
| grep ELF | cut -d ':' -f1 \\
20-
| xargs patchelf --force-rpath --set-rpath "{rpath}"
21-
22-
""".format(output_path = output_dir.path, src_path = ctx.file.src.path, input_dir = ctx.attr.input_dir, rpath = ctx.attr.rpath),
23-
)
24-
25-
return [DefaultInfo(files = depset([output_dir]))]
26-
27-
make_deployable_dir = rule(
28-
implementation = _make_deployable_dir_impl,
29-
attrs = {
30-
"src": attr.label(allow_single_file = True, providers = ["files"], mandatory = True), # gendir input
31-
"input_dir": attr.string(mandatory = True),
32-
"rpath": attr.string(mandatory = True),
33-
},
34-
)
35-
36-
# Set RPATH for a whole directory with known file names
37-
def _make_deployable_file_impl(ctx):
38-
out_file = ctx.actions.declare_file(ctx.attr.out)
39-
40-
ctx.actions.run_shell(
41-
inputs = [ctx.file.src],
42-
outputs = [out_file],
43-
command = """
44-
if [ -d {input_path} ]; then
45-
INPUT_FILE_PATH="{input_path}/{filename}"
46-
else
47-
INPUT_FILE_PATH="{input_path}"
48-
# assert: filename must be suffix of input_path
49-
fi
50-
cp -r -L $INPUT_FILE_PATH {file_dir}
51-
chmod u+w -R {file_dir}
52-
file -L {file_dir} \\
53-
| grep ELF | cut -d ':' -f1 \\
54-
| xargs patchelf --force-rpath --set-rpath "{rpath}"
55-
""".format(input_path = ctx.file.src.path, filename = ctx.attr.out, file_dir = out_file.path, rpath = ctx.attr.rpath),
56-
)
1+
"""Rules to prepare binaries for deployment by replacing strings."""
572

58-
return [DefaultInfo(files = depset([out_file]))]
59-
60-
make_deployable_file = rule(
61-
implementation = _make_deployable_file_impl,
62-
attrs = {
63-
"src": attr.label(allow_single_file = True, providers = ["files"], mandatory = True), # gendir input
64-
"out": attr.string(mandatory = True),
65-
"rpath": attr.string(mandatory = True),
66-
},
67-
)
3+
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
684

695
def _string_replace_impl(ctx):
706
output_dir = ctx.actions.declare_directory(ctx.label.name)

bazel/rules/patchelf.bzl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ set_soname = rule(
9393
)
9494

9595
def _set_runpath_tree_impl(ctx):
96-
"""Patches ELF .so files within a TreeArtifact with depth-relative RUNPATH."""
96+
"""Patches ELF files within a TreeArtifact with depth-relative RUNPATH."""
9797
patchelf = ctx.executable._patchelf
9898
tool = ctx.executable._tool
9999
src = ctx.file.src
@@ -119,7 +119,7 @@ set_runpath_tree = rule(
119119
),
120120
"src": attr.label(
121121
allow_single_file = True,
122-
doc = "TreeArtifact directory whose ELF .so files will be patched",
122+
doc = "TreeArtifact directory whose ELF files will be patched",
123123
mandatory = True,
124124
),
125125
"_patchelf": attr.label(
@@ -133,5 +133,5 @@ set_runpath_tree = rule(
133133
executable = True,
134134
),
135135
},
136-
doc = "Sets the RUNPATH of all ELF .so files within a directory TreeArtifact to depth-relative paths",
136+
doc = "Sets the RUNPATH of all ELF files within a directory TreeArtifact to depth-relative paths",
137137
)

bazel/rules/set_runpath_tree.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,30 @@
22
# Copyright (C) 2026 Checkmk GmbH - License: GNU General Public License v2
33
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
44
# conditions defined in the file COPYING, which is part of this source code package.
5-
"""Patches ELF .so files in a directory tree with depth-relative $ORIGIN rpaths."""
5+
"""Patches ELF files in a directory tree with depth-relative $ORIGIN rpaths."""
66

77
import os
8-
import re
98
import shutil
109
import subprocess
1110
import sys
1211

13-
_SO_PATTERN = re.compile(r"\.so(\.\d+)*$")
12+
13+
def _is_elf(filepath: str) -> bool:
14+
try:
15+
with open(filepath, "rb") as f:
16+
return f.read(4) == b"\x7fELF"
17+
except OSError:
18+
return False
1419

1520

1621
def _patch_elf_files(directory: str, patchelf: str, base_rpath: str) -> None:
1722
for dirpath, _, filenames in os.walk(directory):
1823
for filename in filenames:
19-
if not _SO_PATTERN.search(filename):
20-
continue
2124
filepath = os.path.join(dirpath, filename)
2225
if os.path.islink(filepath):
2326
continue
27+
if not _is_elf(filepath):
28+
continue
2429
rel_dir = os.path.relpath(dirpath, directory)
2530
depth = len(rel_dir.split(os.sep)) if rel_dir != "." else 0
2631
extra_ups = "/".join([".."] * (depth - 1)) if depth > 1 else ""

omd/packages/Python/BUILD

Lines changed: 74 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
load("@aspect_bazel_lib//lib:copy_file.bzl", "copy_file")
2+
load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory")
3+
load("@aspect_bazel_lib//lib:directory_path.bzl", "directory_path")
14
load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_filegroup", "pkg_files", "pkg_mklink", "strip_prefix")
25
load("@rules_pkg//pkg:tar.bzl", "pkg_tar")
3-
load("//bazel/rules:exclude_from_filegroup.bzl", "exclude_from_filegroup")
4-
load("//bazel/rules:make_deployable.bzl", "make_deployable_dir", "string_replace")
6+
load("//bazel/rules:make_deployable.bzl", "string_replace")
7+
load("//bazel/rules:patchelf.bzl", "set_runpath", "set_runpath_tree")
58
load("//omd/packages/Python:version.bzl", "PYTHON_MAJOR_DOT_MINOR", "PYTHON_VERSION_MAJOR")
69

710
exports_files([
@@ -78,40 +81,71 @@ share_symlinks = [
7881

7982
symlinks = bin_symlinks + lib_symlinks + pkgconfig_symlinks + share_symlinks
8083

81-
# Deployable means binaries are prepared to be packaged.
82-
genrule(
83-
name = "python_bin_deployable",
84-
srcs = ["@python//:gen_dir"],
85-
outs = bin_paths,
86-
cmd = """
87-
BIN=$$(find $(location @python//:gen_dir) -name bin)
88-
rsync -r -L --chmod='u+w' $$BIN $$(realpath $(RULEDIR))
84+
filegroup(
85+
name = "python_gen_dir",
86+
srcs = ["@python"],
87+
output_group = "gen_dir",
88+
tags = ["manual"],
89+
)
90+
91+
[directory_path(
92+
name = "python_bin_path_%s" % f.replace("/", "_").replace(".", "_"),
93+
directory = ":python_gen_dir",
94+
path = f,
95+
tags = ["manual"],
96+
) for f in bin_paths]
97+
98+
[copy_file(
99+
name = "python_bin_copy_%s" % f.replace("/", "_").replace(".", "_"),
100+
src = ":python_bin_path_%s" % f.replace("/", "_").replace(".", "_"),
101+
out = f.split("/")[-1],
102+
tags = ["manual"],
103+
) for f in bin_paths]
104+
105+
elf_bin_paths = [
106+
"bin/python%s" % PYTHON_MAJOR_DOT_MINOR,
107+
]
89108

90-
# set RPATH for all ELF binaries we find
91-
file -L $(OUTS) \\
92-
| grep ELF | cut -d ':' -f1 \\
93-
| xargs patchelf --force-rpath --set-rpath "\\$$ORIGIN/../lib"
94-
""",
109+
script_bin_paths = [f for f in bin_paths if f not in elf_bin_paths]
110+
111+
set_runpath(
112+
name = "python_bin_deployable",
113+
srcs = [":python_bin_copy_%s" % f.replace("/", "_").replace(".", "_") for f in elf_bin_paths],
114+
rpaths = ["$ORIGIN/../lib"],
95115
tags = ["manual"],
96116
)
97117

98118
pkg_files(
99119
name = "python_bin_pkg",
100120
srcs = [
101121
":python_bin_deployable",
102-
],
122+
] + [":python_bin_copy_%s" % f.replace("/", "_").replace(".", "_") for f in script_bin_paths],
103123
attributes = pkg_attributes(
104124
mode = "0755",
105125
),
106126
prefix = "bin",
107127
tags = ["manual"],
108128
)
109129

110-
make_deployable_dir(
130+
directory_path(
131+
name = "python_lib_dynload_path",
132+
directory = ":python_gen_dir",
133+
path = "lib/python%s/lib-dynload" % PYTHON_MAJOR_DOT_MINOR,
134+
tags = ["manual"],
135+
)
136+
137+
copy_to_directory(
138+
name = "python_lib_dynload_copy",
139+
srcs = [":python_lib_dynload_path"],
140+
include_external_repositories = ["**"],
141+
root_paths = ["**/lib-dynload"],
142+
tags = ["manual"],
143+
)
144+
145+
set_runpath_tree(
111146
name = "python_lib_dynload_deployable",
112-
src = "@python//:gen_dir",
113-
input_dir = "lib/python%s/lib-dynload" % PYTHON_MAJOR_DOT_MINOR,
114-
rpath = "\\$ORIGIN/../..",
147+
src = ":python_lib_dynload_copy",
148+
rpath = "$ORIGIN/../..",
115149
tags = ["manual"],
116150
)
117151

@@ -121,7 +155,8 @@ pkg_files(
121155
attributes = pkg_attributes(
122156
mode = "0755",
123157
),
124-
prefix = "lib/python%s/" % PYTHON_MAJOR_DOT_MINOR,
158+
prefix = "lib/python%s/lib-dynload" % PYTHON_MAJOR_DOT_MINOR,
159+
strip_prefix = "python_lib_dynload_deployable",
125160
tags = ["manual"],
126161
)
127162

@@ -136,7 +171,7 @@ pkg_filegroup(
136171
name = "python_bin_symlinks_pkg",
137172
srcs = [
138173
":%s" % link_name
139-
for link_name, target in bin_symlinks
174+
for link_name, _ in bin_symlinks
140175
],
141176
prefix = "bin",
142177
tags = ["manual"],
@@ -146,7 +181,7 @@ pkg_filegroup(
146181
name = "python_lib_symlinks_pkg",
147182
srcs = [
148183
":%s" % link_name
149-
for link_name, target in lib_symlinks
184+
for link_name, _ in lib_symlinks
150185
],
151186
prefix = "lib",
152187
tags = ["manual"],
@@ -156,7 +191,7 @@ pkg_filegroup(
156191
name = "python_pkgconfig_symlinks_pkg",
157192
srcs = [
158193
":%s" % link_name
159-
for link_name, target in pkgconfig_symlinks
194+
for link_name, _ in pkgconfig_symlinks
160195
],
161196
prefix = "lib/pkgconfig",
162197
tags = ["manual"],
@@ -166,7 +201,7 @@ pkg_filegroup(
166201
name = "python_share_symlinks_pkg",
167202
srcs = [
168203
":%s" % link_name
169-
for link_name, target in share_symlinks
204+
for link_name, _ in share_symlinks
170205
],
171206
prefix = "share/man/man1",
172207
tags = ["manual"],
@@ -179,15 +214,21 @@ pkg_filegroup(
179214
# the RPATH needs patching, symlinking.
180215
# This target should contain all files that are not referenced
181216
# explicitly somewhere else.
182-
exclude_from_filegroup(
217+
copy_to_directory(
183218
name = "python_rest",
184-
src = "@python//:gen_dir",
185-
excludes = ["lib/python%s/lib-dynload" % PYTHON_MAJOR_DOT_MINOR] +
186-
bin_paths +
187-
["bin/%s" % i[0] for i in bin_symlinks] +
188-
["lib/%s" % i[0] for i in lib_symlinks] +
189-
["lib/pkgconfig/%s" % i[0] for i in pkgconfig_symlinks] +
190-
["share/man/man1/%s" % i[0] for i in share_symlinks],
219+
srcs = ["@python"],
220+
exclude_srcs_patterns =
221+
["lib/python%s/lib-dynload/**" % PYTHON_MAJOR_DOT_MINOR] +
222+
["lib/%s" % i[0] for i in lib_symlinks] +
223+
["lib/pkgconfig/%s" % i[0] for i in pkgconfig_symlinks] +
224+
["share/man/man1/%s" % i[0] for i in share_symlinks],
225+
include_external_repositories = ["**"],
226+
include_srcs_patterns = [
227+
"include/**",
228+
"lib/**",
229+
"share/**",
230+
],
231+
root_paths = ["python"],
191232
tags = ["manual"],
192233
)
193234

omd/packages/Python/BUILD.Python.bazel

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,3 @@ configure_make(
114114
visibility = ["//visibility:public"],
115115
deps = ["@openssl"],
116116
)
117-
118-
filegroup(
119-
name = "gen_dir",
120-
srcs = [":python"],
121-
output_group = "gen_dir",
122-
)

omd/packages/freetds/BUILD

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,28 @@
1+
load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory")
2+
load("@aspect_bazel_lib//lib:directory_path.bzl", "directory_path")
13
load("@rules_pkg//pkg:mappings.bzl", "filter_directory", "pkg_filegroup", "pkg_files", "pkg_mklink", "strip_prefix")
24
load("@rules_pkg//pkg:tar.bzl", "pkg_tar")
3-
load("//bazel/rules:exclude_from_filegroup.bzl", "exclude_from_filegroup")
4-
load("//bazel/rules:make_deployable.bzl", "make_deployable_dir")
5+
load("//bazel/rules:patchelf.bzl", "set_runpath_tree")
56

6-
exclude_from_filegroup(
7+
filegroup(
8+
name = "freetds_gen_dir",
9+
srcs = ["@freetds"],
10+
output_group = "gen_dir",
11+
tags = ["manual"],
12+
)
13+
14+
directory_path(
15+
name = "freetds_include_dir",
16+
directory = ":freetds_gen_dir",
17+
path = "include",
18+
tags = ["manual"],
19+
)
20+
21+
copy_to_directory(
722
name = "freetds_include",
8-
src = "@freetds//:gen_dir",
9-
excludes = [
10-
"share",
11-
"etc",
12-
"lib",
13-
],
23+
srcs = [":freetds_include_dir"],
24+
include_external_repositories = ["**"],
25+
root_paths = ["**/freetds"],
1426
tags = ["manual"],
1527
)
1628

@@ -19,15 +31,29 @@ pkg_files(
1931
srcs = [
2032
":freetds_include",
2133
],
22-
strip_prefix = strip_prefix.from_pkg("rest"),
34+
strip_prefix = strip_prefix.from_pkg("freetds_include"),
35+
tags = ["manual"],
36+
)
37+
38+
directory_path(
39+
name = "freetds_lib_dir",
40+
directory = ":freetds_gen_dir",
41+
path = "lib",
42+
tags = ["manual"],
43+
)
44+
45+
copy_to_directory(
46+
name = "freetds_lib_copy",
47+
srcs = [":freetds_lib_dir"],
48+
include_external_repositories = ["**"],
49+
root_paths = ["**/lib"],
2350
tags = ["manual"],
2451
)
2552

26-
make_deployable_dir(
53+
set_runpath_tree(
2754
name = "freetds_lib_deployable",
28-
src = "@freetds//:gen_dir",
29-
input_dir = "lib",
30-
rpath = "\\$ORIGIN",
55+
src = ":freetds_lib_copy",
56+
rpath = "$ORIGIN",
3157
tags = ["manual"],
3258
)
3359

0 commit comments

Comments
 (0)