From 5009cbabac3bf244ca83ad170c3685a3daf38cc1 Mon Sep 17 00:00:00 2001 From: Malte Poll <1780588+malt3@users.noreply.github.com> Date: Thu, 23 Nov 2023 17:16:44 +0100 Subject: [PATCH] bazel: add patchelf rule This rule allows overwriting a binaries' rpath. This is required to use binaries built by Bazel that link against cc_library targets from nix (like `/nix/store//lib/*.so`). --- WORKSPACE.bazel | 5 ++++ bazel/patchelf/BUILD.bazel | 0 bazel/patchelf/patchelf.bzl | 51 +++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 bazel/patchelf/BUILD.bazel create mode 100644 bazel/patchelf/patchelf.bzl diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index ddec92a54..664992c34 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -88,6 +88,11 @@ nixpkgs_package( repository = "@nixpkgs", ) +nixpkgs_package( + name = "patchelf", + repository = "@nixpkgs", +) + nixpkgs_package( name = "systemd", repository = "@nixpkgs", diff --git a/bazel/patchelf/BUILD.bazel b/bazel/patchelf/BUILD.bazel new file mode 100644 index 000000000..e69de29bb diff --git a/bazel/patchelf/patchelf.bzl b/bazel/patchelf/patchelf.bzl new file mode 100644 index 000000000..d837fcd7f --- /dev/null +++ b/bazel/patchelf/patchelf.bzl @@ -0,0 +1,51 @@ +""" Bazel rule for postprocessing elf files with patchelf """ + +def _patchelf_impl(ctx): + output = ctx.outputs.out + ctx.actions.run_shell( + inputs = [ctx.file.src, ctx.file.rpath, ctx.file.interpreter], + tools = [ctx.executable._patchelf_binary], + outputs = [output], + arguments = [ + ctx.executable._patchelf_binary.path, + ctx.file.rpath.path, + ctx.file.interpreter.path, + output.path, + ctx.file.src.path, + ], + command = "\"$1\" --set-rpath \"$(cat \"$2\")\" --set-interpreter \"$(cat \"$3\")\" --output \"$4\" \"$5\"", + progress_message = "Patching ELF binary " + ctx.file.src.basename, + ) + return DefaultInfo( + files = depset([output]), + executable = output, + ) + +patchelf = rule( + implementation = _patchelf_impl, + attrs = { + "out": attr.output(mandatory = True), + "rpath": attr.label(mandatory = True, allow_single_file = True), + "interpreter": attr.label(mandatory = True, allow_single_file = True), + "src": attr.label(mandatory = True, allow_single_file = True), + "_patchelf_binary": attr.label( + default = Label("@patchelf//:bin/patchelf"), + allow_single_file = True, + executable = True, + cfg = "exec", + ), + }, + doc = """Uses patchelf to set the rpath and interpreter of an ELF binary. + +This is a post processing step for binaries that are built by Bazel +that link shared libraries from Nix. +Native nix binaries always use absolute paths to a specific linker and +embed the rpath for each linked library as an absolute nix store path. +Bazel embeds rpaths using $ORIGIN and uses paths relative to +the binaries output location. Without patchelf, the binary would only +work if we also ship all runfiles with the binary and preserve the relative +directory structure. +See https://github.com/tweag/rules_nixpkgs/issues/449 for more details. +""", + executable = True, +)