From dc09e3edfc4c1a4bf612cd2dcefd05096d8a9026 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Mon, 24 Aug 2020 11:08:20 +0200 Subject: [PATCH] nim: wrap compiler for cross-compilation support --- .../science/biology/mosdepth/default.nix | 3 +- .../compilers/nim/NIM_CONFIG_DIR.patch | 23 ++ pkgs/development/compilers/nim/default.nix | 300 ++++++++++++++---- pkgs/top-level/all-packages.nix | 2 + 4 files changed, 268 insertions(+), 60 deletions(-) create mode 100644 pkgs/development/compilers/nim/NIM_CONFIG_DIR.patch diff --git a/pkgs/applications/science/biology/mosdepth/default.nix b/pkgs/applications/science/biology/mosdepth/default.nix index 96aed307f0b..1ce6357d2e8 100644 --- a/pkgs/applications/science/biology/mosdepth/default.nix +++ b/pkgs/applications/science/biology/mosdepth/default.nix @@ -26,7 +26,8 @@ in stdenv.mkDerivation rec { sha256 = "01gm9gj2x2zs4yx6wk761fi1papi7qr3gp4ln1kkn8n2f9y9h849"; }; - buildInputs = [ nim htslib pcre ]; + nativeBuildInputs = [ nim ]; + buildInputs = [ htslib pcre ]; buildPhase = '' HOME=$TMPDIR diff --git a/pkgs/development/compilers/nim/NIM_CONFIG_DIR.patch b/pkgs/development/compilers/nim/NIM_CONFIG_DIR.patch new file mode 100644 index 00000000000..61e05b791cf --- /dev/null +++ b/pkgs/development/compilers/nim/NIM_CONFIG_DIR.patch @@ -0,0 +1,23 @@ +diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim +index a470179bd..73cfa1a23 100644 +--- a/compiler/nimconf.nim ++++ b/compiler/nimconf.nim +@@ -225,10 +225,15 @@ proc getUserConfigPath*(filename: RelativeFile): AbsoluteFile = + proc getSystemConfigPath*(conf: ConfigRef; filename: RelativeFile): AbsoluteFile = + # try standard configuration file (installation did not distribute files + # the UNIX way) +- let p = getPrefixDir(conf) +- result = p / RelativeDir"config" / filename ++ let ++ prefix = getPrefixDir(conf) ++ env = getEnv("NIM_CONFIG_PATH") ++ if env != "": ++ result = env.toAbsoluteDir / filename ++ else: ++ result = prefix / RelativeDir"config" / filename + when defined(unix): +- if not fileExists(result): result = p / RelativeDir"etc/nim" / filename ++ if not fileExists(result): result = prefix / RelativeDir"etc/nim" / filename + if not fileExists(result): result = AbsoluteDir"/etc/nim" / filename + + proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef) = diff --git a/pkgs/development/compilers/nim/default.nix b/pkgs/development/compilers/nim/default.nix index d497cc76e9b..8ac9f8e048c 100644 --- a/pkgs/development/compilers/nim/default.nix +++ b/pkgs/development/compilers/nim/default.nix @@ -1,73 +1,255 @@ -# based on https://github.com/nim-lang/Nim/blob/v0.18.0/.travis.yml +# https://nim-lang.github.io/Nim/packaging.html -{ stdenv, lib, fetchurl, makeWrapper, openssl, pcre, readline, - boehmgc, sfml, sqlite }: +{ stdenv, lib, fetchgit, fetchurl, makeWrapper, gdb, openssl, pcre, readline +, boehmgc, sqlite, nim-unwrapped, nim-stdlib, nim }: -stdenv.mkDerivation rec { - pname = "nim"; +let version = "1.2.6"; - src = fetchurl { - url = "https://nim-lang.org/download/${pname}-${version}.tar.xz"; + url = "https://nim-lang.org/download/nim-${version}.tar.xz"; sha256 = "0zk5qzxayqjw7kq6p92j4008g9bbyilyymhdc5xq9sln5rqym26z"; }; - enableParallelBuilding = true; - - NIX_LDFLAGS = "-lcrypto -lpcre -lreadline -lgc -lsqlite3"; - - # we could create a separate derivation for the "written in c" version of nim - # used for bootstrapping, but koch insists on moving the nim compiler around - # as part of building it, so it cannot be read-only - - nativeBuildInputs = [ - makeWrapper - ]; - - buildInputs = [ - openssl pcre readline boehmgc sfml sqlite - ]; - - patches = [ ./nixbuild.patch ]; - - postPatch = "echo define:nixbuild >> config/nim.cfg"; - - buildPhase = '' - runHook preBuild - - # build.sh wants to write to $HOME/.cache - HOME=$TMPDIR - sh build.sh - ./bin/nim c koch - ./koch boot -d:release \ - -d:useGnuReadline \ - ${lib.optionals (stdenv.isDarwin || stdenv.isLinux) "-d:nativeStacktrace"} - ./koch tools -d:release - - runHook postBuild - ''; + meta = with lib; { + description = "Statically typed, imperative programming language"; + homepage = "https://nim-lang.org/"; + license = licenses.mit; + maintainers = with maintainers; [ ehmry ]; + }; - installPhase = '' - runHook preInstall + parseCpu = platform: + with platform; + # Derive a Nim CPU identifier + if isAarch32 then + "arm" + else if isAarch64 then + "arm64" + else if isAlpha then + "alpha" + else if isAvr then + "avr" + else if isMips && is32bit then + "mips" + else if isMips && is64bit then + "mips64" + else if isMsp430 then + "msp430" + else if isPowerPC && is32bit then + "powerpc" + else if isPowerPC && is64bit then + "powerpc64" + else if isRiscV && is64bit then + "riscv64" + else if isSparc then + "sparc" + else if isx86_32 then + "i386" + else if isx86_64 then + "amd64" + else + abort "no Nim CPU support known for ${config}"; + + parseOs = platform: + with platform; + # Derive a Nim OS identifier + if isAndroid then + "Android" + else if isDarwin then + "MacOSX" + else if isFreeBSD then + "FreeBSD" + else if isGenode then + "Genode" + else if isLinux then + "Linux" + else if isNetBSD then + "NetBSD" + else if isNone then + "Standalone" + else if isOpenBSD then + "OpenBSD" + else if isWindows then + "Windows" + else if isiOS then + "iOS" + else + abort "no Nim OS support known for ${config}"; + + parsePlatform = p: { + cpu = parseCpu p; + os = parseOs p; + }; - install -Dt $out/bin bin/* koch - ./koch install $out - mv $out/nim/bin/* $out/bin/ && rmdir $out/nim/bin - mv $out/nim/* $out/ && rmdir $out/nim + nimHost = parsePlatform stdenv.hostPlatform; + nimTarget = parsePlatform stdenv.targetPlatform; + + wrapperInputs = rec { + + bootstrap = stdenv.mkDerivation rec { + pname = "nim-bootstrap"; + version = "0.20.0"; + + src = fetchgit { + # A Git checkout is much smaller than a GitHub tarball. + url = "https://github.com/nim-lang/csources.git"; + rev = "v" + version; + sha256 = "0i6vsfy1sgapx43n226q8m0pvn159sw2mhp50zm3hhb9zfijanis"; + }; + + enableParallelBuilding = true; + + installPhase = '' + runHook preInstall + install -Dt $out/bin bin/nim + runHook postInstall + ''; + }; + + unwrapped = stdenv.mkDerivation { + # https://nim-lang.github.io/Nim/packaging.html + pname = "nim-unwrapped"; + inherit version src; + + buildInputs = [ boehmgc openssl pcre readline sqlite ]; + + patches = [ + ./NIM_CONFIG_DIR.patch + # Override compiler configuration via an environmental variable + + ./nixbuild.patch + # Load libraries at runtime by absolute path + ]; + + configurePhase = '' + runHook preConfigure + cp ${bootstrap}/bin/nim bin/ + echo 'define:nixbuild' >> config/nim.cfg + runHook postConfigure + ''; + + kochArgs = [ + "--cpu:${nimHost.cpu}" + "--os:${nimHost.os}" + "-d:release" + "-d:useGnuReadline" + ] ++ lib.optional (stdenv.isDarwin || stdenv.isLinux) + "-d:nativeStacktrace"; + + buildPhase = '' + runHook preBuild + local HOME=$TMPDIR + ./bin/nim c koch + ./koch boot $kochArgs --parallelBuild:$NIX_BUILD_CORES + ./koch tools $kochArgs --parallelBuild:$NIX_BUILD_CORES + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + install -Dt $out/bin bin/* + runHook postInstall + ''; + + inherit meta; + }; + + stdlib = stdenv.mkDerivation { + pname = "nim-stdlib"; + inherit (nim-unwrapped) version src patches; + + dontConfigure = true; + dontBuild = true; + + installPhase = '' + runHook preInstall + touch bin/nim + ./install.sh $TMPDIR + cp -r $TMPDIR/nim/lib $out + runHook postInstall + ''; + + meta = meta // { + description = meta.description + " (standard library)"; + }; + }; + }; + wrapped = let + nim = nim-unwrapped; + inherit (stdenv) targetPlatform; + in stdenv.mkDerivation { + name = "${targetPlatform.config}-nim-wrapper-${nim.version}"; + inherit (nim) version; + preferLocalBuild = true; + + nativeBuildInputs = [ makeWrapper ]; + + unpackPhase = '' + runHook preUnpack + tar xf ${nim.src} nim-$version/config/nim.cfg + cd nim-$version + runHook postUnpack + ''; + + dontConfigure = true; + + wrapperArgs = [ + "--prefix PATH : ${lib.makeBinPath [ stdenv.cc gdb ]}:${ + placeholder "out" + }/bin" + "--prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath [ stdenv.cc.libc openssl ]}" + "--set NIM_CONFIG_PATH ${placeholder "out"}/etc/nim" + ]; + + buildPhase = with stdenv; + let + ccType = if cc.isGNU then + "gcc" + else if cc.isClang then + "clang" + else + abort "no Nim configuration available for ${cc.name}"; + in '' + runHook preBuild + cat >> config/nim.cfg << EOF + + define:nixbuild + os = ${nimTarget.os} + cpu = ${nimTarget.cpu} + cc = ${ccType} + EOF + + mkdir -p $out/bin $out/etc/nim + export cc=$CC + export cxx=$CXX + substituteAll config/nim.cfg $out/etc/nim/nim.cfg \ + --replace "cc = gcc" "" + + for binpath in ${nim}/bin/nim?*; do + local binname=`basename $binpath` + makeWrapper $binpath $out/bin/${targetPlatform.config}-$binname \ + $wrapperArgs + ln -s $out/bin/${targetPlatform.config}-$binname $out/bin/$binname + done + + makeWrapper ${nim}/bin/nim $out/bin/${targetPlatform.config}-nim \ + $wrapperArgs \ + --set NIX_HARDENING_ENABLE "''${NIX_HARDENING_ENABLE/fortify}" \ + --add-flags --lib:${nim-stdlib} + ln -s $out/bin/${targetPlatform.config}-nim $out/bin/nim + + runHook postBuild + ''; # Fortify hardening appends -O2 to gcc flags which is unwanted for unoptimized nim builds. - wrapProgram $out/bin/nim \ - --run 'NIX_HARDENING_ENABLE=''${NIX_HARDENING_ENABLE/fortify/}' \ - --suffix PATH : ${lib.makeBinPath [ stdenv.cc ]} - runHook postInstall - ''; + dontInstall = true; + + meta = meta // { + description = nim.meta.description + + " (${targetPlatform.config} wrapper)"; + platforms = lib.platforms.unix; + }; - meta = with stdenv.lib; { - description = "Statically typed, imperative programming language"; - homepage = "https://nim-lang.org/"; - license = licenses.mit; - maintainers = with maintainers; [ ehmry ]; - platforms = with platforms; linux ++ darwin; # arbitrary }; -} + +in wrapped // wrapperInputs diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index bc1c16f474a..e8de40a13e7 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -9445,6 +9445,8 @@ in mozart2-binary = callPackage ../development/compilers/mozart/binary.nix { }; nim = callPackage ../development/compilers/nim { }; + nim-unwrapped = nim.unwrapped; + nim-stdlib = nim.stdlib; nrpl = callPackage ../development/tools/nrpl { }; neko = callPackage ../development/compilers/neko { };