syndicate_utils: 20240509 -> 20250110
[NixPkgs.git] / pkgs / development / libraries / science / math / openblas / default.nix
blob0a81f0f8af39380e9aba31a3f781b78c5be7d357
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,
32   # for passthru.tests
33   ceres-solver,
34   giac,
35   octave,
36   opencv,
37   python3,
38   openmp ? null,
41 let
42   blas64_ = blas64;
45 let
46   setTarget = x: if target == null then x else target;
47   setDynamicArch = x: if dynamicArch == null then x else dynamicArch;
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     };
58     armv7l-linux = {
59       BINARY = 32;
60       TARGET = setTarget "ARMV7";
61       DYNAMIC_ARCH = setDynamicArch false;
62       USE_OPENMP = true;
63     };
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     };
73     aarch64-linux = {
74       BINARY = 64;
75       TARGET = setTarget "ARMV8";
76       DYNAMIC_ARCH = setDynamicArch true;
77       USE_OPENMP = true;
78     };
80     i686-linux = {
81       BINARY = 32;
82       TARGET = setTarget "P2";
83       DYNAMIC_ARCH = setDynamicArch true;
84       USE_OPENMP = true;
85     };
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     };
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     };
104     powerpc64le-linux = {
105       BINARY = 64;
106       TARGET = setTarget "POWER5";
107       DYNAMIC_ARCH = setDynamicArch true;
108       USE_OPENMP = !stdenv.hostPlatform.isMusl;
109     };
111     riscv64-linux = {
112       BINARY = 64;
113       TARGET = setTarget "RISCV64_GENERIC";
114       DYNAMIC_ARCH = setDynamicArch false;
115       USE_OPENMP = true;
116     };
118     loongarch64-linux = {
119       BINARY = 64;
120       TARGET = setTarget "LOONGSONGENERIC";
121       DYNAMIC_ARCH = setDynamicArch false;
122       USE_OPENMP = true;
123     };
125     s390x-linux = {
126       BINARY = 64;
127       TARGET = setTarget "ZARCH_GENERIC";
128       DYNAMIC_ARCH = setDynamicArch true;
129       USE_OPENMP = true;
130     };
131   };
135   config =
136     configs.${stdenv.hostPlatform.system}
137       or (throw "unsupported system: ${stdenv.hostPlatform.system}");
141   blas64 = if blas64_ != null then blas64_ else lib.hasPrefix "x86_64" stdenv.hostPlatform.system;
142   # Convert flag values to format OpenBLAS's build expects.
143   # `toString` is almost what we need other than bools,
144   # which we need to map {true -> 1, false -> 0}
145   # (`toString` produces empty string `""` for false instead of `0`)
146   mkMakeFlagValue =
147     val:
148     if !builtins.isBool val then
149       toString val
150     else if val then
151       "1"
152     else
153       "0";
154   mkMakeFlagsFromConfig = lib.mapAttrsToList (var: val: "${var}=${mkMakeFlagValue val}");
156   shlibExt = stdenv.hostPlatform.extensions.sharedLibrary;
159 stdenv.mkDerivation rec {
160   pname = "openblas";
161   version = "0.3.28";
163   outputs = [
164     "out"
165     "dev"
166   ];
168   src = fetchFromGitHub {
169     owner = "OpenMathLib";
170     repo = "OpenBLAS";
171     rev = "v${version}";
172     hash = "sha256-430zG47FoBNojcPFsVC7FA43FhVPxrulxAW3Fs6CHo8=";
173   };
175   postPatch = ''
176     # cc1: error: invalid feature modifier 'sve2' in '-march=armv8.5-a+sve+sve2+bf16'
177     substituteInPlace Makefile.arm64 --replace "+sve2+bf16" ""
178   '';
180   inherit blas64;
182   # Some hardening features are disabled due to sporadic failures in
183   # OpenBLAS-based programs. The problem may not be with OpenBLAS itself, but
184   # with how these flags interact with hardening measures used downstream.
185   # In either case, OpenBLAS must only be used by trusted code--it is
186   # inherently unsuitable for security-conscious applications--so there should
187   # be no objection to disabling these hardening measures.
188   hardeningDisable =
189     [
190       # don't modify or move the stack
191       "stackprotector"
192       "pic"
193       # don't alter index arithmetic
194       "strictoverflow"
195       # don't interfere with dynamic target detection
196       "relro"
197       "bindnow"
198     ]
199     ++ lib.optionals stdenv.hostPlatform.isAarch64 [
200       # "__builtin_clear_padding not supported for variable length aggregates"
201       # in aarch64-specific code
202       "trivialautovarinit"
203     ];
205   nativeBuildInputs = [
206     perl
207     which
208   ];
210   buildInputs = lib.optional (stdenv.cc.isClang && config.USE_OPENMP) openmp;
212   depsBuildBuild = [
213     buildPackages.gfortran
214     buildPackages.stdenv.cc
215   ];
217   enableParallelBuilding = true;
219   makeFlags = mkMakeFlagsFromConfig (
220     config
221     // {
222       FC = "${stdenv.cc.targetPrefix}gfortran";
223       CC = "${stdenv.cc.targetPrefix}${if stdenv.cc.isClang then "clang" else "cc"}";
224       PREFIX = placeholder "out";
225       OPENBLAS_INCLUDE_DIR = "${placeholder "dev"}/include";
226       NUM_THREADS = 64;
227       INTERFACE64 = blas64;
228       NO_STATIC = !enableStatic;
229       NO_SHARED = !enableShared;
230       CROSS = stdenv.hostPlatform != stdenv.buildPlatform;
231       HOSTCC = "cc";
232       # Makefile.system only checks defined status
233       # This seems to be a bug in the openblas Makefile:
234       # on x86_64 it expects NO_BINARY_MODE=
235       # but on aarch64 it expects NO_BINARY_MODE=0
236       NO_BINARY_MODE =
237         if stdenv.hostPlatform.isx86_64 then
238           toString (stdenv.hostPlatform != stdenv.buildPlatform)
239         else
240           stdenv.hostPlatform != stdenv.buildPlatform;
241       # This disables automatic build job count detection (which honours neither enableParallelBuilding nor NIX_BUILD_CORES)
242       # and uses the main make invocation's job count, falling back to 1 if no parallelism is used.
243       # https://github.com/OpenMathLib/OpenBLAS/blob/v0.3.20/getarch.c#L1781-L1792
244       MAKE_NB_JOBS = 0;
245     }
246     // (lib.optionalAttrs stdenv.cc.isClang {
247       LDFLAGS = "-L${lib.getLib buildPackages.gfortran.cc}/lib"; # contains `libgfortran.so`; building with clang needs this, gcc has it implicit
248     })
249     // (lib.optionalAttrs singleThreaded {
250       # As described on https://github.com/OpenMathLib/OpenBLAS/wiki/Faq/4bded95e8dc8aadc70ce65267d1093ca7bdefc4c#multi-threaded
251       USE_THREAD = false;
252       USE_LOCKING = true; # available with openblas >= 0.3.7
253       USE_OPENMP = false; # openblas will refuse building with both USE_OPENMP=1 and USE_THREAD=0
254     })
255   );
257   doCheck = true;
258   checkTarget = "tests";
260   postInstall =
261     ''
262           # Write pkgconfig aliases. Upstream report:
263           # https://github.com/OpenMathLib/OpenBLAS/issues/1740
264           for alias in blas cblas lapack; do
265             cat <<EOF > $out/lib/pkgconfig/$alias.pc
266       Name: $alias
267       Version: ${version}
268       Description: $alias provided by the OpenBLAS package.
269       Cflags: -I$dev/include
270       Libs: -L$out/lib -lopenblas
271       EOF
272           done
274           # Setup symlinks for blas / lapack
275     ''
276     + lib.optionalString enableShared ''
277       ln -s $out/lib/libopenblas${shlibExt} $out/lib/libblas${shlibExt}
278       ln -s $out/lib/libopenblas${shlibExt} $out/lib/libcblas${shlibExt}
279       ln -s $out/lib/libopenblas${shlibExt} $out/lib/liblapack${shlibExt}
280       ln -s $out/lib/libopenblas${shlibExt} $out/lib/liblapacke${shlibExt}
281     ''
282     + lib.optionalString (stdenv.hostPlatform.isLinux && enableShared) ''
283       ln -s $out/lib/libopenblas${shlibExt} $out/lib/libblas${shlibExt}.3
284       ln -s $out/lib/libopenblas${shlibExt} $out/lib/libcblas${shlibExt}.3
285       ln -s $out/lib/libopenblas${shlibExt} $out/lib/liblapack${shlibExt}.3
286       ln -s $out/lib/libopenblas${shlibExt} $out/lib/liblapacke${shlibExt}.3
287     ''
288     + lib.optionalString enableStatic ''
289       ln -s $out/lib/libopenblas.a $out/lib/libblas.a
290       ln -s $out/lib/libopenblas.a $out/lib/libcblas.a
291       ln -s $out/lib/libopenblas.a $out/lib/liblapack.a
292       ln -s $out/lib/libopenblas.a $out/lib/liblapacke.a
293     '';
295   passthru.tests = {
296     inherit (python3.pkgs) numpy scipy scikit-learn;
297     inherit
298       ceres-solver
299       giac
300       octave
301       opencv
302       ;
303   };
305   meta = with lib; {
306     description = "Basic Linear Algebra Subprograms";
307     license = licenses.bsd3;
308     homepage = "https://github.com/OpenMathLib/OpenBLAS";
309     platforms = attrNames configs;
310     maintainers = with maintainers; [ ttuegel ];
311   };