1let
2 withGold = platform: platform.parsed.kernel.execFormat.name == "elf" && !platform.isRiscV && !platform.isLoongArch64;
3in
4
5{ stdenv
6, autoreconfHook
7, autoconf269, automake, libtool
8, bison
9, buildPackages
10, fetchFromGitHub
11, fetchurl
12, flex
13, gettext
14, lib
15, noSysDirs
16, perl
17, substitute
18, zlib
19
20, enableGold ? withGold stdenv.targetPlatform
21, enableGoldDefault ? false
22, enableShared ? !stdenv.hostPlatform.isStatic
23 # WARN: Enabling all targets increases output size to a multiple.
24, withAllTargets ? false
25}:
26
27# WARN: configure silently disables ld.gold if it's unsupported, so we need to
28# make sure that intent matches result ourselves.
29assert enableGold -> withGold stdenv.targetPlatform;
30assert enableGoldDefault -> enableGold;
31
32
33let
34 inherit (stdenv) buildPlatform hostPlatform targetPlatform;
35
36 version = "2.40";
37
38 srcs = {
39 normal = fetchurl {
40 url = "mirror://gnu/binutils/binutils-${version}.tar.bz2";
41 hash = "sha256-+CmOsVOks30RLpRapcsoUAQLzyaj6mW1pxXIOv4F5Io=";
42 };
43 vc4-none = fetchFromGitHub {
44 owner = "itszor";
45 repo = "binutils-vc4";
46 rev = "708acc851880dbeda1dd18aca4fd0a95b2573b36";
47 sha256 = "1kdrz6fki55lm15rwwamn74fnqpy0zlafsida2zymk76n3656c63";
48 };
49 };
50
51 #INFO: The targetPrefix prepended to binary names to allow multiple binuntils
52 # on the PATH to both be usable.
53 targetPrefix = lib.optionalString (targetPlatform != hostPlatform) "${targetPlatform.config}-";
54in
55
56stdenv.mkDerivation (finalAttrs: {
57 pname = targetPrefix + "binutils";
58 inherit version;
59
60 # HACK: Ensure that we preserve source from bootstrap binutils to not rebuild LLVM
61 src = stdenv.__bootPackages.binutils-unwrapped.src
62 or srcs.${targetPlatform.system}
63 or srcs.normal;
64
65 # WARN: this package is used for bootstrapping fetchurl, and thus cannot use
66 # fetchpatch! All mutable patches (generated by GitHub or cgit) that are
67 # needed here should be included directly in Nixpkgs as files.
68 patches = [
69 # Make binutils output deterministic by default.
70 ./deterministic.patch
71
72
73 # Breaks nm BSD flag detection, heeds an upstream fix:
74 # https://sourceware.org/PR29547
75 ./0001-Revert-libtool.m4-fix-the-NM-nm-over-here-B-option-w.patch
76 ./0001-Revert-libtool.m4-fix-nm-BSD-flag-detection.patch
77
78 # Required for newer macos versions
79 ./0001-libtool.m4-update-macos-version-detection-block.patch
80
81 # For some reason bfd ld doesn't search DT_RPATH when cross-compiling. It's
82 # not clear why this behavior was decided upon but it has the unfortunate
83 # consequence that the linker will fail to find transitive dependencies of
84 # shared objects when cross-compiling. Consequently, we are forced to
85 # override this behavior, forcing ld to search DT_RPATH even when
86 # cross-compiling.
87 ./always-search-rpath.patch
88
89 # Avoid `lib -> out -> lib` reference. Normally `bfd-plugins` does
90 # not need to know binutils' BINDIR at all. It's an absolute path
91 # where libraries are stored.
92 ./plugins-no-BINDIR.patch
93
94 # CVE-2023-1972 fix to bfd/elf.c from:
95 # https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=c22d38baefc5a7a1e1f5cdc9dbb556b1f0ec5c57
96 ./CVE-2023-1972.patch
97 ]
98 ++ lib.optional targetPlatform.isiOS ./support-ios.patch
99 # Adds AVR-specific options to "size" for compatibility with Atmel's downstream distribution
100 # Patch from arch-community
101 # https://github.com/archlinux/svntogit-community/blob/c8d53dd1734df7ab15931f7fad0c9acb8386904c/trunk/avr-size.patch
102 ++ lib.optional targetPlatform.isAvr ./avr-size.patch
103 ++ lib.optional stdenv.targetPlatform.isWindows ./windres-locate-gcc.patch
104 ++ lib.optional stdenv.targetPlatform.isMips64n64
105 # this patch is from debian:
106 # https://sources.debian.org/data/main/b/binutils/2.38-3/debian/patches/mips64-default-n64.diff
107 (if stdenv.targetPlatform.isMusl
108 then substitute { src = ./mips64-default-n64.patch; replacements = [ "--replace" "gnuabi64" "muslabi64" ]; }
109 else ./mips64-default-n64.patch)
110 # This patch fixes a bug in 2.40 on MinGW, which breaks DXVK when cross-building from Darwin.
111 # See https://sourceware.org/bugzilla/show_bug.cgi?id=30079
112 ++ lib.optional stdenv.targetPlatform.isMinGW ./mingw-abort-fix.patch
113 ;
114
115 outputs = [ "out" "info" "man" "dev" ]
116 # Ideally we would like to always install 'lib' into a separate
117 # target. Unfortunately cross-compiled binutils installs libraries
118 # across both `$lib/lib/` and `$out/$target/lib` with a reference
119 # from $out to $lib. Probably a binutils bug: all libraries should go
120 # to $lib as binutils does not build target libraries. Let's make our
121 # life slightly simpler by installing everything into $out for
122 # cross-binutils.
123 ++ lib.optionals (targetPlatform == hostPlatform) [ "lib" ];
124
125 strictDeps = true;
126 depsBuildBuild = [ buildPackages.stdenv.cc ];
127 # texinfo was removed here in https://github.com/NixOS/nixpkgs/pull/210132
128 # to reduce rebuilds during stdenv bootstrap. Please don't add it back without
129 # checking the impact there first.
130 nativeBuildInputs = [
131 bison
132 perl
133 ]
134 ++ lib.optionals targetPlatform.isiOS [ autoreconfHook ]
135 ++ lib.optionals buildPlatform.isDarwin [ autoconf269 automake gettext libtool ]
136 ++ lib.optionals targetPlatform.isVc4 [ flex ]
137 ;
138
139 buildInputs = [ zlib gettext ];
140
141 inherit noSysDirs;
142
143 preConfigure = (lib.optionalString buildPlatform.isDarwin ''
144 for i in */configure.ac; do
145 pushd "$(dirname "$i")"
146 echo "Running autoreconf in $PWD"
147 # autoreconf doesn't work, don't know why
148 # autoreconf ''${autoreconfFlags:---install --force --verbose}
149 autoconf
150 popd
151 done
152 '') + ''
153 # Clear the default library search path.
154 if test "$noSysDirs" = "1"; then
155 echo 'NATIVE_LIB_DIRS=' >> ld/configure.tgt
156 fi
157
158 # Use symlinks instead of hard links to save space ("strip" in the
159 # fixup phase strips each hard link separately).
160 for i in binutils/Makefile.in gas/Makefile.in ld/Makefile.in gold/Makefile.in; do
161 sed -i "$i" -e 's|ln |ln -s |'
162 done
163
164 # autoreconfHook is not included for all targets.
165 # Call it here explicitly as well.
166 ${finalAttrs.postAutoreconf}
167 '';
168
169 postAutoreconf = ''
170 # As we regenerated configure build system tries hard to use
171 # texinfo to regenerate manuals. Let's avoid the dependency
172 # on texinfo in bootstrap path and keep manuals unmodified.
173 touch gas/doc/.dirstamp
174 touch gas/doc/asconfig.texi
175 touch gas/doc/as.1
176 touch gas/doc/as.info
177 '';
178
179 # As binutils takes part in the stdenv building, we don't want references
180 # to the bootstrap-tools libgcc (as uses to happen on arm/mips)
181 env.NIX_CFLAGS_COMPILE =
182 if hostPlatform.isDarwin
183 then "-Wno-string-plus-int -Wno-deprecated-declarations"
184 else "-static-libgcc";
185
186 hardeningDisable = [ "format" "pie" ];
187
188 configurePlatforms = [ "build" "host" "target" ];
189
190 configureFlags = [
191 "--enable-64-bit-bfd"
192 "--with-system-zlib"
193
194 "--enable-deterministic-archives"
195 "--disable-werror"
196 "--enable-fix-loongson2f-nop"
197
198 # Turn on --enable-new-dtags by default to make the linker set
199 # RUNPATH instead of RPATH on binaries. This is important because
200 # RUNPATH can be overridden using LD_LIBRARY_PATH at runtime.
201 "--enable-new-dtags"
202
203 # force target prefix. Some versions of binutils will make it empty if
204 # `--host` and `--target` are too close, even if Nixpkgs thinks the
205 # platforms are different (e.g. because not all the info makes the
206 # `config`). Other versions of binutils will always prefix if `--target` is
207 # passed, even if `--host` and `--target` are the same. The easiest thing
208 # for us to do is not leave it to chance, and force the program prefix to be
209 # what we want it to be.
210 "--program-prefix=${targetPrefix}"
211
212 # Unconditionally disable:
213 # - musl target needs porting: https://sourceware.org/PR29477
214 "--disable-gprofng"
215
216 # By default binutils searches $libdir for libraries. This brings in
217 # libbfd and libopcodes into a default visibility. Drop default lib
218 # path to force users to declare their use of these libraries.
219 "--with-lib-path=:"
220 ]
221 ++ lib.optionals withAllTargets [ "--enable-targets=all" ]
222 ++ lib.optionals enableGold [
223 "--enable-gold${lib.optionalString enableGoldDefault "=default"}"
224 "--enable-plugins"
225 ] ++ (if enableShared
226 then [ "--enable-shared" "--disable-static" ]
227 else [ "--disable-shared" "--enable-static" ])
228 ;
229
230 # Fails
231 doCheck = false;
232
233 # Break dependency on pkgsBuildBuild.gcc when building a cross-binutils
234 stripDebugList = if stdenv.hostPlatform != stdenv.targetPlatform then "bin lib ${stdenv.hostPlatform.config}" else null;
235
236 # INFO: Otherwise it fails with:
237 # `./sanity.sh: line 36: $out/bin/size: not found`
238 doInstallCheck = (buildPlatform == hostPlatform) && (hostPlatform == targetPlatform);
239
240 enableParallelBuilding = true;
241
242 # For the same reason we don't split "lib" output we undo the $target/
243 # prefix for installed headers and libraries we link:
244 # $out/$host/$target/lib/* to $out/lib/
245 # $out/$host/$target/include/* to $dev/include/*
246 # TODO(trofi): fix installation paths upstream so we could remove this
247 # code and have "lib" output unconditionally.
248 postInstall = lib.optionalString (hostPlatform.config != targetPlatform.config) ''
249 ln -s $out/${hostPlatform.config}/${targetPlatform.config}/lib/* $out/lib/
250 ln -s $out/${hostPlatform.config}/${targetPlatform.config}/include/* $dev/include/
251 '';
252
253 passthru = {
254 inherit targetPrefix;
255 hasGold = enableGold;
256 isGNU = true;
257 # Having --enable-plugins is not enough, system has to support
258 # dlopen() or equivalent. See config/plugins.m4 and configure.ac
259 # (around PLUGINS) for cases that support or not support plugins.
260 # No platform specific filters yet here.
261 hasPluginAPI = enableGold;
262 };
263
264 meta = with lib; {
265 description = "Tools for manipulating binaries (linker, assembler, etc.)";
266 longDescription = ''
267 The GNU Binutils are a collection of binary tools. The main
268 ones are `ld' (the GNU linker) and `as' (the GNU assembler).
269 They also include the BFD (Binary File Descriptor) library,
270 `gprof', `nm', `strip', etc.
271 '';
272 homepage = "https://www.gnu.org/software/binutils/";
273 license = licenses.gpl3Plus;
274 maintainers = with maintainers; [ ericson2314 lovesegfault ];
275 platforms = platforms.unix;
276
277 # INFO: Give binutils a lower priority than gcc-wrapper to prevent a
278 # collision due to the ld/as wrappers/symlinks in the latter.
279 priority = 10;
280 };
281})