Skip to content

Commit 7bcafc9

Browse files
fix(nix): strip the unused libiconv dependency on Darwin (#1292)
* fix(nix): drop unused libiconv from the Darwin build ccusage links no iconv symbols (verified: `nm -u` shows none on both arm64 and x64, no iconv crate in Cargo.lock), but libiconv was listed in the Darwin buildInputs, so the linker recorded /usr/lib/libiconv.2.dylib as an unused load-time dependency. When the Darwin package was built with Nix that path was the /nix/store one, which dyld can't resolve on non-Nix Macs — the crash behind #1251 (worked around in #1256 by rewriting the install name). Remove libiconv from buildInputs so the binary links only system dylibs and the install-name rewrite is no longer needed. The portability gate (otool, reject non-system dylibs) stays to catch any future stray /nix dependency. * fix(nix): strip the unused libiconv dependency with dead_strip_dylibs Removing libiconv from buildInputs was not enough: the nixpkgs Darwin stdenv injects -liconv regardless, so the arm64 binary still recorded the unused /nix/store libiconv dylib (the otool gate caught it). ccusage references no iconv symbols, so add -Wl,-dead_strip_dylibs to the Darwin link, which drops dylib load commands with no used symbols. The arm64 binary now links only /usr/lib/libSystem.B.dylib (verified), so the install-name rewrite stays gone. (Linux ships a fully static musl binary with no dynamic deps, so no equivalent is needed there.) * fix(nix): fall back to libiconv install_name_tool rewrite when dead_strip_dylibs doesn't strip it --------- Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
1 parent b1c60c4 commit 7bcafc9

2 files changed

Lines changed: 24 additions & 9 deletions

File tree

‎nix/darwin-x64-package.nix‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ in
6363
# End-user Intel Macs have no /nix/store, so fail the build if the
6464
# binary links anything outside the macOS system paths.
6565
postInstall = ''
66-
if otool -L $out/bin/ccusage | tail -n +2 | awk '{print $1}' | grep -Ev '^(/usr/lib/|/System/Library/)'; then
66+
for lib in $(otool -L "$out/bin/ccusage" | tail -n +2 | awk '{print $1}' | grep -E '^/nix/store/[^/]+-libiconv-'); do
67+
install_name_tool -change "$lib" /usr/lib/libiconv.2.dylib "$out/bin/ccusage"
68+
done
69+
if otool -L "$out/bin/ccusage" | tail -n +2 | awk '{print $1}' | grep -Ev '^(/usr/lib/|/System/Library/)'; then
6770
echo "error: ccusage-darwin-x64 links dylibs that do not exist on end-user machines" >&2
6871
exit 1
6972
fi

‎package.nix‎

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
root ? ./.,
88
stdenv,
99
apple-sdk_15,
10-
libiconv,
1110
}:
1211
let
1312
inherit ((builtins.fromJSON (builtins.readFile (root + /package.json)))) version;
@@ -28,14 +27,20 @@ let
2827
doCheck = false;
2928
cargoExtraArgs = "-p ccusage --bin ccusage";
3029
CCUSAGE_PRICING_JSON_PATH = "${inputs.litellm}/model_prices_and_context_window.json";
31-
RUSTFLAGS = lib.optionalString stdenv.isLinux "-C link-arg=-fuse-ld=mold";
30+
RUSTFLAGS =
31+
lib.optionalString stdenv.isLinux "-C link-arg=-fuse-ld=mold"
32+
# The nixpkgs Darwin stdenv injects -liconv even though ccusage uses no
33+
# iconv symbols, recording an unused /nix/store libiconv dependency that
34+
# crashes non-Nix Macs (#1251). dead_strip_dylibs drops dylib load
35+
# commands with no referenced symbols, so the unused libiconv is removed
36+
# and the binary links only system dylibs.
37+
+ lib.optionalString stdenv.isDarwin "-C link-arg=-Wl,-dead_strip_dylibs";
3238
nativeBuildInputs = [
3339
pkg-config
3440
]
3541
++ lib.optionals stdenv.isLinux [ mold ];
3642
buildInputs = lib.optionals stdenv.isDarwin [
3743
apple-sdk_15
38-
libiconv
3944
];
4045
};
4146
# Keep the dependency artifact keyed only by inputs that affect Cargo deps.
@@ -50,11 +55,18 @@ craneLib.buildPackage (
5055
// {
5156
inherit cargoArtifacts;
5257
postInstall = lib.optionalString stdenv.isDarwin ''
53-
install_name_tool -change ${libiconv}/lib/libiconv.2.dylib /usr/lib/libiconv.2.dylib $out/bin/ccusage
54-
# End-user machines have no /nix/store, so any dylib outside the macOS
55-
# system paths would crash the published binary with a missing dynamic
56-
# library error. grep prints the offending entries when it matches.
57-
if otool -L $out/bin/ccusage | tail -n +2 | awk '{print $1}' | grep -Ev '^(/usr/lib/|/System/Library/)'; then
58+
# The nixpkgs Darwin stdenv cc-wrapper injects -liconv into the link even
59+
# when libiconv is absent from buildInputs. dead_strip_dylibs (set in
60+
# RUSTFLAGS) drops it locally, but in CI the cc-wrapper's -liconv may
61+
# arrive after the linker has resolved dead_strip_dylibs. Rewrite the
62+
# install name as a robust fallback so the safety gate below doesn't fail
63+
# on a dylib that carries no referenced symbols.
64+
for lib in $(otool -L "$out/bin/ccusage" | tail -n +2 | awk '{print $1}' | grep -E '^/nix/store/[^/]+-libiconv-'); do
65+
install_name_tool -change "$lib" /usr/lib/libiconv.2.dylib "$out/bin/ccusage"
66+
done
67+
# Every remaining dylib MUST be a macOS system path. grep prints the
68+
# offending entries when it matches — fail the build for any matches.
69+
if otool -L "$out/bin/ccusage" | tail -n +2 | awk '{print $1}' | grep -Ev '^(/usr/lib/|/System/Library/)'; then
5870
echo "error: ccusage links dylibs that do not exist on end-user machines" >&2
5971
exit 1
6072
fi

0 commit comments

Comments
 (0)