Skip to content

Commit 8abd908

Browse files
committed
Update flake.nix
1 parent aaeaefc commit 8abd908

1 file changed

Lines changed: 108 additions & 11 deletions

File tree

flake.nix

Lines changed: 108 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
];
2626
};
2727

28-
# Build ArrayFire from the official binary installer; avoids freeimage entirely.
29-
mkArrayfire = pkgs: pkgs.stdenv.mkDerivation rec {
28+
# Build ArrayFire from the official Linux binary installer; avoids freeimage entirely.
29+
mkArrayfireLinux = pkgs: pkgs.stdenv.mkDerivation rec {
3030
pname = "arrayfire";
3131
version = "3.10.0";
3232
src = pkgs.fetchurl {
@@ -56,6 +56,77 @@
5656
};
5757
};
5858

59+
# Build ArrayFire on macOS from the official .pkg installer. ArrayFire has not
60+
# shipped a macOS binary since 3.8.2 (x86_64 only), so darwin pins that version.
61+
# The .pkg is a xar archive of component sub-packages, each carrying a
62+
# gzip+cpio Payload that installs under opt/arrayfire/{include,lib}.
63+
mkArrayfireDarwin = pkgs: pkgs.stdenv.mkDerivation rec {
64+
pname = "arrayfire";
65+
version = "3.8.2";
66+
src = pkgs.fetchurl {
67+
url = "https://arrayfire.s3.amazonaws.com/${version}/ArrayFire-${version}_OSX_x86_64.pkg";
68+
hash = "sha256-MDqpDONbzl+PNu2VS1UTaYL10fpzpt0pv10oxNwgm+k=";
69+
};
70+
nativeBuildInputs = with pkgs; [ xar cpio fixDarwinDylibNames ];
71+
# Never strip the prebuilt vendor dylibs: the default strip phase corrupts
72+
# them (it silently truncated libmkl_core.dylib to 0 bytes, which then made
73+
# MKL fail to load its computational layer at runtime).
74+
dontStrip = true;
75+
unpackPhase = ''
76+
runHook preUnpack
77+
xar -xf $src
78+
runHook postUnpack
79+
'';
80+
# Extract every component Payload (except the heavy CUDA/OpenCL/examples ones
81+
# we don't ship) into a staging tree, then install only the unified + CPU
82+
# backends and their bundled runtime deps (MKL, TBB, forge).
83+
installPhase = ''
84+
runHook preInstall
85+
mkdir -p stage
86+
for comp in ArrayFire-${version}-Darwin-*.pkg; do
87+
case "$comp" in
88+
*cuda*|*opencl*|*examples*|*documentation*) continue ;;
89+
esac
90+
[ -f "$comp/Payload" ] || continue
91+
( cd stage && gzip -dc "../$comp/Payload" | cpio -id --quiet )
92+
done
93+
94+
mkdir -p $out/lib
95+
cp -R stage/opt/arrayfire/include $out/include
96+
for pat in 'libaf.*' 'libafcpu.*' 'libforge.*' 'libmkl_*.dylib' \
97+
'libtbb*.dylib' 'libiomp*.dylib'; do
98+
cp -P stage/opt/arrayfire/lib/$pat $out/lib/ 2>/dev/null || true
99+
done
100+
runHook postInstall
101+
'';
102+
# fixDarwinDylibNames (run in fixupPhase) rewrites the @rpath install ids
103+
# and matching inter-library references to absolute store paths. It only
104+
# rewrites references whose leaf matches a sibling's *original* id, so it
105+
# misses cases where the ids differ, e.g. libafcpu -> @rpath/libmkl_rt and
106+
# libmkl_tbb_thread -> @rpath/libtbb (the latter is dlopen'd by MKL's
107+
# libmkl_rt and would otherwise fail to load at runtime). Re-point any
108+
# remaining @rpath/<leaf> dep at $out/lib/<leaf> so everything is hermetic.
109+
postFixup = ''
110+
for dylib in $out/lib/*.dylib; do
111+
for dep in $(otool -L "$dylib" | awk 'NR>1{print $1}' | grep '^@rpath/' || true); do
112+
leaf=''${dep#@rpath/}
113+
if [ -e "$out/lib/$leaf" ]; then
114+
install_name_tool -change "$dep" "$out/lib/$leaf" "$dylib"
115+
fi
116+
done
117+
done
118+
'';
119+
meta = {
120+
description = "A general-purpose library for parallel and massively-parallel architectures";
121+
platforms = [ "x86_64-darwin" ];
122+
};
123+
};
124+
125+
mkArrayfire = pkgs:
126+
if pkgs.stdenv.isDarwin
127+
then mkArrayfireDarwin pkgs
128+
else mkArrayfireLinux pkgs;
129+
59130
arrayfire-overlay = self: super: {
60131
arrayfire = mkArrayfire self;
61132
};
@@ -65,11 +136,26 @@
65136
haskell = super.haskell // {
66137
packageOverrides = inputs.nixpkgs.lib.composeExtensions super.haskell.packageOverrides
67138
(hself: hsuper: {
68-
arrayfire = self.haskell.lib.appendConfigureFlags
69-
(hself.callCabal2nix "arrayfire" src {
70-
af = self.arrayfire;
71-
})
72-
[ "-f disable-default-paths" ];
139+
arrayfire =
140+
let
141+
pkg = self.haskell.lib.appendConfigureFlags
142+
(hself.callCabal2nix "arrayfire" src {
143+
af = self.arrayfire;
144+
})
145+
[ "-f disable-default-paths" ];
146+
in
147+
# On macOS ArrayFire's bundled MKL dlopens its threading layer
148+
# (libmkl_tbb_thread.dylib) by bare leaf name, which dyld only
149+
# resolves via DYLD_LIBRARY_PATH. Point it at the arrayfire libs
150+
# so the test suite (and doctests) can run. Runtime consumers of
151+
# this package need the same DYLD_LIBRARY_PATH.
152+
if self.stdenv.isDarwin
153+
then pkg.overrideAttrs (old: {
154+
preCheck = (old.preCheck or "") + ''
155+
export DYLD_LIBRARY_PATH="${self.arrayfire}/lib''${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"
156+
'';
157+
})
158+
else pkg;
73159
});
74160
};
75161
};
@@ -79,9 +165,12 @@
79165
ps = pkgs.haskellPackages;
80166
isLinux = pkgs.stdenv.isLinux;
81167
isDarwin = pkgs.stdenv.isDarwin;
168+
# ArrayFire only ships an x86_64 macOS binary, so it's unavailable on
169+
# Apple Silicon; fall back to a plain shell there.
170+
hasArrayfire = isLinux || pkgs.stdenv.hostPlatform.system == "x86_64-darwin";
82171
in
83172
ps.shellFor {
84-
packages = ps: if isLinux then [ ps.arrayfire ] else [ ];
173+
packages = ps: if hasArrayfire then [ ps.arrayfire ] else [ ];
85174
withHoogle = true;
86175
buildInputs = with pkgs; (if isLinux then [ ocl-icd ] else [ darwin.apple_sdk.frameworks.Security ]);
87176
nativeBuildInputs = with pkgs; with ps; [
@@ -94,7 +183,10 @@
94183
# Formatters
95184
nixpkgs-fmt
96185
];
97-
shellHook = if isLinux then ''export LD_LIBRARY_PATH="${pkgs.arrayfire}/lib:$LD_LIBRARY_PATH"'' else "";
186+
shellHook =
187+
if isLinux then ''export LD_LIBRARY_PATH="${pkgs.arrayfire}/lib:$LD_LIBRARY_PATH"''
188+
else if hasArrayfire then ''export DYLD_LIBRARY_PATH="${pkgs.arrayfire}/lib:$DYLD_LIBRARY_PATH"''
189+
else "";
98190
};
99191

100192
pkgs-for = system: import inputs.nixpkgs {
@@ -107,8 +199,13 @@
107199
in
108200
{
109201
packages = inputs.flake-utils.lib.eachDefaultSystemMap (system:
110-
with (pkgs-for system); {
111-
default = haskellPackages.arrayfire;
202+
let
203+
pkgs = pkgs-for system;
204+
# ArrayFire only provides binaries for x86_64-linux and x86_64-darwin
205+
# (no Apple Silicon / aarch64), so only expose the package there.
206+
hasArrayfire = pkgs.stdenv.isLinux || system == "x86_64-darwin";
207+
in inputs.nixpkgs.lib.optionalAttrs hasArrayfire {
208+
default = pkgs.haskellPackages.arrayfire;
112209
});
113210

114211
devShells = inputs.flake-utils.lib.eachDefaultSystemMap (system: {

0 commit comments

Comments
 (0)