core/pkgs/build-support/alternatives/blas/default.nix
2024-06-30 09:12:46 +01:00

301 lines
6.4 KiB
Nix

{
lib,
stdenv,
lapack-reference,
openblas,
isILP64 ? false,
blasProvider ? openblas,
}:
let
blasFortranSymbols = [
"caxpy"
"ccopy"
"cdotc"
"cdotu"
"cgbmv"
"cgemm"
"cgemv"
"cgerc"
"cgeru"
"chbmv"
"chemm"
"chemv"
"cher"
"cher2"
"cher2k"
"cherk"
"chpmv"
"chpr"
"chpr2"
"crotg"
"cscal"
"csrot"
"csscal"
"cswap"
"csymm"
"csyr2k"
"csyrk"
"ctbmv"
"ctbsv"
"ctpmv"
"ctpsv"
"ctrmm"
"ctrmv"
"ctrsm"
"ctrsv"
"dasum"
"daxpy"
"dcabs1"
"dcopy"
"ddot"
"dgbmv"
"dgemm"
"dgemv"
"dger"
"dnrm2"
"drot"
"drotg"
"drotm"
"drotmg"
"dsbmv"
"dscal"
"dsdot"
"dspmv"
"dspr"
"dspr2"
"dswap"
"dsymm"
"dsymv"
"dsyr"
"dsyr2"
"dsyr2k"
"dsyrk"
"dtbmv"
"dtbsv"
"dtpmv"
"dtpsv"
"dtrmm"
"dtrmv"
"dtrsm"
"dtrsv"
"dzasum"
"dznrm2"
"icamax"
"idamax"
"isamax"
"izamax"
"lsame"
"sasum"
"saxpy"
"scabs1"
"scasum"
"scnrm2"
"scopy"
"sdot"
"sdsdot"
"sgbmv"
"sgemm"
"sgemv"
"sger"
"snrm2"
"srot"
"srotg"
"srotm"
"srotmg"
"ssbmv"
"sscal"
"sspmv"
"sspr"
"sspr2"
"sswap"
"ssymm"
"ssymv"
"ssyr"
"ssyr2"
"ssyr2k"
"ssyrk"
"stbmv"
"stbsv"
"stpmv"
"stpsv"
"strmm"
"strmv"
"strsm"
"strsv"
"xerbla"
"xerbla_array"
"zaxpy"
"zcopy"
"zdotc"
"zdotu"
"zdrot"
"zdscal"
"zgbmv"
"zgemm"
"zgemv"
"zgerc"
"zgeru"
"zhbmv"
"zhemm"
"zhemv"
"zher"
"zher2"
"zher2k"
"zherk"
"zhpmv"
"zhpr"
"zhpr2"
"zrotg"
"zscal"
"zswap"
"zsymm"
"zsyr2k"
"zsyrk"
"ztbmv"
"ztbsv"
"ztpmv"
"ztpsv"
"ztrmm"
"ztrmv"
"ztrsm"
"ztrsv"
];
version = "3";
canonicalExtension =
if stdenv.hostPlatform.isLinux then
"${stdenv.hostPlatform.extensions.sharedLibrary}.${version}"
else
stdenv.hostPlatform.extensions.sharedLibrary;
blasImplementation = lib.getName blasProvider;
blasProvider' =
if blasImplementation == "mkl" then blasProvider else blasProvider.override { blas64 = isILP64; };
in
assert isILP64 -> blasImplementation == "mkl" || blasProvider'.blas64;
stdenv.mkDerivation {
pname = "blas";
inherit version;
outputs = [
"out"
"dev"
];
meta = (blasProvider'.meta or { }) // {
description = "${lib.getName blasProvider} with just the BLAS C and FORTRAN ABI";
};
passthru = {
inherit isILP64;
provider = blasProvider';
implementation = blasImplementation;
};
dontBuild = true;
dontConfigure = true;
unpackPhase = "src=$PWD";
dontPatchELF = true;
installPhase = (
''
mkdir -p $out/lib $dev/include $dev/lib/pkgconfig
libblas="${lib.getLib blasProvider'}/lib/libblas${canonicalExtension}"
if ! [ -e "$libblas" ]; then
echo "$libblas does not exist, ${blasProvider'.name} does not provide libblas."
exit 1
fi
$NM -an "$libblas" | cut -f3 -d' ' > symbols
for symbol in ${toString blasFortranSymbols}; do
grep -q "^$symbol_$" symbols || { echo "$symbol" was not found in "$libblas"; exit 1; }
done
cp -L "$libblas" $out/lib/libblas${canonicalExtension}
chmod +w $out/lib/libblas${canonicalExtension}
''
+ (
if stdenv.hostPlatform.isElf then
''
patchelf --set-soname libblas${canonicalExtension} $out/lib/libblas${canonicalExtension}
patchelf --set-rpath "$(patchelf --print-rpath $out/lib/libblas${canonicalExtension}):${lib.getLib blasProvider'}/lib" $out/lib/libblas${canonicalExtension}
''
else
lib.optionalString (stdenv.hostPlatform.isDarwin) ''
install_name_tool \
-id $out/lib/libblas${canonicalExtension} \
-add_rpath ${lib.getLib blasProvider'}/lib \
$out/lib/libblas${canonicalExtension}
''
)
+ ''
if [ "$out/lib/libblas${canonicalExtension}" != "$out/lib/libblas${stdenv.hostPlatform.extensions.sharedLibrary}" ]; then
ln -s $out/lib/libblas${canonicalExtension} "$out/lib/libblas${stdenv.hostPlatform.extensions.sharedLibrary}"
fi
cat <<EOF > $dev/lib/pkgconfig/blas.pc
Name: blas
Version: ${version}
Description: BLAS FORTRAN implementation
Libs: -L$out/lib -lblas
Cflags: -I$dev/include
EOF
libcblas="${lib.getLib blasProvider'}/lib/libcblas${canonicalExtension}"
if ! [ -e "$libcblas" ]; then
echo "$libcblas does not exist, ${blasProvider'.name} does not provide libcblas."
exit 1
fi
cp -L "$libcblas" $out/lib/libcblas${canonicalExtension}
chmod +w $out/lib/libcblas${canonicalExtension}
''
+ (
if stdenv.hostPlatform.isElf then
''
patchelf --set-soname libcblas${canonicalExtension} $out/lib/libcblas${canonicalExtension}
patchelf --set-rpath "$(patchelf --print-rpath $out/lib/libcblas${canonicalExtension}):${lib.getLib blasProvider'}/lib" $out/lib/libcblas${canonicalExtension}
''
else
lib.optionalString stdenv.hostPlatform.isDarwin ''
install_name_tool \
-id $out/lib/libcblas${canonicalExtension} \
-add_rpath ${lib.getLib blasProvider'}/lib \
$out/lib/libcblas${canonicalExtension}
''
)
+ ''
if [ "$out/lib/libcblas${canonicalExtension}" != "$out/lib/libcblas${stdenv.hostPlatform.extensions.sharedLibrary}" ]; then
ln -s $out/lib/libcblas${canonicalExtension} "$out/lib/libcblas${stdenv.hostPlatform.extensions.sharedLibrary}"
fi
cp ${lib.getDev lapack-reference}/include/cblas{,_mangling}.h $dev/include
cat <<EOF > $dev/lib/pkgconfig/cblas.pc
Name: cblas
Version: ${version}
Description: BLAS C implementation
Cflags: -I$dev/include
Libs: -L$out/lib -lcblas
EOF
''
+ lib.optionalString (blasImplementation == "mkl") ''
mkdir -p $out/nix-support
echo 'export MKL_INTERFACE_LAYER=${lib.optionalString isILP64 "I"}LP64,GNU' > $out/nix-support/setup-hook
ln -s $out/lib/libblas${canonicalExtension} $out/lib/libmkl_rt${stdenv.hostPlatform.extensions.sharedLibrary}
ln -sf ${blasProvider'}/include/* $dev/include
''
);
}