From d99cc0aec1f4239c97d31ea1801975023a611b32 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 13 Mar 2023 10:58:00 -0700 Subject: [PATCH] build.zig: automatically patchelf the rpath when in a nix shell --- build.zig | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/build.zig b/build.zig index 0234aafc2..5fa6c2ed7 100644 --- a/build.zig +++ b/build.zig @@ -3,6 +3,7 @@ const builtin = @import("builtin"); const fs = std.fs; const Builder = std.build.Builder; const LibExeObjStep = std.build.LibExeObjStep; +const RunStep = std.build.RunStep; const apprt = @import("src/apprt.zig"); const glfw = @import("vendor/mach/libs/glfw/build.zig"); const fontconfig = @import("pkg/fontconfig/build.zig"); @@ -116,6 +117,26 @@ pub fn build(b: *std.build.Builder) !void { "Build and install the benchmark executables.", ) orelse false; + // On NixOS, the built binary from `zig build` needs to patch the rpath + // into the built binary for it to be portable across the NixOS system + // it was built for. We default this to true if we can detect we're in + // a Nix shell and have LD_LIBRARY_PATH set. + const patch_rpath: ?[]const u8 = b.option( + []const u8, + "patch-rpath", + "Inject the LD_LIBRARY_PATH as the rpath in the built binary. " ++ + "This defaults to LD_LIBRARY_PATH if we're in a Nix shell environment on NixOS.", + ) orelse patch_rpath: { + // We only do the patching if we're targeting our own CPU and its Linux. + if (!target.isLinux() or !target.isNativeCpu()) break :patch_rpath null; + + // If we're in a nix shell we default to doing this. + // Note: we purposely never deinit envmap because we leak the strings + const env = try std.process.getEnvMap(b.allocator); + if (env.get("IN_NIX_SHELL") == null) break :patch_rpath null; + break :patch_rpath env.get("LD_LIBRARY_PATH"); + }; + var version_string = b.option( []const u8, "version-string", @@ -179,16 +200,36 @@ pub fn build(b: *std.build.Builder) !void { // Exe { + exe.addOptions("build_options", exe_options); + if (target.isDarwin()) { // See the comment in this file exe.addCSourceFile("src/renderer/metal_workaround.c", &.{}); } - exe.addOptions("build_options", exe_options); - if (app_runtime != .none) exe.install(); - // Add the shared dependencies _ = try addDeps(b, exe, static); + + // If we're installing, we get the install step so we can add + // additional dependencies to it. + const install_step = if (app_runtime != .none) step: { + const step = b.addInstallArtifact(exe); + b.getInstallStep().dependOn(&step.step); + break :step step; + } else null; + + // Patch our rpath if that option is specified. + if (patch_rpath) |rpath| { + if (rpath.len > 0) { + const run = RunStep.create(b, "patchelf rpath"); + run.addArgs(&.{ "patchelf", "--set-rpath", rpath }); + run.addArtifactArg(exe); + + if (install_step) |step| { + step.step.dependOn(&run.step); + } + } + } } // App (Linux)