Rstan on NixOS

All right, I created a Nix overlay workaround. Basically, it creates a single R_LIBS_SITE directory, similar to symlinkJoin. This prevents environment variables from getting too long.

In a file named something like ~/.config/nixpkgs/utils/r-wrapper2.nix:

{ runCommand, R, makeWrapper, lndir, recommendedPackages, packages }:

runCommand (R.name + "-wrapper") {
  preferLocalBuild = true;
  allowSubstitutes = false;

  buildInputs = [R] ++ recommendedPackages ++ packages;

  nativeBuildInputs = [makeWrapper];

  # Make the list of recommended R packages accessible to other packages such as rpy2
  # (Same as in the original rWrapper)
  passthru = { inherit recommendedPackages; };
}
  # Wrap a site lib, similar to symlinkJoin but without propagating buildInputs.
''
  mkdir -p $out/library
  for lib in $(echo -n $R_LIBS_SITE | sed -e 's/:/\n/g'); do
    ${lndir}/bin/lndir -silent $lib $out/library/
  done
  
  mkdir -p $out/bin
  cd ${R}/bin
  for exe in *; do
    makeWrapper ${R}/bin/$exe $out/bin/$exe \
      --prefix "R_LIBS_SITE" ":" "$out/library"
  done
''

Then create an overlay in a file like ~/.config/nixpkgs/overlays/10-rwrapper2.nix:

self: super:
{
  rWrapper = super.callPackage ../utils/r-wrapper2.nix {
    # Copied from the original rWrapper in all-packages.nix
    # If you define this as rWrapper2, you can just use
    # "inherit (self.rWrapper) recommendedPackages;"
    recommendedPackages = with super.rPackages; [
      boot class cluster codetools foreign KernSmooth lattice MASS
      Matrix mgcv nlme nnet rpart spatial survival
    ];
    # Override this attribute to register additional libraries.
    packages = [];
  };
}

You can call this new wrapper either rWrapper or something different like rWrapper2, depending on your preference.

Basically, the issue is that the R_LIBS_SITE environment variable accumulates all Nix propagatedBuildInputs, so it contains hundreds of paths. The R package callr duplicates these environment variables in some shell script files that are sourced by the child R script, probably just in case environment variables aren’t properly inherited by child processes for whatever reason. This is fine if R_LIBS_SITE is only a few directories long, as it is in most distributions, but it breaks when there are hundreds of long paths. This overlay makes it one path, containing symlinks.

The reason RStudio in Nix doesn’t face this issue is because the RStudio wrapper never redefines R_LIBS_SITE (because RStudio actually ignores it). Instead, the wrapper creates an .Rprofile file with the list of library paths.

This fix should probably be in nixpkgs proper, but I have to test that the symlinking used here doesn’t break anything.

Hope this helps.

2 Likes