|
| 1 | +# To be used as an overlay |
| 2 | +(final: prev: { |
| 3 | + R = |
| 4 | + let |
| 5 | + inherit (final) |
| 6 | + lib |
| 7 | + stdenv |
| 8 | + stdenvNoCC |
| 9 | + fetchurl |
| 10 | + blas |
| 11 | + bzip2 |
| 12 | + curlMinimal |
| 13 | + gfortran |
| 14 | + lapack |
| 15 | + ncurses |
| 16 | + pcre2 |
| 17 | + readline |
| 18 | + removeReferencesTo |
| 19 | + runCommand |
| 20 | + tzdata |
| 21 | + which |
| 22 | + xz |
| 23 | + zlib |
| 24 | + ; |
| 25 | + in |
| 26 | + prev.R.overrideAttrs { |
| 27 | + buildInputs = [ |
| 28 | + blas |
| 29 | + bzip2 |
| 30 | + gfortran |
| 31 | + lapack |
| 32 | + ncurses |
| 33 | + pcre2 |
| 34 | + readline |
| 35 | + which |
| 36 | + xz |
| 37 | + zlib |
| 38 | + ]; |
| 39 | + |
| 40 | + nativeBuildInputs = prev.R.nativeBuildInputs ++ [ removeReferencesTo ]; |
| 41 | + |
| 42 | + preConfigure = '' |
| 43 | + configureFlagsArray=( |
| 44 | + --disable-lto |
| 45 | + --without-recommended-packages |
| 46 | + --with-blas="-L${blas}/lib -lblas" |
| 47 | + --with-lapack="-L${lapack}/lib -llapack" |
| 48 | + --with-readline |
| 49 | + --without-aqua |
| 50 | + --without-tcltk |
| 51 | + --without-cairo |
| 52 | + --without-libpng |
| 53 | + --without-jpeglib |
| 54 | + --without-libtiff |
| 55 | + --without-ICU |
| 56 | + --without-x |
| 57 | + --disable-R-framework |
| 58 | + --disable-java |
| 59 | + AR=$(type -p ar) |
| 60 | + AWK=$(type -p gawk) |
| 61 | + CC=$(type -p cc) |
| 62 | + CXX=$(type -p c++) |
| 63 | + FC="${gfortran}/bin/gfortran" F77="${gfortran}/bin/gfortran" |
| 64 | + RANLIB=$(type -p ranlib) |
| 65 | + CURL_CONFIG="${lib.getExe' (lib.getDev curlMinimal) "curl-config"}" |
| 66 | + r_cv_have_curl728=yes |
| 67 | + R_SHELL="${stdenvNoCC.shell}" |
| 68 | + '' |
| 69 | + + lib.optionalString stdenv.hostPlatform.isDarwin '' |
| 70 | + OBJC="clang" |
| 71 | + CPPFLAGS="-isystem ${lib.getInclude stdenv.cc.libcxx}/include/c++/v1" |
| 72 | + LDFLAGS="-L${lib.getLib stdenv.cc.libcxx}/lib" |
| 73 | + '' |
| 74 | + + '' |
| 75 | + ) |
| 76 | + echo >>etc/Renviron.in "TZDIR=${tzdata}/share/zoneinfo" |
| 77 | + ''; |
| 78 | + |
| 79 | + # Upstream postInstall link to the `tex` output, which we don't need |
| 80 | + postInstall = "mv -T \"$out/lib/R/share/texmf\" \"$tex\""; |
| 81 | + postFixup = |
| 82 | + prev.R.postFixup |
| 83 | + # Keep the C/C++ compiler out of R's runtime closure (enforced by |
| 84 | + # outputChecks.disallowedReferences below). R records the absolute path of the |
| 85 | + # compiler it was built with in Makeconf (and a couple of launchers); rewrite |
| 86 | + # those to bare command names so packages are compiled with the toolchain |
| 87 | + # provided by their own build environment. Only the compiler's runtime |
| 88 | + # libraries (…-lib) are needed at run time, so repoint the recorded library |
| 89 | + # search paths, and strip any residual paths recorded in compiled objects |
| 90 | + # (e.g. debug/.comment sections). |
| 91 | + + '' |
| 92 | + compilers='cc|gcc|g\+\+|c\+\+|cpp|clang|clang\+\+|gccgo|gfortran|g77|ld|ld\.gold|ld\.bfd|ld\.lld|ar|ranlib|nm|as|strip|dsymutil|install_name_tool|libtool|lipo|otool' |
| 93 | + for f in \ |
| 94 | + $out/lib/R/etc/Makeconf $out/lib/R/etc/Renviron \ |
| 95 | + $out/lib/R/bin/R $out/bin/R \ |
| 96 | + $out/lib/R/bin/libtool $out/lib/R/bin/javareconf \ |
| 97 | + ; do |
| 98 | + [ -f "$f" ] && sed -i -E "s#/nix/store/[a-z0-9]{32}-[^/ \"')]*/bin/($compilers)#\1#g" "$f" |
| 99 | + done |
| 100 | +
|
| 101 | + substituteInPlace \ |
| 102 | + $out/lib/R/etc/Makeconf \ |
| 103 | + ${ |
| 104 | + if stdenv.hostPlatform.isDarwin then |
| 105 | + # On Darwin the toolchain is clang. After bare-naming, CC/CXX are plain |
| 106 | + # `cc`/`c++`, which resolve via PATH to the gfortran cc-wrapper's GCC |
| 107 | + # drivers in an R-package build env; GCC's libstdc++ headers are |
| 108 | + # incompatible with the SDK libcxx (e.g. "'abort' has not been declared in |
| 109 | + # 'std'"). Pin them to clang/clang++, which the gfortran wrapper does not |
| 110 | + # provide (so PATH resolves to the real clang) and which are not store |
| 111 | + # paths (so the disallowedReferences check still passes). |
| 112 | + '' |
| 113 | + --replace-fail 'CC = cc' 'CC = clang' \ |
| 114 | + --replace-fail 'CXX = c++' 'CXX = clang++' \ |
| 115 | + --replace-fail 'CXX17 = c++' 'CXX17 = clang++' \ |
| 116 | + --replace-fail 'CXX20 = c++' 'CXX20 = clang++' \ |
| 117 | + --replace-fail 'CXX23 = c++' 'CXX23 = clang++' |
| 118 | + '' |
| 119 | + else |
| 120 | + # On Linux gfortran.cc is the same derivation as stdenv.cc.cc (the full |
| 121 | + # gcc), which the disallowedReferences check forbids, so repoint its |
| 122 | + # recorded library search paths to the -lib output. This must NOT run on |
| 123 | + # Darwin: there gfortran is a separate derivation from clang (so the check |
| 124 | + # already passes) and its -lib output lacks lib/gcc/<triple>/<ver> and the |
| 125 | + # libemutls_w/libheapt_w archives that Fortran packages link against. |
| 126 | + '' |
| 127 | + $out/lib/R/etc/ldpaths \ |
| 128 | + --replace-fail "${gfortran.cc}" "${lib.getLib gfortran.cc}" |
| 129 | + '' |
| 130 | + } |
| 131 | +
|
| 132 | + ${lib.optionalString (!stdenv.hostPlatform.isDarwin) '' |
| 133 | + substituteInPlace $out/lib/R/bin/libtool \ |
| 134 | + --replace-fail "${stdenv.cc.cc}" "${lib.getLib stdenv.cc.cc}"''} |
| 135 | +
|
| 136 | + # Neutralise any residual references that are not a plain /bin/<tool> path, |
| 137 | + # e.g. the compiler resource dir baked into libtool's library search path. |
| 138 | + for f in $out/lib/R/etc/Makeconf $out/lib/R/bin/libtool; do |
| 139 | + [ -f "$f" ] && remove-references-to -t ${stdenv.cc} "$f" |
| 140 | + done |
| 141 | +
|
| 142 | + rm $out/lib/R/bin/javareconf |
| 143 | +
|
| 144 | + find $out -type f -name '*.${stdenv.hostPlatform.extensions.sharedLibrary}' -exec \ |
| 145 | + remove-references-to -t ${stdenv.cc} -t ${stdenv.cc.cc} {} + |
| 146 | +
|
| 147 | + find $out -type f -exec remove-references-to -t "$man" {} + |
| 148 | +
|
| 149 | + # 1) Drop recorded `# configure …` / comment lines that pin build-time |
| 150 | + # store paths (R-man via --mandir, the *-dev pkgconfig set, …). |
| 151 | + # Pure metadata — never used at run time. |
| 152 | + sed -i -E '\|^#.*/nix/store/[a-z0-9]{32}|d' $out/lib/R/etc/Makeconf |
| 153 | +
|
| 154 | + # 2) Bare-name the external tool commands R records for |
| 155 | + # install.packages()/vignettes (gzip, bzip2, sed, tar, …). R uses |
| 156 | + # libz/libbz2 internally to *read* compressed data, so dropping the |
| 157 | + # store path (keeping the bare name, resolved from PATH if present) |
| 158 | + # doesn't affect running scripts or loading packages. |
| 159 | + tools='gzip|bzip2|bunzip2|sed|tar|gtar|make|gmake|unzip|zip|xz|gawk|awk' |
| 160 | + for f in $out/lib/R/etc/Renviron $out/lib/R/etc/Makeconf; do |
| 161 | + [ -f "$f" ] && sed -i -E "s#/nix/store/[a-z0-9]{32}-[^/ \"')]*/bin/($tools)#\1#g" "$f" |
| 162 | + done |
| 163 | +
|
| 164 | + # 3) full gfortran (its lib/gcc/<triple>/<ver> crt dir) baked into libtool. |
| 165 | + [ -f $out/lib/R/bin/libtool ] && \ |
| 166 | + remove-references-to -t ${gfortran.cc} -t ${final.coreutils} -t ${final.gnugrep} -t ${final.gnused} $out/lib/R/bin/libtool |
| 167 | + ''; |
| 168 | + |
| 169 | + # Enforce that the compiler wrapper and the unwrapped compiler do not end up in |
| 170 | + # R's runtime closure. On Linux the postFixup above scrubs the references that |
| 171 | + # would otherwise pull them in. |
| 172 | + __structuredAttrs = true; |
| 173 | + outputChecks.out.disallowedReferences = [ |
| 174 | + "man" |
| 175 | + "tex" |
| 176 | + stdenv.cc |
| 177 | + stdenv.cc.cc |
| 178 | + ]; |
| 179 | + }; |
| 180 | +}) |
0 commit comments