aboutsummaryrefslogtreecommitdiff
path: root/pkgs/build-support/alternatives
diff options
context:
space:
mode:
authorMatthew Bauer <mjbauer95@gmail.com>2020-03-27 14:50:45 -0400
committerMatthew Bauer <mjbauer95@gmail.com>2020-04-17 16:23:55 -0500
commit43873351ffed36b52170571839e26b57c9f15920 (patch)
treeb786ea2449e58fa8ccead15251bfbb187b7d94aa /pkgs/build-support/alternatives
parent90326ba624ddfbd3b7f9eb3995994644cee804fb (diff)
blas/lapack: add wrapper for “alternative”s of BLAS/LAPACK provider
This is based on previous work for switching between BLAS and LAPACK implementation in Debian[1] and Gentoo[2]. The goal is to have one way to depend on the BLAS/LAPACK libraries that all packages must use. The attrs “blas” and “lapack” are used to represent a wrapped BLAS/LAPACK provider. Derivations that don’t care how BLAS and LAPACK are implemented can just use blas and lapack directly. If you do care what you get (perhaps for some CPP), you should verify that blas and lapack match what you expect with an assertion. The “blas” package collides with the old “blas” reference implementation. This has been renamed to “blas-reference”. In addition, “lapack-reference” is also included, corresponding to “liblapack” from Netlib.org. Currently, there are 3 providers of the BLAS and LAPACK interfaces: - lapack-reference: the BLAS/LAPACK implementation maintained by netlib.org - OpenBLAS: an optimized version of BLAS and LAPACK - MKL: Intel’s unfree but highly optimized BLAS/LAPACK implementation By default, the above implementations all use the “LP64” BLAS and LAPACK ABI. This corresponds to “openblasCompat” and is the safest way to use BLAS/LAPACK. You may received some benefits from “ILP64” or 8-byte integer BLAS at the expense of breaking compatibility with some packages. This can be switched at build time with an override like: import <nixpkgs> { config.allowUnfree = true; overlays = [(self: super: { lapack = super.lapack.override { lapackProvider = super.lapack-reference; }; blas = super.blas.override { blasProvider = super.lapack-reference; }; })]; } or, switched at runtime via LD_LIBRARY_PATH like: $ LD_LIBRARY_PATH=$(nix-build -E '(with import <nixpkgs> {}).lapack.override { lapackProvider = pkgs.mkl; is64bit = true; })')/lib:$(nix-build -E '(with import <nixpkgs> {}).blas.override { blasProvider = pkgs.mkl; is64bit = true; })')/lib ./your-blas-linked-binary By default, we use OpenBLAS LP64 also known in Nixpkgs as openblasCompat. [1]: https://wiki.debian.org/DebianScience/LinearAlgebraLibraries [2]: https://wiki.gentoo.org/wiki/Blas-lapack-switch
Diffstat (limited to 'pkgs/build-support/alternatives')
-rw-r--r--pkgs/build-support/alternatives/blas/default.nix137
-rw-r--r--pkgs/build-support/alternatives/lapack/default.nix111
2 files changed, 248 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 000000000000..1b8783438662
--- /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 000000000000..24c339042a2f
--- /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
+'');
+}