forked from TravisWhitaker/nix-quartus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgeneric.nix
453 lines (408 loc) · 19 KB
/
generic.nix
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
{ stdenv, fetchurl, utillinux, file, bash, glibc, pkgsi686Linux, writeScript
, nukeReferences, glibcLocales, libfaketime, coreutils, gnugrep, gnused, proot
# Runtime dependencies
, zlib, glib, libpng12, freetype, libSM, libICE, libXrender, fontconfig
, libXext, libX11, libXtst, gtk2, bzip2, libelf
}:
{ baseName
, prettyName ? baseName
, version
, components ? []
, updateComponents ? []
# Set to true for the old installers that are 32-bit only
, is32bitPackage ? false
# There are .so files inside .jar files bundled with Quartus that lack RPATH
# directives. This breaks starting e.g. eclipse-nios2:
#
# java.lang.UnsatisfiedLinkError: Could not load SWT library. Reasons:
# $HOME/.altera.sbt4e/16.1.0.196-linux64/configuration/org.eclipse.osgi/bundles/404/1/.cp/libswt-pi-gtk-4335.so: libXtst.so.6: cannot open shared object file: No such file or directory
# no swt-pi-gtk in java.library.path
# $HOME/.swt/lib/linux/x86_64/libswt-pi-gtk-4335.so: libXtst.so.6: cannot open shared object file: No such file or directory
# Can't load library: $HOME/.swt/lib/linux/x86_64/libswt-pi-gtk.so
#
# Although we _could_ fixup these .so files that live inside .jar files (or
# find all java interpreters and specify "-Djava.library.path=" on their
# command line), I don't think it's worth it. Quartus *itself* sets
# LD_LIBRARY_PATH, thus breaking spawning firefox from it, so I see no reason
# we shouldn't be equally lazy.
, wrapWithLdLibraryPath ? true
}:
let
# Somewhere between NixOS 16.09 and 17.03 (for instance, commit 9e6eec201b)
# the glibc attribute lacked $out/lib{,64}. The glibc_lib attribute below
# helped when bisecting build issues between 16.03 and 17.03.
glibc_lib =
if glibc ? out then glibc.out else glibc;
glibc_lib32 =
if pkgsi686Linux.glibc ? out then pkgsi686Linux.glibc.out else pkgsi686Linux.glibc;
# Using glibc>=2.25 causes the Quartus*Setup*run installer to hang.
# Use 2.24 instead.
commonGlibcAttrs224 = rec {
name = "glibc-${version}";
version = "2.24";
src = fetchurl {
url = "http://ftpmirror.gnu.org/glibc/${name}.tar.xz";
sha256 = "1lxmprg9gm73gvafxd503x70z32phwjzcy74i0adfi6ixzla7m4r";
};
};
# Backport upstream patch to fix build against nixpkgs-18.09.
glibc_lib_for_installer = glibc_lib.overrideAttrs (oldAttrs:
commonGlibcAttrs224 // { patches = [ ./patches/glibc/0001-Avoid-.symver-on-common-symbols-BZ-21666.patch ]; }
);
glibc_lib32_for_installer = glibc_lib32.overrideAttrs (oldAttrs:
commonGlibcAttrs224 // { patches = [ ./patches/glibc/0001-Avoid-.symver-on-common-symbols-BZ-21666.patch ]; }
);
# Keep in sync with runtimeLibPath64
# (with pkgsi686Linux; [ .. ] doesn't bind strongly enough.)
runtimeLibPath32 =
stdenv.lib.makeLibraryPath
[ pkgsi686Linux.zlib pkgsi686Linux.glib pkgsi686Linux.libpng12
pkgsi686Linux.freetype pkgsi686Linux.xorg.libSM pkgsi686Linux.xorg.libICE
pkgsi686Linux.xorg.libXrender pkgsi686Linux.fontconfig.lib
pkgsi686Linux.xorg.libXext pkgsi686Linux.xorg.libX11 pkgsi686Linux.xorg.libXtst
pkgsi686Linux.gtk2 pkgsi686Linux.bzip2.out pkgsi686Linux.libelf
pkgsi686Linux.stdenv.cc.cc.lib
];
# Keep in sync with runtimeLibPath32
runtimeLibPath64 =
stdenv.lib.makeLibraryPath
[ zlib glib libpng12 freetype libSM libICE libXrender fontconfig.lib
libXext libX11 libXtst gtk2 bzip2.out libelf
stdenv.cc.cc.lib
];
runtimeLibPath =
if is32bitPackage then runtimeLibPath32 else runtimeLibPath64;
runtimeBinPath = stdenv.lib.makeBinPath
[ coreutils gnugrep gnused glibc proot ];
setup-chroot-and-exec = writeScript "setup-chroot-and-exec"
(''
#!${bash}/bin/sh
chrootdir=chroot # relative to the current directory
mkdir -p "$chrootdir"/host
mkdir -p "$chrootdir"/proc
mkdir -p "$chrootdir"/nix
mkdir -p "$chrootdir"/tmp
mkdir -p "$chrootdir"/dev
mkdir -p "$chrootdir"/lib
mkdir -p "$chrootdir"/lib64
mkdir -p "$chrootdir"/bin
${utillinux}/bin/mount --rbind / "$chrootdir"/host
${utillinux}/bin/mount --rbind /proc "$chrootdir"/proc
${utillinux}/bin/mount --rbind /nix "$chrootdir"/nix
${utillinux}/bin/mount --rbind /tmp "$chrootdir"/tmp
${utillinux}/bin/mount --rbind /dev "$chrootdir"/dev
'' + (if is32bitPackage then ''
${utillinux}/bin/mount --rbind "${glibc_lib32_for_installer}"/lib "$chrootdir"/lib
'' else ''
${utillinux}/bin/mount --rbind "${glibc_lib_for_installer}"/lib64 "$chrootdir"/lib64
'') + ''
${utillinux}/bin/mount --rbind "${bash}"/bin "$chrootdir"/bin
chroot "$chrootdir" "$@"
'');
# buildFHSUserEnv from nixpkgs tries to mount a few directories that are not
# available in sandboxed Nix builds (/sys, /run), hence we have our own
# slimmed down variant.
run-in-fhs-env = writeScript "run-in-fhs-env"
''
#!${bash}/bin/sh
if [ "$*" = "" ]; then
echo "Usage: run-in-fhs-env <COMMAND> [ARGS...]"
exit 1
fi
"${utillinux}/bin/unshare" -r -U -m "${setup-chroot-and-exec}" "$@"
'';
mkInstallersDir = srcs:
stdenv.mkDerivation rec {
name = "${baseName}-installers";
inherit srcs version;
buildCommand =
''
# The files are copied, not symlinked, because
# - We must add execute bit to *.run files
# - Quartus*Setup*.run fails to use the *.qdz files if they are symlinks.
# Example error message (which doesn't abort the installer!):
# Error copying file from /nix/store/HASH1-altera-quartus-prime-lite-installers-16.1.0.196/cyclonev-16.1.0.196.qdz/cyclonev-16.1.0.196.qdz to /nix/store/HASH2-altera-quartus-prime-lite-16.1.0.196/cyclonev-16.1.0.196.qdz:
# /nix/store/HASH1-altera-quartus-prime-lite-installers-16.1.0.196/cyclonev-16.1.0.196.qdz/cyclonev-16.1.0.196.qdz does not exist
# Abort
# Unable to copy file
set -x
mkdir -p "$out"
${stdenv.lib.concatStringsSep "\n"
(map
(p: ''
cp "${p}" "$out/$(stripHash "${p}")"
'')
srcs
)
}
for f in $out/*run; do
[ -e "$f" ] && chmod +x "$f"
done
'';
};
componentInstallers = mkInstallersDir components;
updateComponentInstallers = mkInstallersDir updateComponents;
quartusUnwrapped = stdenv.mkDerivation rec {
name = "${baseName}-unwrapped-${version}";
inherit version;
# srcs is for keeping track of inputs used for the build.
srcs = components ++ updateComponents;
buildInputs = [ file nukeReferences ];
# Fix this:
# /nix/store/...-altera-quartus-ii-web-13.1.4.182/quartus/adm/qenv.sh: line 83: \
# warning: setlocale: LC_CTYPE: cannot change locale (en_US.UTF-8): No such file or directory
LOCALE_ARCHIVE = "${glibcLocales}/lib/locale/locale-archive";
# Prebuilt binaries need special treatment
dontStrip = true;
dontPatchELF = true;
# Fix "RPATH of binary X contains a forbidden reference to /build" issue.
# (These are prebuilt binaries, not much we can do.)
noAuditTmpdir = true;
configurePhase = "true";
buildPhase = "true";
unpackPhase = "true";
# Quartus' setup.sh (from the all-in-one-installers) doesn't fit our needs
# (we want automatic and distro-agnostic install), so call the actual setup
# program directly instead.
#
# Quartus*Setup*.run files are statically linked ELF executables that run
# open("/lib64/ld-linux-x86-64.so.2", ...) (or "/lib/ld-linux.so.2" for
# 32-bit versions) . That obviously doesn't work in sandboxed Nix builds.
#
# Things that do not work:
# * patchelf the installer (there is no .interp section in static ELF)
# * dynamic linker tricks (again, static ELF)
# * proot (the installer somehow detects something is wrong and aborts)
#
# We need bigger guns: user namespaces and chroot. That's how we make /lib64/
# available to the installer. The installer installs dynamically linked ELF
# files, so those we can fixup with usual tools.
#
# For runtime, injecting (or wrapping with) LD_LIBRARY_PATH is easier, but it
# messes with the environment for all child processes. We take the less
# invasive approach here, patchelf + RPATH. Unfortunately, Quartus itself
# uses LD_LIBRARY_PATH in its wrapper scripts. This cause e.g. firefox to
# fail due to LD_LIBRARY_PATH pulling in wrong libraries for it (happens if
# clicking any URL in Quartus).
installPhase = ''
set -x
run_quartus_installer()
{
installer="$1"
if [ ! -x "$installer" ]; then
echo "ERROR: \"$installer\" either doesn't exist or is not executable"
exit 1
fi
maybe_accept_eula="${if stdenv.lib.versionAtLeast version "17.1" then "--accept_eula 1" else ""}"
echo "### ${run-in-fhs-env} $installer --mode unattended --installdir $out" $maybe_accept_eula
"${run-in-fhs-env}" "$installer" --mode unattended --installdir "$out" $maybe_accept_eula
echo "...done"
}
echo "Running Quartus Setup (in FHS sandbox)..."
run_quartus_installer "$(echo "${componentInstallers}"/Quartus*Setup*)"
${stdenv.lib.optionalString (updateComponents != []) ''
echo "Running Quartus Update (in FHS sandbox)..."
run_quartus_installer "$(echo "${updateComponentInstallers}"/Quartus*Setup*)"
''}
echo "Removing unneeded \"uninstall\" binaries (saves $(du -sh "$out"/uninstall | cut -f1))"
rm -rf "$out"/uninstall
echo "Prevent retaining a runtime dependency on the installer binaries (saves $(du -sh "${componentInstallers}" | cut -f1) + $(du -sh "${updateComponentInstallers}" | cut -f1))"
nuke-refs "$out/logs/"*
echo "Fixing ELF interpreter paths with patchelf"
find "$out" -type f | while read f; do
case "$f" in
*.debug) continue;;
esac
# A few files are read-only. Make them writeable for patchelf. (Nix
# will make all files read-only after the build.)
chmod +w "$f"
magic=$(file "$f") || { echo "file \"$f\" failed"; exit 1; }
case "$magic" in
*ELF*dynamically\ linked*)
orig_rpath=$(patchelf --print-rpath "$f") || { echo "FAILED: patchelf --print-rpath $f"; exit 1; }
# Take care not to add ':' at start or end of RPATH, because
# that is the same as '.' (current directory), and that's
# insecure.
if [ "$orig_rpath" != "" ]; then
orig_rpath="$orig_rpath:"
fi
new_rpath="$orig_rpath${runtimeLibPath}"
case "$magic" in
*ELF*pie\ executable*|*ELF*shared\ object*x86-64*)
patchelf --set-rpath "$new_rpath" "$f" || { echo "FAILED: patchelf --set-rpath $f"; exit 1; }
;;
*ELF*executable*)
interp=$(patchelf --print-interpreter "$f") || { echo "FAILED: patchelf --print-interpreter $f"; exit 1; }
# Note the LSB interpreters, required by some files
case "$interp" in
/lib64/ld-linux-x86-64.so.2|/lib64/ld-lsb-x86-64.so.3)
new_interp=$(cat "$NIX_CC"/nix-support/dynamic-linker)
;;
/lib/ld-linux.so.2|/lib/ld-lsb.so.3)
new_interp="${glibc_lib32}/lib/ld-linux.so.2"
;;
/lib/ld-linux-armhf.so.3|/lib64/ld64.so.1|/lib64/ld64.so.2)
# Ignore ARM/ppc64/ppc64le executables, they
# are not meant to be run on the build machine.
# Example files:
# altera-quartus-prime-lite-15.1.0.185/hld/host/arm32/bin/aocl-binedit
# altera-quartus-prime-lite-15.1.0.185/hld/host/ppc64/bin/aocl-binedit
# altera-quartus-prime-lite-15.1.0.185/hld/host/ppc64le/bin/aocl-binedit
continue
;;
/usr/lib/ld.so.1)
echo "Unclear if this will work?"
new_interp="${glibc_lib32}/lib/ld-linux.so.2"
;;
*)
echo "FIXME: unhandled interpreter \"$interp\" in $f"
exit 1
;;
esac
test -f "$new_interp" || { echo "$new_interp is missing"; exit 1; }
patchelf --set-interpreter "$new_interp" \
--set-rpath "$new_rpath" "$f" || { echo "FAILED: patchelf --set-interpreter $new_interp --set-rpath $new_rpath $f"; exit 1; }
;;
esac
;;
*ELF*statically\ linked*)
echo "WARN: $f is statically linked. Needs fixup?"
;;
esac
done
# Modelsim is optional
f="$out"/modelsim_ase/vco
if [ -f "$f" ]; then
echo "Fix hardcoded \"/bin/ls\" in .../modelsim_ase/vco"
sed -i -e "s,/bin/ls,ls," "$f"
echo "Fix support for Linux 4.x in .../modelsim_ase/vco"
sed -i -e "/case \$utype in/a 4.[0-9]*) vco=\"linux\" ;;" "$f"
fi
'';
};
in
stdenv.mkDerivation rec {
name = "${baseName}-${version}";
# version and srcs are unused by this derivation, but keep them as metadata
# (for users).
inherit (quartusUnwrapped) version srcs;
buildCommand = ''
set -x
# Provide convenience wrappers in $out/bin, so that the tools can be
# started directly from PATH. Plain symlinks don't work, due to assumptions
# of resources relative to arg0.
wrap()
{
dest="$out/bin/$(basename "$1")"
if [ -f "$dest" ]; then
echo "ERROR: $dest already exist"
exit 1
fi
cat > "$dest" << EOF
#!${bash}/bin/sh
# Some tools seem to forget sourcing their environment setup file (e.g
# elf2hex), so help them by setting QUARTUS_ROOTDIR (and *OVERRIDE).
# (Perhaps these tools were never tested _not_ being started from Quartus
# IDE?)
export QUARTUS_ROOTDIR="${quartusUnwrapped}/quartus"
export QUARTUS_ROOTDIR_OVERRIDE="\$QUARTUS_ROOTDIR"
# To prevent e.g. "alt-file-convert" from aborting due to not being able to
# write to __pycache__ in the (read-only) nix store.
export PYTHONDONTWRITEBYTECODE=1
${stdenv.lib.optionalString wrapWithLdLibraryPath ''
if [ "x\$LD_LIBRARY_PATH" != x ]; then
export LD_LIBRARY_PATH="${runtimeLibPath}:\$LD_LIBRARY_PATH"
else
export LD_LIBRARY_PATH="${runtimeLibPath}"
fi
''}
# Inject path to known tools. This is important not only for having a
# complete package (all deps), but also to ensure that LD_PRELOAD etc.
# won't break the CLI tools. (Think non-NixOS setups.)
export PATH="${runtimeBinPath}:\$PATH"
# Check if we need to isolate ourself from /bin/sh. This is to work around
# a long standing bug in nixpkgs that glibc system() calls /bin/sh. The
# reasoning behind the test is that Nix tools don't depend on things in
# /lib. The test should be positive only on non-sandboxed, non-NixOS builds.
bin_sh_is_clean=1
if ldd /bin/sh | grep -q "^\s*/lib"; then
bin_sh_is_clean=0
fi
# Implement the SOURCE_DATE_EPOCH specification, for reproducible builds:
# https://reproducible-builds.org/specs/source-date-epoch
if [ "x\$SOURCE_DATE_EPOCH" != x ]; then
# Create a minimal "sandbox" with proot, or else programs running
# /bin/sh will fail because we're setting LD_PRELOAD etc.
if [ \$bin_sh_is_clean -eq 0 ]; then
maybe_proot_cmd="proot -b ${bash}/bin/sh:/bin/sh"
# Work around bug with linux 4.8.4+ (costs some performance, but
# prevents breakage).
export PROOT_NO_SECCOMP=1
fi
# Prepare LD_LIBRARY_PATH, LD_PRELOAD
if [ "x\$LD_LIBRARY_PATH" != x ]; then
export LD_LIBRARY_PATH="${libfaketime}/lib:\$LD_LIBRARY_PATH"
else
export LD_LIBRARY_PATH="${libfaketime}/lib"
fi
if [ "x${toString is32bitPackage}" = "x${toString true}" ]; then
export LD_LIBRARY_PATH="${pkgsi686Linux.libfaketime}/lib:\$LD_LIBRARY_PATH"
fi
if [ "x\$LD_PRELOAD" != x ]; then
export LD_PRELOAD="libfaketime.so.1:\$LD_PRELOAD"
else
export LD_PRELOAD=libfaketime.so.1
fi
# Set the time to SOURCE_DATE_EPOCH
export FAKETIME_FMT="%s"
export FAKETIME=\$(date +%s -d @\$SOURCE_DATE_EPOCH)
fi
# Fix this:
# /nix/store/...-altera-quartus-ii-web-13.1.4.182/quartus/adm/qenv.sh: line 83: \
# warning: setlocale: LC_CTYPE: cannot change locale (en_US.UTF-8): No such file or directory
export LOCALE_ARCHIVE="${glibcLocales}/lib/locale/locale-archive"
exec \$maybe_proot_cmd "$1" "\$@"
EOF
chmod +x "$dest"
}
echo "Creating top-level bin/ directory with wrappers for common tools"
mkdir -p "$out/bin"
for p in "${quartusUnwrapped}/"*"/bin/"*; do
test -f "$p" || continue
wrap "$p"
done
echo "Installing Desktop file..."
mkdir -p "$out/share/applications"
f="$out"/share/applications/quartus.desktop
cat >> "$f" << EOF
[Desktop Entry]
Type=Application
Name=${prettyName} ${version}
Comment=${prettyName} ${version}
Icon=${quartusUnwrapped}/quartus/adm/quartusii.png
Exec=$out/bin/quartus
Terminal=false
Path=$out
EOF
# udev rules based on
# https://www.intel.com/content/www/us/en/programmable/support/support-resources/download/drivers/dri-usb_b-lnx.html
echo "Installing udev rules"
mkdir -p "$out/lib/udev/rules.d"
cat > "$out/lib/udev/rules.d/51-usbblaster.rules" << EOF
# USB-Blaster / Intel FPGA Download Cable
SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6001", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6002", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6003", MODE="0666"
# USB-Blaster II / Intel FPGA Download Cable II
SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6010", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="09fb", ATTR{idProduct}=="6810", MODE="0666"
EOF
'';
meta = with stdenv.lib; {
description = "Development tools for Altera FPGA, CPLD and SoC designs";
homepage = https://www.altera.com/;
license = licenses.unfree;
platforms = [ "x86_64-linux" ];
maintainers = [ maintainers.bjornfor ];
};
}