Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1{
2 lib,
3 stdenv,
4 fetchFromGitHub,
5 perl,
6 which,
7 # Most packages depending on openblas expect integer width to match
8 # pointer width, but some expect to use 32-bit integers always
9 # (for compatibility with reference BLAS).
10 blas64 ? null,
11 # Multi-threaded applications must not call a threaded OpenBLAS
12 # (the only exception is when an application uses OpenMP as its
13 # *only* form of multi-threading). See
14 # https://github.com/OpenMathLib/OpenBLAS/wiki/Faq/4bded95e8dc8aadc70ce65267d1093ca7bdefc4c#multi-threaded
15 # https://github.com/OpenMathLib/OpenBLAS/issues/2543
16 # This flag builds a single-threaded OpenBLAS using the flags
17 # stated in thre.
18 singleThreaded ? false,
19 buildPackages,
20 # Select a specific optimization target (other than the default)
21 # See https://github.com/OpenMathLib/OpenBLAS/blob/develop/TargetList.txt
22 target ? null,
23 # Select whether DYNAMIC_ARCH is enabled or not.
24 dynamicArch ? null,
25 # enable AVX512 optimized kernels.
26 # These kernels have been a source of trouble in the past.
27 # Use with caution.
28 enableAVX512 ? false,
29 enableStatic ? stdenv.hostPlatform.isStatic,
30 enableShared ? !stdenv.hostPlatform.isStatic,
31
32 # for passthru.tests
33 ceres-solver,
34 giac,
35 octave,
36 opencv,
37 python3,
38 openmp ? null,
39}:
40
41let
42 blas64_ = blas64;
43in
44
45let
46 setTarget = x: if target == null then x else target;
47 setDynamicArch = x: if dynamicArch == null then x else dynamicArch;
48
49 # To add support for a new platform, add an element to this set.
50 configs = {
51 armv6l-linux = {
52 BINARY = 32;
53 TARGET = setTarget "ARMV6";
54 DYNAMIC_ARCH = setDynamicArch false;
55 USE_OPENMP = true;
56 };
57
58 armv7l-linux = {
59 BINARY = 32;
60 TARGET = setTarget "ARMV7";
61 DYNAMIC_ARCH = setDynamicArch false;
62 USE_OPENMP = true;
63 };
64
65 aarch64-darwin = {
66 BINARY = 64;
67 TARGET = setTarget "VORTEX";
68 DYNAMIC_ARCH = setDynamicArch true;
69 USE_OPENMP = false;
70 MACOSX_DEPLOYMENT_TARGET = "11.0";
71 };
72
73 aarch64-linux = {
74 BINARY = 64;
75 TARGET = setTarget "ARMV8";
76 DYNAMIC_ARCH = setDynamicArch true;
77 USE_OPENMP = true;
78 };
79
80 i686-linux = {
81 BINARY = 32;
82 TARGET = setTarget "P2";
83 DYNAMIC_ARCH = setDynamicArch true;
84 USE_OPENMP = true;
85 };
86
87 x86_64-darwin = {
88 BINARY = 64;
89 TARGET = setTarget "ATHLON";
90 DYNAMIC_ARCH = setDynamicArch true;
91 NO_AVX512 = !enableAVX512;
92 USE_OPENMP = false;
93 MACOSX_DEPLOYMENT_TARGET = "10.7";
94 };
95
96 x86_64-linux = {
97 BINARY = 64;
98 TARGET = setTarget "ATHLON";
99 DYNAMIC_ARCH = setDynamicArch true;
100 NO_AVX512 = !enableAVX512;
101 USE_OPENMP = !stdenv.hostPlatform.isMusl;
102 };
103
104 x86_64-windows = {
105 BINARY = 64;
106 TARGET = setTarget "ATHLON";
107 DYNAMIC_ARCH = setDynamicArch true;
108 NO_AVX512 = !enableAVX512;
109 USE_OPENMP = false;
110 };
111
112 powerpc64-linux = {
113 BINARY = 64;
114 TARGET = setTarget "POWER4";
115 DYNAMIC_ARCH = setDynamicArch false;
116 USE_OPENMP = !stdenv.hostPlatform.isMusl;
117 };
118
119 powerpc64le-linux = {
120 BINARY = 64;
121 TARGET = setTarget "POWER5";
122 DYNAMIC_ARCH = setDynamicArch true;
123 USE_OPENMP = !stdenv.hostPlatform.isMusl;
124 };
125
126 riscv64-linux = {
127 BINARY = 64;
128 TARGET = setTarget "RISCV64_GENERIC";
129 DYNAMIC_ARCH = setDynamicArch false;
130 USE_OPENMP = true;
131 };
132
133 loongarch64-linux = {
134 TARGET = setTarget "LA64_GENERIC";
135 DYNAMIC_ARCH = setDynamicArch false;
136 USE_OPENMP = true;
137 };
138
139 s390x-linux = {
140 BINARY = 64;
141 TARGET = setTarget "ZARCH_GENERIC";
142 DYNAMIC_ARCH = setDynamicArch true;
143 USE_OPENMP = true;
144 };
145
146 x86_64-freebsd = {
147 BINARY = 64;
148 TARGET = setTarget "ATHLON";
149 DYNAMIC_ARCH = setDynamicArch true;
150 NO_AVX512 = !enableAVX512;
151 USE_OPENMP = true;
152 };
153 };
154in
155
156let
157 config =
158 configs.${stdenv.hostPlatform.system}
159 or (throw "unsupported system: ${stdenv.hostPlatform.system}");
160in
161
162let
163 blas64 = if blas64_ != null then blas64_ else lib.hasPrefix "x86_64" stdenv.hostPlatform.system;
164 # Convert flag values to format OpenBLAS's build expects.
165 # `toString` is almost what we need other than bools,
166 # which we need to map {true -> 1, false -> 0}
167 # (`toString` produces empty string `""` for false instead of `0`)
168 mkMakeFlagValue =
169 val:
170 if !builtins.isBool val then
171 toString val
172 else if val then
173 "1"
174 else
175 "0";
176 mkMakeFlagsFromConfig = lib.mapAttrsToList (var: val: "${var}=${mkMakeFlagValue val}");
177
178 shlibExt = stdenv.hostPlatform.extensions.sharedLibrary;
179
180in
181stdenv.mkDerivation rec {
182 pname = "openblas";
183 version = "0.3.30";
184
185 outputs = [
186 "out"
187 "dev"
188 ];
189
190 src = fetchFromGitHub {
191 owner = "OpenMathLib";
192 repo = "OpenBLAS";
193 rev = "v${version}";
194 hash = "sha256-foP2OXUL6ttgYvCxLsxUiVdkPoTvGiHomdNudbSUmSE=";
195 };
196
197 postPatch = ''
198 # cc1: error: invalid feature modifier 'sve2' in '-march=armv8.5-a+sve+sve2+bf16'
199 substituteInPlace Makefile.arm64 --replace "+sve2+bf16" ""
200 '';
201
202 inherit blas64;
203
204 # Some hardening features are disabled due to sporadic failures in
205 # OpenBLAS-based programs. The problem may not be with OpenBLAS itself, but
206 # with how these flags interact with hardening measures used downstream.
207 # In either case, OpenBLAS must only be used by trusted code--it is
208 # inherently unsuitable for security-conscious applications--so there should
209 # be no objection to disabling these hardening measures.
210 hardeningDisable = [
211 # don't modify or move the stack
212 "stackprotector"
213 "pic"
214 # don't alter index arithmetic
215 "strictoverflow"
216 # don't interfere with dynamic target detection
217 "relro"
218 "bindnow"
219 ]
220 ++ lib.optionals stdenv.hostPlatform.isAarch64 [
221 # "__builtin_clear_padding not supported for variable length aggregates"
222 # in aarch64-specific code
223 "trivialautovarinit"
224 ];
225
226 nativeBuildInputs = [
227 perl
228 which
229 ];
230
231 buildInputs = lib.optional (stdenv.cc.isClang && config.USE_OPENMP) openmp;
232
233 depsBuildBuild = [
234 buildPackages.gfortran
235 buildPackages.stdenv.cc
236 ];
237
238 enableParallelBuilding = true;
239
240 makeFlags = mkMakeFlagsFromConfig (
241 config
242 // {
243 FC = "${stdenv.cc.targetPrefix}gfortran";
244 CC = "${stdenv.cc.targetPrefix}${if stdenv.cc.isClang then "clang" else "cc"}";
245 PREFIX = placeholder "out";
246 OPENBLAS_INCLUDE_DIR = "${placeholder "dev"}/include";
247 NUM_THREADS = 64;
248 INTERFACE64 = blas64;
249 NO_STATIC = !enableStatic;
250 NO_SHARED = !enableShared;
251 CROSS = stdenv.hostPlatform != stdenv.buildPlatform;
252 HOSTCC = "cc";
253 # Makefile.system only checks defined status
254 # This seems to be a bug in the openblas Makefile:
255 # on x86_64 it expects NO_BINARY_MODE=
256 # but on aarch64 it expects NO_BINARY_MODE=0
257 NO_BINARY_MODE =
258 if stdenv.hostPlatform.isx86_64 then
259 toString (stdenv.hostPlatform != stdenv.buildPlatform)
260 else
261 stdenv.hostPlatform != stdenv.buildPlatform;
262 # This disables automatic build job count detection (which honours neither enableParallelBuilding nor NIX_BUILD_CORES)
263 # and uses the main make invocation's job count, falling back to 1 if no parallelism is used.
264 # https://github.com/OpenMathLib/OpenBLAS/blob/v0.3.20/getarch.c#L1781-L1792
265 MAKE_NB_JOBS = 0;
266 }
267 // (lib.optionalAttrs stdenv.cc.isClang {
268 LDFLAGS = "-L${lib.getLib buildPackages.gfortran.cc}/lib"; # contains `libgfortran.so`; building with clang needs this, gcc has it implicit
269 })
270 // (lib.optionalAttrs singleThreaded {
271 # As described on https://github.com/OpenMathLib/OpenBLAS/wiki/Faq/4bded95e8dc8aadc70ce65267d1093ca7bdefc4c#multi-threaded
272 USE_THREAD = false;
273 USE_LOCKING = true; # available with openblas >= 0.3.7
274 USE_OPENMP = false; # openblas will refuse building with both USE_OPENMP=1 and USE_THREAD=0
275 })
276 );
277
278 doCheck = true;
279 checkTarget = "tests";
280
281 postInstall = ''
282 # Write pkgconfig aliases. Upstream report:
283 # https://github.com/OpenMathLib/OpenBLAS/issues/1740
284 for alias in blas cblas lapack; do
285 cat <<EOF > $out/lib/pkgconfig/$alias.pc
286 Name: $alias
287 Version: ${version}
288 Description: $alias provided by the OpenBLAS package.
289 Cflags: -I$dev/include
290 Libs: -L$out/lib -lopenblas
291 EOF
292 done
293
294 # Setup symlinks for blas / lapack
295 ''
296 + lib.optionalString stdenv.hostPlatform.isMinGW ''
297 ln -s $out/bin/*.dll $out/lib
298 ''
299 + lib.optionalString enableShared ''
300 ln -s $out/lib/libopenblas${shlibExt} $out/lib/libblas${shlibExt}
301 ln -s $out/lib/libopenblas${shlibExt} $out/lib/libcblas${shlibExt}
302 ln -s $out/lib/libopenblas${shlibExt} $out/lib/liblapack${shlibExt}
303 ln -s $out/lib/libopenblas${shlibExt} $out/lib/liblapacke${shlibExt}
304 ''
305 + lib.optionalString (stdenv.hostPlatform.isLinux && enableShared) ''
306 ln -s $out/lib/libopenblas${shlibExt} $out/lib/libblas${shlibExt}.3
307 ln -s $out/lib/libopenblas${shlibExt} $out/lib/libcblas${shlibExt}.3
308 ln -s $out/lib/libopenblas${shlibExt} $out/lib/liblapack${shlibExt}.3
309 ln -s $out/lib/libopenblas${shlibExt} $out/lib/liblapacke${shlibExt}.3
310 ''
311 + lib.optionalString enableStatic ''
312 ln -s $out/lib/libopenblas.a $out/lib/libblas.a
313 ln -s $out/lib/libopenblas.a $out/lib/libcblas.a
314 ln -s $out/lib/libopenblas.a $out/lib/liblapack.a
315 ln -s $out/lib/libopenblas.a $out/lib/liblapacke.a
316 '';
317
318 passthru.tests = {
319 inherit (python3.pkgs) numpy scipy scikit-learn;
320 inherit
321 ceres-solver
322 giac
323 octave
324 opencv
325 ;
326 };
327
328 meta = with lib; {
329 description = "Basic Linear Algebra Subprograms";
330 license = licenses.bsd3;
331 homepage = "https://github.com/OpenMathLib/OpenBLAS";
332 platforms = attrNames configs;
333 maintainers = with maintainers; [ ttuegel ];
334 };
335}