diff options
author | John Ericson <John.Ericson@Obsidian.Systems> | 2020-04-17 18:40:51 -0400 |
---|---|---|
committer | John Ericson <John.Ericson@Obsidian.Systems> | 2020-04-17 18:40:51 -0400 |
commit | 33c2a76c5e1dac06d2963ad626d1083ed4b96f06 (patch) | |
tree | 90e5ce60f3d7ea83f41f54c86971e19aae6b3594 /pkgs/build-support | |
parent | d1009f4d99dbb6600f08ab0ef214806acc675670 (diff) | |
parent | cdfda4b455d0d904428fd157fba323f131fe8f6f (diff) |
Merge remote-tracking branch 'upstream/master' into staging
Diffstat (limited to 'pkgs/build-support')
-rw-r--r-- | pkgs/build-support/alternatives/blas/default.nix | 137 | ||||
-rw-r--r-- | pkgs/build-support/alternatives/lapack/default.nix | 111 | ||||
-rw-r--r-- | pkgs/build-support/setup-hooks/audit-blas.sh | 37 |
3 files changed, 285 insertions, 0 deletions
diff --git a/pkgs/build-support/alternatives/blas/default.nix b/pkgs/build-support/alternatives/blas/default.nix new file mode 100644 index 0000000000000..1b87834386623 --- /dev/null +++ b/pkgs/build-support/alternatives/blas/default.nix @@ -0,0 +1,137 @@ +{ lib, stdenv +, lapack-reference, openblasCompat, openblas +, is64bit ? false +, blasProvider ? if is64bit then openblas else openblasCompat }: + +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; + + + is64bit = blasProvider.blas64 or false; + blasImplementation = lib.getName blasProvider; + +in + +assert is64bit -> (blasImplementation == "openblas" && blasProvider.blas64) || blasImplementation == "mkl"; + +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 is64bit; + provider = blasProvider; + implementation = blasImplementation; + }; + + dontBuild = true; + dontConfigure = true; + unpackPhase = "src=$PWD"; + + installPhase = ('' + mkdir -p $out/lib $dev/include $dev/include/pkgconfig + + libblas="${lib.getLib blasProvider}/lib/libblas${stdenv.hostPlatform.extensions.sharedLibrary}" + + 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 "^$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.parsed.kernel.execFormat.name == "elf" 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 if stdenv.hostPlatform.isDarwin then '' + install_name_tool \ + -id libblas${canonicalExtension} + -add_rpath ${lib.getLib blasProvider}/lib \ + $out/lib/libblas${canonicalExtension} +'' else "") + '' + + 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${stdenv.hostPlatform.extensions.sharedLibrary}" + + 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.parsed.kernel.execFormat.name == "elf" 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 if stdenv.hostPlatform.isDarwin then '' + install_name_tool \ + -id libcblas${canonicalExtension} \ + -add_rpath ${lib.getLib blasProvider}/lib \ + $out/lib/libcblas${canonicalExtension} +'' else "") + '' + 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 +'' + stdenv.lib.optionalString (blasImplementation == "mkl") '' + mkdir -p $out/nix-support + echo 'export MKL_INTERFACE_LAYER=${lib.optionalString is64bit "I"}LP64,GNU' > $out/nix-support/setup-hook +''); +} diff --git a/pkgs/build-support/alternatives/lapack/default.nix b/pkgs/build-support/alternatives/lapack/default.nix new file mode 100644 index 0000000000000..24c339042a2ff --- /dev/null +++ b/pkgs/build-support/alternatives/lapack/default.nix @@ -0,0 +1,111 @@ +{ lib, stdenv +, lapack-reference, openblasCompat, openblas +, is64bit ? false +, lapackProvider ? if is64bit then openblas else openblasCompat }: + +let + + version = "3"; + canonicalExtension = if stdenv.hostPlatform.isLinux + then "${stdenv.hostPlatform.extensions.sharedLibrary}.${version}" + else stdenv.hostPlatform.extensions.sharedLibrary; + + lapackImplementation = lib.getName lapackProvider; + +in + +assert is64bit -> (lapackImplementation == "openblas" && lapackProvider.blas64) || lapackImplementation == "mkl"; + +stdenv.mkDerivation { + pname = "lapack"; + inherit version; + + outputs = [ "out" "dev" ]; + + meta = (lapackProvider.meta or {}) // { + description = "${lib.getName lapackProvider} with just the LAPACK C and FORTRAN ABI"; + }; + + passthru = { + inherit is64bit; + provider = lapackProvider; + implementation = lapackImplementation; + }; + + dontBuild = true; + dontConfigure = true; + unpackPhase = "src=$PWD"; + + installPhase = ('' + mkdir -p $out/lib $dev/include $dev/lib/pkgconfig + + liblapack="${lib.getLib lapackProvider}/lib/liblapack${stdenv.hostPlatform.extensions.sharedLibrary}" + + if ! [ -e "$liblapack" ]; then + echo "$liblapack does not exist, ${lapackProvider.name} does not provide liblapack." + exit 1 + fi + + cp -L "$liblapack" $out/lib/liblapack${canonicalExtension} + chmod +w $out/lib/liblapack${canonicalExtension} + +'' + (if stdenv.hostPlatform.parsed.kernel.execFormat.name == "elf" then '' + patchelf --set-soname liblapack${canonicalExtension} $out/lib/liblapack${canonicalExtension} + patchelf --set-rpath "$(patchelf --print-rpath $out/lib/liblapack${canonicalExtension}):${lapackProvider}/lib" $out/lib/liblapack${canonicalExtension} +'' else if stdenv.hostPlatform.isDarwin then '' + install_name_tool -id liblapack${canonicalExtension} \ + -add_rpath ${lib.getLib lapackProvider}/lib \ + $out/lib/liblapack${canonicalExtension} +'' else "") + '' + + if [ "$out/lib/liblapack${canonicalExtension}" != "$out/lib/liblapack${stdenv.hostPlatform.extensions.sharedLibrary}" ]; then + ln -s $out/lib/liblapack${canonicalExtension} "$out/lib/liblapack${stdenv.hostPlatform.extensions.sharedLibrary}" + fi + + install -D ${lib.getDev lapack-reference}/include/lapack.h $dev/include/lapack.h + + cat <<EOF > $dev/lib/pkgconfig/lapack.pc +Name: lapack +Version: ${version} +Description: LAPACK FORTRAN implementation +Cflags: -I$dev/include +Libs: -L$out/lib -llapack +EOF + + liblapacke="${lib.getLib lapackProvider}/lib/liblapacke${stdenv.hostPlatform.extensions.sharedLibrary}" + + if ! [ -e "$liblapacke" ]; then + echo "$liblapacke does not exist, ${lapackProvider.name} does not provide liblapacke." + exit 1 + fi + + cp -L "$liblapacke" $out/lib/liblapacke${canonicalExtension} + chmod +w $out/lib/liblapacke${canonicalExtension} + +'' + (if stdenv.hostPlatform.parsed.kernel.execFormat.name == "elf" then '' + patchelf --set-soname liblapacke${canonicalExtension} $out/lib/liblapacke${canonicalExtension} + patchelf --set-rpath "$(patchelf --print-rpath $out/lib/liblapacke${canonicalExtension}):${lib.getLib lapackProvider}/lib" $out/lib/liblapacke${canonicalExtension} +'' else if stdenv.hostPlatform.isDarwin then '' + install_name_tool -id liblapacke${canonicalExtension} \ + -add_rpath ${lib.getLib lapackProvider}/lib \ + $out/lib/liblapacke${canonicalExtension} +'' else "") + '' + + if [ -f "$out/lib/liblapacke.so.3" ]; then + ln -s $out/lib/liblapacke.so.3 $out/lib/liblapacke.so + fi + + cp ${lib.getDev lapack-reference}/include/lapacke{,_mangling,_config}.h $dev/include + + cat <<EOF > $dev/lib/pkgconfig/lapacke.pc +Name: lapacke +Version: ${version} +Description: LAPACK C implementation +Cflags: -I$dev/include +Libs: -L$out/lib -llapacke +EOF +'' + stdenv.lib.optionalString (lapackImplementation == "mkl") '' + mkdir -p $out/nix-support + echo 'export MKL_INTERFACE_LAYER=${lib.optionalString is64bit "I"}LP64,GNU' > $out/nix-support/setup-hook +''); +} diff --git a/pkgs/build-support/setup-hooks/audit-blas.sh b/pkgs/build-support/setup-hooks/audit-blas.sh new file mode 100644 index 0000000000000..6a40073fb2345 --- /dev/null +++ b/pkgs/build-support/setup-hooks/audit-blas.sh @@ -0,0 +1,37 @@ +# Ensure that we are always linking against “libblas.so.3” and +# “liblapack.so.3”. + +auditBlas() { + local dir="$prefix" + [ -e "$dir" ] || return 0 + + local i + while IFS= read -r -d $'\0' i; do + if ! isELF "$i"; then continue; fi + + if $OBJDUMP -p "$i" | grep 'NEEDED' | awk '{ print $2; }' | grep -q '\(libmkl_rt.so\|libopenblas.so.0\)'; then + echo "$i refers to a specific implementation of BLAS or LAPACK." + echo "This prevents users from switching BLAS/LAPACK implementations." + echo "Add \`blas' or \`lapack' to buildInputs instead of \`mkl' or \`openblas'." + exit 1 + fi + + (IFS=: + for dir in "$(patchelf --print-rpath "$i")"; do + if [ -f "$dir/libblas.so.3" ] || [ -f "$dir/libblas.so" ]; then + if [ "$dir" != "@blas@/lib" ]; then + echo "$dir is not allowed to contain a library named libblas.so.3" + exit 1 + fi + fi + if [ -f "$dir/liblapack.so.3" ] || [ -f "$dir/liblapack.so" ]; then + if [ "$dir" != "@lapack@/lib" ]; then + echo "$dir is not allowed to contain a library named liblapack.so.3" + exit 1 + fi + fi + done) + done < <(find "$dir" -type f -print0) +} + +fixupOutputHooks+=(auditBlas) |