454 lines
19 KiB
Nix
454 lines
19 KiB
Nix
{ 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 ];
|
|
};
|
|
}
|