Skip to content

Commit 645df53

Browse files
daniel-nolandclaude
andcommitted
build(frr): skip the libgccjit build on x86_64 glibc
`fancy.libatomic` is one file copied out of a full libgccjit build: gcc from source, the longest step in an image build. No FRR object on x86_64 glibc references libatomic (every atomic is inlined), yet FRR linked it, named it in its buildInputs and kept it through nuke-refs, so gcc was built anyway. Worse, `fancy.libxcrypt` is overridden per sanitizer, which gives libgccjit a new hash in every sanitizer flavour: an ASan or TSan build rebuilds gcc. Stop linking libatomic on x86_64 glibc and pass it to FRR only where it is linked. That takes two cuts: our own -latomic in LDFLAGS, and the -latomic configure appends to LIBS when the build toolchain has one (which would otherwise leave a DT_NEEDED nothing in the closure provides). `--as-needed` cannot do this for us: libtool hoists the `-l` flags of a shared-library link ahead of every `-Wl,` flag. A postInstall check fails the build if any output still names libatomic. aarch64 and musl are unchanged. The x86_64 glibc FRR build graph (default, release and ASan) loses libgccjit and libatomic entirely. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Daniel Noland <daniel@githedgehog.com>
1 parent 655ddd8 commit 645df53

2 files changed

Lines changed: 40 additions & 10 deletions

File tree

‎nix/overlays/frr.nix‎

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
}:
1111
final: prev:
1212
let
13+
# No FRR object references libatomic on x86_64 glibc; unverified on aarch64 and musl, which
14+
# keep linking it.
15+
drop-libatomic = final.stdenv.hostPlatform.isx86_64 && libc == "gnu";
1316
dep =
1417
pkg:
1518
(pkg.override { stdenv = final.stdenv'; }).overrideAttrs (orig: {
@@ -36,6 +39,9 @@ let
3639
// {
3740
stdenv = final.stdenv';
3841
inherit frrSrc vtysh-extensions;
42+
# `fancy.libatomic` is copied out of a full libgccjit (gcc) build; do not ask for it
43+
# where FRR does not link libatomic.
44+
libatomic = if drop-libatomic then null else final.fancy.libatomic;
3945
}
4046
)).overrideAttrs
4147
(orig: {
@@ -63,8 +69,14 @@ let
6369
# backs the cross-musl clang stdenv (note: stdenv, not
6470
# stdenv' -- the prime is the clang stdenv whose cc.cc is
6571
# clang and contains no libatomic at all).
72+
#
73+
# On x86_64 glibc no FRR object references libatomic at all (every atomic is inlined),
74+
# so it is not linked there. `--as-needed` cannot do this for us: libtool hoists the
75+
# `-l` flags of a shared-library link ahead of every `-Wl,` flag.
6676
+ (
67-
if libc == "musl" then
77+
if drop-libatomic then
78+
""
79+
else if libc == "musl" then
6880
" -L${final.stdenv.cc.cc.lib}/${final.stdenv.hostPlatform.config}/lib -latomic "
6981
else if libc == "gnu" then
7082
" -L${final.fancy.libatomic}/lib -latomic "
@@ -83,6 +95,22 @@ let
8395
# this overrides the base package's --enable-static-bin.
8496
"--disable-static-bin"
8597
];
98+
# Where configure finds a libatomic (the build toolchain has one), it appends -latomic to
99+
# LIBS, which ends every link and would leave a DT_NEEDED nothing in the closure provides.
100+
postConfigure =
101+
(orig.postConfigure or "")
102+
+ final.lib.optionalString drop-libatomic ''
103+
sed -E -i '/^LIBS = /s/ -latomic\b//g' Makefile
104+
grep -E '^LIBS = ' Makefile
105+
'';
106+
postInstall =
107+
(orig.postInstall or "")
108+
+ final.lib.optionalString drop-libatomic ''
109+
if grep -rl 'libatomic\.so' "$out"; then
110+
echo "FRR still needs libatomic, which is not in its closure" >&2
111+
exit 1
112+
fi
113+
'';
86114
# `buildPackages.nukeReferences` rather than `prev.nukeReferences`:
87115
# the `nuke-refs` script substitutes a perl path at build time, and
88116
# under a cross pkgset `prev.nukeReferences` picks up target-arch
@@ -104,7 +132,7 @@ let
104132
-e ${final.fancy.readline} \
105133
-e ${final.fancy.libxcrypt} \
106134
-e ${final.fancy.json_c} \
107-
${if libc == "gnu" then "-e ${final.fancy.libatomic}" else ""} \
135+
${if libc == "gnu" && !drop-libatomic then "-e ${final.fancy.libatomic}" else ""} \
108136
${if libc == "musl" then "-e ${final.stdenv.cc.cc.lib}" else ""} \
109137
'{}' +;
110138
'';

‎nix/pkgs/frr/default.nix‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
pcre2,
2525
readline,
2626
rtrlib,
27-
libatomic,
27+
# null where FRR does not link libatomic at all (see `drop-libatomic` in nix/overlays/frr.nix)
28+
libatomic ? null,
2829

2930
# other general options besides snmp support
3031
numMultipath ? 8,
@@ -127,13 +128,14 @@ stdenv.mkDerivation (finalAttrs: {
127128
python3Minimal
128129
readline
129130
]
130-
# libatomic.so.1 is a DT_NEEDED of libfrr.so and of every daemon. On glibc
131-
# it comes from `fancy.libatomic`, a re-export of the single file FRR needs
132-
# out of libgccjit (see the note on that attribute in nix/overlays/frr.nix).
133-
# On musl FRR pulls libatomic from the cross-musl gcc-libs output via
134-
# `stdenv.cc.cc.lib` in the overlay instead, so naming it here would only
135-
# bloat the build closure without contributing any symbol.
136-
++ lib.optionals stdenv.hostPlatform.isGnu [ libatomic ]
131+
# Where FRR links libatomic, libatomic.so.1 is a DT_NEEDED of libfrr.so and of
132+
# every daemon. On glibc it comes from `fancy.libatomic`, a re-export of the
133+
# single file FRR needs out of libgccjit (see the note on that attribute in
134+
# nix/overlays/frr.nix). On musl FRR pulls libatomic from the cross-musl
135+
# gcc-libs output via `stdenv.cc.cc.lib` in the overlay instead, so naming it
136+
# here would only bloat the build closure without contributing any symbol.
137+
# On x86_64 glibc it is not linked at all, and naming it would still build gcc.
138+
++ lib.optionals (stdenv.hostPlatform.isGnu && libatomic != null) [ libatomic ]
137139
++ lib.optionals bgpRpki [ rtrlib ];
138140

139141
# cross-compiling: clippy is compiled with the build host toolchain, split it out to ease

0 commit comments

Comments
 (0)