1{
2 lib,
3 stdenv,
4 icu,
5 zlib,
6 bzip2,
7 zstd,
8 xz,
9 python ? null,
10 fixDarwinDylibNames,
11 libiconv,
12 libxcrypt,
13 makePkgconfigItem,
14 copyPkgconfigItems,
15 boost-build,
16 fetchpatch,
17 which,
18 toolset ?
19 if stdenv.cc.isClang then
20 "clang"
21 else if stdenv.cc.isGNU then
22 "gcc"
23 else
24 null,
25 enableRelease ? true,
26 enableDebug ? false,
27 enableSingleThreaded ? false,
28 enableMultiThreaded ? true,
29 enableShared ? !(with stdenv.hostPlatform; isStatic || isMinGW), # problems for now
30 enableStatic ? !enableShared,
31 enablePython ? false,
32 enableNumpy ? false,
33 enableIcu ? stdenv.hostPlatform == stdenv.buildPlatform,
34 taggedLayout ? (
35 (enableRelease && enableDebug)
36 || (enableSingleThreaded && enableMultiThreaded)
37 || (enableShared && enableStatic)
38 ),
39 patches ? [ ],
40 boostBuildPatches ? [ ],
41 useMpi ? false,
42 mpi,
43 extraB2Args ? [ ],
44
45 # Attributes inherit from specific versions
46 version,
47 src,
48 ...
49}:
50
51# We must build at least one type of libraries
52assert enableShared || enableStatic;
53
54assert enableNumpy -> enablePython;
55
56let
57
58 variant = lib.concatStringsSep "," (
59 lib.optional enableRelease "release" ++ lib.optional enableDebug "debug"
60 );
61
62 threading = lib.concatStringsSep "," (
63 lib.optional enableSingleThreaded "single" ++ lib.optional enableMultiThreaded "multi"
64 );
65
66 link = lib.concatStringsSep "," (
67 lib.optional enableShared "shared" ++ lib.optional enableStatic "static"
68 );
69
70 runtime-link = if enableShared then "shared" else "static";
71
72 # To avoid library name collisions
73 layout = if taggedLayout then "tagged" else "system";
74
75 needUserConfig =
76 stdenv.hostPlatform != stdenv.buildPlatform
77 || useMpi
78 || (stdenv.hostPlatform.isDarwin && enableShared);
79
80 b2Args = lib.concatStringsSep " " (
81 [
82 "--includedir=$dev/include"
83 "--libdir=$out/lib"
84 "-j$NIX_BUILD_CORES"
85 "--layout=${layout}"
86 "variant=${variant}"
87 "threading=${threading}"
88 "link=${link}"
89 ]
90 ++ lib.optionals (lib.versionAtLeast version "1.85") [
91 (
92 # The stacktrace from exception feature causes memory leaks when built
93 # with libc++. For all other standard library implementations, i.e.
94 # libstdc++, we must acknowledge this or stacktrace refuses to compile.
95 # Issue upstream: https://github.com/boostorg/stacktrace/issues/163
96 if (stdenv.cc.libcxx != null) then
97 "boost.stacktrace.from_exception=off"
98 else
99 "define=BOOST_STACKTRACE_LIBCXX_RUNTIME_MAY_CAUSE_MEMORY_LEAK"
100 )
101 ]
102 # TODO: make this unconditional
103 ++
104 lib.optionals
105 (
106 stdenv.hostPlatform != stdenv.buildPlatform
107 ||
108 # required on mips; see 61d9f201baeef4c4bb91ad8a8f5f89b747e0dfe4
109 (stdenv.hostPlatform.isMips && lib.versionAtLeast version "1.79")
110 )
111 [
112 "address-model=${toString stdenv.hostPlatform.parsed.cpu.bits}"
113 "architecture=${
114 if stdenv.hostPlatform.isMips64 then
115 if lib.versionOlder version "1.78" then "mips1" else "mips"
116 else if stdenv.hostPlatform.isS390 then
117 "s390x"
118 else
119 toString stdenv.hostPlatform.parsed.cpu.family
120 }"
121 # env in host triplet for Mach-O is "macho", but boost binary format for Mach-O is "mach-o"
122 "binary-format=${
123 if stdenv.hostPlatform.isMacho then
124 "mach-o"
125 else
126 toString stdenv.hostPlatform.parsed.kernel.execFormat.name
127 }"
128 "target-os=${toString stdenv.hostPlatform.parsed.kernel.name}"
129
130 # adapted from table in boost manual
131 # https://www.boost.org/doc/libs/1_66_0/libs/context/doc/html/context/architectures.html
132 "abi=${
133 if stdenv.hostPlatform.parsed.cpu.family == "arm" then
134 "aapcs"
135 else if stdenv.hostPlatform.isWindows then
136 "ms"
137 else if stdenv.hostPlatform.isMips32 then
138 "o32"
139 else if stdenv.hostPlatform.isMips64n64 then
140 "n64"
141 else
142 "sysv"
143 }"
144 ]
145 ++ lib.optional (link != "static") "runtime-link=${runtime-link}"
146 ++ lib.optional (variant == "release") "debug-symbols=off"
147 ++ lib.optional (toolset != null) "toolset=${toolset}"
148 ++ lib.optional (!enablePython) "--without-python"
149 ++ lib.optional needUserConfig "--user-config=user-config.jam"
150 ++ lib.optional (stdenv.buildPlatform.isDarwin && stdenv.hostPlatform.isLinux) "pch=off"
151 ++ lib.optionals stdenv.hostPlatform.isMinGW [
152 "threadapi=win32"
153 ]
154 ++ extraB2Args
155 );
156
157in
158
159stdenv.mkDerivation {
160 pname = "boost";
161
162 inherit src version;
163
164 patchFlags = [ ];
165
166 patches =
167 patches
168 ++ lib.optional (
169 lib.versionOlder version "1.88" && stdenv.hostPlatform.isDarwin
170 ) ./darwin-no-system-python.patch
171 ++ lib.optional (lib.versionOlder version "1.88") ./cmake-paths-173.patch
172 ++ lib.optional (lib.versionAtLeast version "1.88") ./cmake-paths-188.patch
173 ++ lib.optional (version == "1.77.0") (fetchpatch {
174 url = "https://github.com/boostorg/math/commit/7d482f6ebc356e6ec455ccb5f51a23971bf6ce5b.patch";
175 relative = "include";
176 sha256 = "sha256-KlmIbixcds6GyKYt1fx5BxDIrU7msrgDdYo9Va/KJR4=";
177 })
178 # Fixes ABI detection
179 ++ lib.optional (version == "1.83.0") (fetchpatch {
180 url = "https://github.com/boostorg/context/commit/6fa6d5c50d120e69b2d8a1c0d2256ee933e94b3b.patch";
181 stripLen = 1;
182 extraPrefix = "libs/context/";
183 sha256 = "sha256-bCfLL7bD1Rn4Ie/P3X+nIcgTkbXdCX6FW7B9lHsmVW8=";
184 })
185 # This fixes another issue regarding ill-formed constant expressions, which is a default error
186 # in clang 16 and will be a hard error in clang 17.
187 ++ lib.optional (lib.versionOlder version "1.80") (fetchpatch {
188 url = "https://github.com/boostorg/log/commit/77f1e20bd69c2e7a9e25e6a9818ae6105f7d070c.patch";
189 relative = "include";
190 hash = "sha256-6qOiGJASm33XzwoxVZfKJd7sTlQ5yd+MMFQzegXm5RI=";
191 })
192 ++ lib.optionals (lib.versionOlder version "1.81") [
193 # libc++ 15 dropped support for `std::unary_function` and `std::binary_function` in C++17+.
194 # C++17 is the default for clang 16, but clang 15 is also affected in that language mode.
195 # This patch is for Boost 1.80, but it also applies to earlier versions.
196 (fetchpatch {
197 url = "https://www.boost.org/patches/1_80_0/0005-config-libcpp15.patch";
198 hash = "sha256-ULFMzKphv70unvPZ3o4vSP/01/xbSM9a2TlIV67eXDQ=";
199 })
200 # This fixes another ill-formed contant expressions issue flagged by clang 16.
201 (fetchpatch {
202 url = "https://github.com/boostorg/numeric_conversion/commit/50a1eae942effb0a9b90724323ef8f2a67e7984a.patch";
203 relative = "include";
204 hash = "sha256-dq4SVgxkPJSC7Fvr59VGnXkM4Lb09kYDaBksCHo9C0s=";
205 })
206 # This fixes an issue in Python 3.11 about Py_TPFLAGS_HAVE_GC
207 (fetchpatch {
208 name = "python311-compatibility.patch";
209 url = "https://github.com/boostorg/python/commit/a218babc8daee904a83f550fb66e5cb3f1cb3013.patch";
210 hash = "sha256-IHxLtJBx0xSy7QEr8FbCPofsjcPuSYzgtPwDlx1JM+4=";
211 stripLen = 1;
212 extraPrefix = "libs/python/";
213 })
214 ]
215
216 ++ lib.optional (
217 lib.versionAtLeast version "1.81" && lib.versionOlder version "1.88" && stdenv.cc.isClang
218 ) ./fix-clang-target.patch
219 ++ lib.optional (lib.versionAtLeast version "1.86" && lib.versionOlder version "1.87") [
220 # Backport fix for NumPy 2 support.
221 (fetchpatch {
222 name = "boost-numpy-2-compatibility.patch";
223 url = "https://github.com/boostorg/python/commit/0474de0f6cc9c6e7230aeb7164af2f7e4ccf74bf.patch";
224 stripLen = 1;
225 extraPrefix = "libs/python/";
226 hash = "sha256-0IHK55JSujYcwEVOuLkwOa/iPEkdAKQlwVWR42p/X2U=";
227 })
228 ]
229 ++ lib.optional (version == "1.87.0") [
230 # Fix operator<< for shared_ptr and intrusive_ptr
231 # https://github.com/boostorg/smart_ptr/issues/115
232 (fetchpatch {
233 url = "https://github.com/boostorg/smart_ptr/commit/e7433ba54596da97cb7859455cd37ca140305a9c.patch";
234 relative = "include";
235 hash = "sha256-9JvKQOAB19wQpWLNAhuB9eL8qKqXWTQHAJIXdLYMNG8=";
236 })
237 # Fixes ABI detection on some platforms (like loongarch64)
238 (fetchpatch {
239 url = "https://github.com/boostorg/context/commit/63996e427b4470c7b99b0f4cafb94839ea3670b6.patch";
240 stripLen = 1;
241 extraPrefix = "libs/context/";
242 hash = "sha256-Z8uw2+4IEybqVcU25i/0XJKS16hi/+3MXUxs53ghjL0=";
243 })
244 ];
245
246 meta = with lib; {
247 homepage = "http://boost.org/";
248 description = "Collection of C++ libraries";
249 license = licenses.boost;
250 platforms = platforms.unix ++ platforms.windows;
251 # boost-context lacks support for the N32 ABI on mips64. The build
252 # will succeed, but packages depending on boost-context will fail with
253 # a very cryptic error message.
254 badPlatforms = [ lib.systems.inspect.patterns.isMips64n32 ];
255 broken =
256 enableNumpy && lib.versionOlder version "1.86" && lib.versionAtLeast python.pkgs.numpy.version "2";
257 };
258
259 passthru = {
260 inherit boostBuildPatches;
261 };
262
263 preConfigure =
264 lib.optionalString useMpi ''
265 cat << EOF >> user-config.jam
266 using mpi : ${lib.getDev mpi}/bin/mpiCC ;
267 EOF
268 ''
269 # On darwin we need to add the `$out/lib` to the libraries' rpath explicitly,
270 # otherwise the dynamic linker is unable to resolve the reference to @rpath
271 # when the boost libraries want to load each other at runtime.
272 + lib.optionalString (stdenv.hostPlatform.isDarwin && enableShared) ''
273 cat << EOF >> user-config.jam
274 using clang-darwin : : ${stdenv.cc.targetPrefix}c++
275 : <linkflags>"-rpath $out/lib/"
276 <archiver>$AR
277 <ranlib>$RANLIB
278 ;
279 EOF
280 ''
281 # b2 has trouble finding the correct compiler and tools for cross compilation
282 # since it apparently ignores $CC, $AR etc. Thus we need to set everything
283 # in user-config.jam. To keep things simple we just set everything in an
284 # uniform way for clang and gcc (which works thanks to our cc-wrapper).
285 # We pass toolset later which will make b2 invoke everything in the right
286 # way -- the other toolset in user-config.jam will be ignored.
287 + lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) ''
288 cat << EOF >> user-config.jam
289 using gcc : cross : ${stdenv.cc.targetPrefix}c++
290 : <archiver>$AR
291 <ranlib>$RANLIB
292 ;
293
294 using clang : cross : ${stdenv.cc.targetPrefix}c++
295 : <archiver>$AR
296 <ranlib>$RANLIB
297 ;
298 EOF
299 ''
300 # b2 needs to be explicitly told how to find Python when cross-compiling
301 + lib.optionalString enablePython ''
302 cat << EOF >> user-config.jam
303 using python : : ${python.pythonOnBuildForHost.interpreter}
304 : ${python}/include/python${python.pythonVersion}
305 : ${python}/lib
306 ;
307 EOF
308 '';
309
310 # Fix compilation to 32-bit ARM with clang in downstream packages
311 # https://github.com/ned14/outcome/pull/308
312 # https://github.com/boostorg/json/pull/1064
313 postPatch = lib.optionalString (version == "1.87.0") ''
314 substituteInPlace \
315 boost/outcome/outcome_gdb.h \
316 boost/outcome/experimental/status-code/status_code.hpp \
317 boost/json/detail/gdb_printers.hpp \
318 boost/unordered/unordered_printers.hpp \
319 boost/interprocess/interprocess_printers.hpp \
320 libs/json/pretty_printers/generate-gdb-header.py \
321 --replace-fail ",@progbits,1" ",%progbits,1"
322 '';
323
324 env = {
325 NIX_CFLAGS_LINK = lib.optionalString stdenv.hostPlatform.isDarwin "-headerpad_max_install_names";
326 # copyPkgconfigItems will substitute these in the pkg-config file
327 includedir = "${placeholder "dev"}/include";
328 libdir = "${placeholder "out"}/lib";
329 };
330
331 pkgconfigItems = [
332 (makePkgconfigItem {
333 name = "boost";
334 inherit version;
335 # Exclude other variables not needed by meson
336 variables = {
337 includedir = "@includedir@";
338 libdir = "@libdir@";
339 };
340 })
341 ];
342
343 enableParallelBuilding = true;
344
345 nativeBuildInputs = [
346 which
347 boost-build
348 copyPkgconfigItems
349 ]
350 ++ lib.optional stdenv.hostPlatform.isDarwin fixDarwinDylibNames;
351 buildInputs = [
352 zlib
353 bzip2
354 libiconv
355 ]
356 ++ lib.optional (lib.versionAtLeast version "1.69") zstd
357 ++ [ xz ]
358 ++ lib.optional enableIcu icu
359 ++ lib.optionals enablePython [
360 libxcrypt
361 python
362 ]
363 ++ lib.optional enableNumpy python.pkgs.numpy;
364
365 configureScript = "./bootstrap.sh";
366 configurePlatforms = [ ];
367 dontDisableStatic = true;
368 dontAddStaticConfigureFlags = true;
369 configureFlags = [
370 "--includedir=$(dev)/include"
371 "--libdir=$(out)/lib"
372 "--with-bjam=b2" # prevent bootstrapping b2 in configurePhase
373 ]
374 ++ lib.optional (toolset != null) "--with-toolset=${toolset}"
375 ++ [ (if enableIcu then "--with-icu=${icu.dev}" else "--without-icu") ];
376
377 buildPhase = ''
378 runHook preBuild
379 b2 ${b2Args}
380 runHook postBuild
381 '';
382
383 installPhase = ''
384 runHook preInstall
385
386 # boostbook is needed by some applications
387 mkdir -p $dev/share/boostbook
388 cp -a tools/boostbook/{xsl,dtd} $dev/share/boostbook/
389
390 # Let boost install everything else
391 b2 ${b2Args} install
392
393 runHook postInstall
394 '';
395
396 postFixup = lib.optionalString stdenv.hostPlatform.isMinGW ''
397 $RANLIB "$out/lib/"*.a
398 '';
399
400 outputs = [
401 "out"
402 "dev"
403 ];
404 setOutputFlags = false;
405}