about summary refs log tree commit diff
path: root/pkgs/build-support
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2020-04-17 18:40:51 -0400
committerJohn Ericson <John.Ericson@Obsidian.Systems>2020-04-17 18:40:51 -0400
commit33c2a76c5e1dac06d2963ad626d1083ed4b96f06 (patch)
tree90e5ce60f3d7ea83f41f54c86971e19aae6b3594 /pkgs/build-support
parentd1009f4d99dbb6600f08ab0ef214806acc675670 (diff)
parentcdfda4b455d0d904428fd157fba323f131fe8f6f (diff)
Merge remote-tracking branch 'upstream/master' into staging
Diffstat (limited to 'pkgs/build-support')
-rw-r--r--pkgs/build-support/alternatives/blas/default.nix137
-rw-r--r--pkgs/build-support/alternatives/lapack/default.nix111
-rw-r--r--pkgs/build-support/setup-hooks/audit-blas.sh37
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)