summary refs log tree commit diff
path: root/pkgs/development/libraries/science/math/openblas/default.nix
blob: 9c411234357ab5a10393a2fd50117b5ca84a0827 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
{ stdenv, fetchFromGitHub, perl, which
# Most packages depending on openblas expect integer width to match
# pointer width, but some expect to use 32-bit integers always
# (for compatibility with reference BLAS).
, blas64 ? null
, buildPackages
# Select a specific optimization target (other than the default)
# See https://github.com/xianyi/OpenBLAS/blob/develop/TargetList.txt
, target ? null
, enableStatic ? false
, enableShared ? true
}:

with stdenv.lib;

let blas64_ = blas64; in

let
  setTarget = x: if target == null then x else target;

  # To add support for a new platform, add an element to this set.
  configs = {
    armv6l-linux = {
      BINARY = 32;
      TARGET = setTarget "ARMV6";
      DYNAMIC_ARCH = false;
      USE_OPENMP = true;
    };

    armv7l-linux = {
      BINARY = 32;
      TARGET = setTarget "ARMV7";
      DYNAMIC_ARCH = false;
      USE_OPENMP = true;
    };

    aarch64-linux = {
      BINARY = 64;
      TARGET = setTarget "ARMV8";
      DYNAMIC_ARCH = true;
      USE_OPENMP = true;
    };

    i686-linux = {
      BINARY = 32;
      TARGET = setTarget "P2";
      DYNAMIC_ARCH = true;
      USE_OPENMP = true;
    };

    x86_64-darwin = {
      BINARY = 64;
      TARGET = setTarget "ATHLON";
      DYNAMIC_ARCH = true;
      USE_OPENMP = false;
      MACOSX_DEPLOYMENT_TARGET = "10.7";
    };

    x86_64-linux = {
      BINARY = 64;
      TARGET = setTarget "ATHLON";
      DYNAMIC_ARCH = true;
      NO_AVX512 = true;
      USE_OPENMP = !stdenv.hostPlatform.isMusl;
    };
  };
in

let
  config =
    configs.${stdenv.hostPlatform.system}
    or (throw "unsupported system: ${stdenv.hostPlatform.system}");
in

let
  blas64 =
    if blas64_ != null
      then blas64_
      else hasPrefix "x86_64" stdenv.hostPlatform.system;
  # Convert flag values to format OpenBLAS's build expects.
  # `toString` is almost what we need other than bools,
  # which we need to map {true -> 1, false -> 0}
  # (`toString` produces empty string `""` for false instead of `0`)
  mkMakeFlagValue = val:
    if !builtins.isBool val then toString val
    else if val then "1" else "0";
  mkMakeFlagsFromConfig = mapAttrsToList (var: val: "${var}=${mkMakeFlagValue val}");
in
stdenv.mkDerivation rec {
  pname = "openblas";
  version = "0.3.8";
  src = fetchFromGitHub {
    owner = "xianyi";
    repo = "OpenBLAS";
    rev = "v${version}";
    sha256 = "0s017qqi4n6jzrxl9cyx625wj26smnyn5g8s699s7h8v1srlrw6p";
  };

  inherit blas64;

  # Some hardening features are disabled due to sporadic failures in
  # OpenBLAS-based programs. The problem may not be with OpenBLAS itself, but
  # with how these flags interact with hardening measures used downstream.
  # In either case, OpenBLAS must only be used by trusted code--it is
  # inherently unsuitable for security-conscious applications--so there should
  # be no objection to disabling these hardening measures.
  hardeningDisable = [
    # don't modify or move the stack
    "stackprotector" "pic"
    # don't alter index arithmetic
    "strictoverflow"
    # don't interfere with dynamic target detection
    "relro" "bindnow"
  ];

  nativeBuildInputs = [
    perl
    which
  ];

  depsBuildBuild = [
    buildPackages.gfortran
    buildPackages.stdenv.cc
  ];

  makeFlags = mkMakeFlagsFromConfig (config // {
    FC = "${stdenv.cc.targetPrefix}gfortran";
    CC = "${stdenv.cc.targetPrefix}${if stdenv.cc.isClang then "clang" else "cc"}";
    PREFIX = placeholder "out";
    NUM_THREADS = 64;
    INTERFACE64 = blas64;
    NO_STATIC = !enableStatic;
    NO_SHARED = !enableShared;
    CROSS = stdenv.hostPlatform != stdenv.buildPlatform;
    HOSTCC = "cc";
    # Makefile.system only checks defined status
    # This seems to be a bug in the openblas Makefile:
    # on x86_64 it expects NO_BINARY_MODE=
    # but on aarch64 it expects NO_BINARY_MODE=0
    NO_BINARY_MODE = if stdenv.isx86_64
        then toString (stdenv.hostPlatform != stdenv.buildPlatform)
        else stdenv.hostPlatform != stdenv.buildPlatform;
  });

  doCheck = true;
  checkTarget = "tests";

  postInstall = ''
    # Write pkgconfig aliases. Upstream report:
    # https://github.com/xianyi/OpenBLAS/issues/1740
    for alias in blas cblas lapack; do
      cat <<EOF > $out/lib/pkgconfig/$alias.pc
Name: $alias
Version: ${version}
Description: $alias provided by the OpenBLAS package.
Cflags: -I$out/include
Libs: -L$out/lib -lopenblas
EOF
    done
  '';

  meta = with stdenv.lib; {
    description = "Basic Linear Algebra Subprograms";
    license = licenses.bsd3;
    homepage = https://github.com/xianyi/OpenBLAS;
    platforms = platforms.unix;
    maintainers = with maintainers; [ ttuegel ];
  };

  # We use linkName to pass a different name to --with-blas-libs for
  # fflas-ffpack and linbox, because we use blas on darwin but openblas
  # elsewhere.
  # See see https://github.com/NixOS/nixpkgs/pull/45013.
  passthru.linkName = "openblas";
}