1{ lib, stdenv, icu, expat, zlib, bzip2, zstd, xz, python ? null, fixDarwinDylibNames, libiconv, libxcrypt
2, boost-build
3, fetchpatch
4, which
5, toolset ? /**/ if stdenv.cc.isClang then "clang"
6 else if stdenv.cc.isGNU then "gcc"
7 else null
8, enableRelease ? true
9, enableDebug ? false
10, enableSingleThreaded ? false
11, enableMultiThreaded ? true
12, enableShared ? !(with stdenv.hostPlatform; isStatic || libc == "msvcrt") # problems for now
13, enableStatic ? !enableShared
14, enablePython ? false
15, enableNumpy ? false
16, enableIcu ? stdenv.hostPlatform == stdenv.buildPlatform
17, taggedLayout ? ((enableRelease && enableDebug) || (enableSingleThreaded && enableMultiThreaded) || (enableShared && enableStatic))
18, patches ? []
19, boostBuildPatches ? []
20, useMpi ? false
21, mpi
22, extraB2Args ? []
23
24# Attributes inherit from specific versions
25, version, src
26, ...
27}:
28
29# We must build at least one type of libraries
30assert enableShared || enableStatic;
31
32assert enableNumpy -> enablePython;
33
34# Boost <1.69 can't be built on linux with clang >8, because pth was removed
35assert with lib; (stdenv.isLinux && toolset == "clang" && versionAtLeast stdenv.cc.version "8.0.0") -> versionAtLeast version "1.69";
36
37let
38
39 variant = lib.concatStringsSep ","
40 (lib.optional enableRelease "release" ++
41 lib.optional enableDebug "debug");
42
43 threading = lib.concatStringsSep ","
44 (lib.optional enableSingleThreaded "single" ++
45 lib.optional enableMultiThreaded "multi");
46
47 link = lib.concatStringsSep ","
48 (lib.optional enableShared "shared" ++
49 lib.optional enableStatic "static");
50
51 runtime-link = if enableShared then "shared" else "static";
52
53 # To avoid library name collisions
54 layout = if taggedLayout then "tagged" else "system";
55
56 needUserConfig = stdenv.hostPlatform != stdenv.buildPlatform || useMpi || (stdenv.isDarwin && enableShared);
57
58 b2Args = lib.concatStringsSep " " ([
59 "--includedir=$dev/include"
60 "--libdir=$out/lib"
61 "-j$NIX_BUILD_CORES"
62 "--layout=${layout}"
63 "variant=${variant}"
64 "threading=${threading}"
65 "link=${link}"
66 "-sEXPAT_INCLUDE=${expat.dev}/include"
67 "-sEXPAT_LIBPATH=${expat.out}/lib"
68
69 # TODO: make this unconditional
70 ] ++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform ||
71 # required on mips; see 61d9f201baeef4c4bb91ad8a8f5f89b747e0dfe4
72 (stdenv.hostPlatform.isMips && lib.versionAtLeast version "1.79")) [
73 "address-model=${toString stdenv.hostPlatform.parsed.cpu.bits}"
74 "architecture=${if stdenv.hostPlatform.isMips64
75 then if lib.versionOlder version "1.78" then "mips1" else "mips"
76 else if stdenv.hostPlatform.parsed.cpu.name == "s390x" then "s390x"
77 else toString stdenv.hostPlatform.parsed.cpu.family}"
78 "binary-format=${toString stdenv.hostPlatform.parsed.kernel.execFormat.name}"
79 "target-os=${toString stdenv.hostPlatform.parsed.kernel.name}"
80
81 # adapted from table in boost manual
82 # https://www.boost.org/doc/libs/1_66_0/libs/context/doc/html/context/architectures.html
83 "abi=${if stdenv.hostPlatform.parsed.cpu.family == "arm" then "aapcs"
84 else if stdenv.hostPlatform.isWindows then "ms"
85 else if stdenv.hostPlatform.isMips32 then "o32"
86 else if stdenv.hostPlatform.isMips64n64 then "n64"
87 else "sysv"}"
88 ] ++ lib.optional (link != "static") "runtime-link=${runtime-link}"
89 ++ lib.optional (variant == "release") "debug-symbols=off"
90 ++ lib.optional (toolset != null) "toolset=${toolset}"
91 ++ lib.optional (!enablePython) "--without-python"
92 ++ lib.optional needUserConfig "--user-config=user-config.jam"
93 ++ lib.optional (stdenv.buildPlatform.isDarwin && stdenv.hostPlatform.isLinux) "pch=off"
94 ++ lib.optionals (stdenv.hostPlatform.libc == "msvcrt") [
95 "threadapi=win32"
96 ] ++ extraB2Args
97 );
98
99in
100
101stdenv.mkDerivation {
102 pname = "boost";
103
104 inherit src version;
105
106 patchFlags = [];
107
108 patches = patches
109 ++ lib.optional stdenv.isDarwin ./darwin-no-system-python.patch
110 # Fix boost-context segmentation faults on ppc64 due to ABI violation
111 ++ lib.optional (lib.versionOlder version "1.71") (fetchpatch {
112 url = "https://github.com/boostorg/context/commit/2354eca9b776a6739112833f64754108cc0d1dc5.patch";
113 sha256 = "067m4bjpmcanqvg28djax9a10avmdwhlpfx6gn73kbqqq70dnz29";
114 stripLen = 1;
115 extraPrefix = "libs/context/";
116 })
117 ++ lib.optional (lib.versionOlder version "1.70") (fetchpatch {
118 # support for Mips64n64 appeared in boost-context 1.70
119 url = "https://github.com/boostorg/context/commit/e3f744a1862164062d579d1972272d67bdaa9c39.patch";
120 sha256 = "sha256-qjQy1b4jDsIRrI+UYtcguhvChrMbGWO0UlEzEJHYzRI=";
121 stripLen = 1;
122 extraPrefix = "libs/context/";
123 })
124 ++ lib.optional (lib.versionAtLeast version "1.70" && lib.versionOlder version "1.73") ./cmake-paths.patch
125 ++ lib.optional (lib.versionAtLeast version "1.73") ./cmake-paths-173.patch
126 ++ lib.optional (version == "1.77.0") (fetchpatch {
127 url = "https://github.com/boostorg/math/commit/7d482f6ebc356e6ec455ccb5f51a23971bf6ce5b.patch";
128 relative = "include";
129 sha256 = "sha256-KlmIbixcds6GyKYt1fx5BxDIrU7msrgDdYo9Va/KJR4=";
130 });
131
132 meta = with lib; {
133 homepage = "http://boost.org/";
134 description = "Collection of C++ libraries";
135 license = licenses.boost;
136 platforms = platforms.unix ++ platforms.windows;
137 badPlatforms = optionals (versionOlder version "1.73") platforms.riscv;
138 maintainers = with maintainers; [ hjones2199 ];
139
140 broken =
141 # boost-context lacks support for the N32 ABI on mips64. The build
142 # will succeed, but packages depending on boost-context will fail with
143 # a very cryptic error message.
144 stdenv.hostPlatform.isMips64n32;
145 };
146
147 passthru = {
148 inherit boostBuildPatches;
149 };
150
151 preConfigure = lib.optionalString useMpi ''
152 cat << EOF >> user-config.jam
153 using mpi : ${mpi}/bin/mpiCC ;
154 EOF
155 ''
156 # On darwin we need to add the `$out/lib` to the libraries' rpath explicitly,
157 # otherwise the dynamic linker is unable to resolve the reference to @rpath
158 # when the boost libraries want to load each other at runtime.
159 + lib.optionalString (stdenv.isDarwin && enableShared) ''
160 cat << EOF >> user-config.jam
161 using clang-darwin : : ${stdenv.cc.targetPrefix}c++
162 : <linkflags>"-rpath $out/lib/"
163 ;
164 EOF
165 ''
166 # b2 has trouble finding the correct compiler and tools for cross compilation
167 # since it apparently ignores $CC, $AR etc. Thus we need to set everything
168 # in user-config.jam. To keep things simple we just set everything in an
169 # uniform way for clang and gcc (which works thanks to our cc-wrapper).
170 # We pass toolset later which will make b2 invoke everything in the right
171 # way -- the other toolset in user-config.jam will be ignored.
172 + lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) ''
173 cat << EOF >> user-config.jam
174 using gcc : cross : ${stdenv.cc.targetPrefix}c++
175 : <archiver>$AR
176 <ranlib>$RANLIB
177 ;
178
179 using clang : cross : ${stdenv.cc.targetPrefix}c++
180 : <archiver>$AR
181 <ranlib>$RANLIB
182 ;
183 EOF
184 ''
185 # b2 needs to be explicitly told how to find Python when cross-compiling
186 + lib.optionalString enablePython ''
187 cat << EOF >> user-config.jam
188 using python : : ${python.interpreter}
189 : ${python}/include/python${python.pythonVersion}
190 : ${python}/lib
191 ;
192 EOF
193 '';
194
195 NIX_CFLAGS_LINK = lib.optionalString stdenv.isDarwin
196 "-headerpad_max_install_names";
197
198 enableParallelBuilding = true;
199
200 nativeBuildInputs = [ which boost-build ]
201 ++ lib.optional stdenv.hostPlatform.isDarwin fixDarwinDylibNames;
202 buildInputs = [ expat zlib bzip2 libiconv ]
203 ++ lib.optional (lib.versionAtLeast version "1.69") zstd
204 ++ [ xz ]
205 ++ lib.optional enableIcu icu
206 ++ lib.optionals enablePython [ libxcrypt python ]
207 ++ lib.optional enableNumpy python.pkgs.numpy;
208
209 configureScript = "./bootstrap.sh";
210 configurePlatforms = [];
211 dontDisableStatic = true;
212 dontAddStaticConfigureFlags = true;
213 configureFlags = [
214 "--includedir=$(dev)/include"
215 "--libdir=$(out)/lib"
216 "--with-bjam=b2" # prevent bootstrapping b2 in configurePhase
217 ] ++ lib.optional (toolset != null) "--with-toolset=${toolset}"
218 ++ [ (if enableIcu then "--with-icu=${icu.dev}" else "--without-icu") ];
219
220 buildPhase = ''
221 runHook preBuild
222 b2 ${b2Args}
223 runHook postBuild
224 '';
225
226 installPhase = ''
227 runHook preInstall
228
229 # boostbook is needed by some applications
230 mkdir -p $dev/share/boostbook
231 cp -a tools/boostbook/{xsl,dtd} $dev/share/boostbook/
232
233 # Let boost install everything else
234 b2 ${b2Args} install
235
236 runHook postInstall
237 '';
238
239 postFixup = ''
240 # Make boost header paths relative so that they are not runtime dependencies
241 cd "$dev" && find include \( -name '*.hpp' -or -name '*.h' -or -name '*.ipp' \) \
242 -exec sed '1s/^\xef\xbb\xbf//;1i#line 1 "{}"' -i '{}' \;
243 '' + lib.optionalString (stdenv.hostPlatform.libc == "msvcrt") ''
244 $RANLIB "$out/lib/"*.a
245 '';
246
247 outputs = [ "out" "dev" ];
248 setOutputFlags = false;
249}