Guidance to get R package `sf` built on Macbook aarch64

Hello,

I am trying to instantiate an R environment on a Macbook using a flake that I use on x86_64 (NixOS and Linux)

The flake is

{
  description = "Basic R env flake";
  
  inputs = {
    flake-utils.url = "github:numtide/flake-utils";
    # nixpkgs.url = "nixpkgs/nixos-21.11";
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
  };
  
  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system:
      let
	    pkgs = import nixpkgs { inherit system; };

        our-R-packages = with pkgs.rPackages; [
          dplyr here # good
          sf # fails, as do  geojsonio leaflet
        ]; 
        R-with-our-packages = pkgs.rWrapper.override{ packages =  our-R-packages; };
        
      in rec {

        devShell =  pkgs.mkShell {
          buildInputs = [ pkgs.cowsay R-with-our-packages];
        }; 
      }
    );
}

Running nix develop fails with message including:

       > ld: library not found for -liconv
       > clang-11: error: linker command failed with exit code 1 (use -v to see invocation)
       > make: *** [/nix/store/sddgzxiv53lz4q56q73alkxg6vaa3k85-R-4.2.1/lib/R/share/make/shlib.mk:10: classInt.so] Error 1
       > ERROR: compilation failed for package ‘classInt’
       > * removing ‘/nix/store/17lw6hncla0yh4hk0fyqw16db61ckq71-r-classInt-0.4-7/library/classInt’
       For full logs, run 'nix log /nix/store/vrmwmj03fz00lqsbzwhrlfzxmgjj5npa-r-classInt-0.4-7.drv'.

If anyone has any suggestions I’d be grateful!

The rPackages.sf package depends on the rPackages.classInt package, which seems to be missing a dependency on libiconv. You can overridde that classInt package by using this instead:

classInt-with-libiconv = nixpkgs.rPackages.classInt.overrideDerivation (old: {
  nativeBuildInputs = old.nativeBuildInputs ++ [ nixpkgs.libiconv ];
})

The tricky part is overriding rPackages.sf to use this instead of rPackages.classInt: each R package can only be overridden by the low-level .overrideDerivation function (unlike e.g. pythonPackages, which provides a higher-level .overridePythonAttrs function). The approach I’m using at the moment is to filter out any dependencies with a name beginning r-classInt, then append the above package instead:

removeClassInt = builtins.filter ({ name, ... }: !(nixpkgs.lib.hasPrefix "r-classInt" name));

sf-with-dependencies = nixpkgs.rPackages.sf.overrideDerivation (old: {
  nativeBuildInputs = removeClassInt old.nativeBuildInputs ++ [ classInt-with-libiconv ];  
  propagatedBuildInputs = removeClassInt old.propagatedBuildInputs ++ [ classInt-with-libiconv ];
  propagatedNativeBuildInputs = removeClassInt old.propagatedNativeBuildInputs ++ [ classInt-with-libiconv ];
})

This got me a little further: the classInt package builds, but I get a few errors from the sf package itself. Adding nixpkgs.curl.dev and nixpkgs.libtiff.dev to those nativeBuildInputs fixes some of them, but I’m currently stuck on this error:

checking PROJ: checking whether PROJ and sqlite3 are available for linking:... no
configure: error: libproj or sqlite3 not found in standard or given locations.
ERROR: configuration failed for package ‘sf’

This is weird, since Nixpkgs already adds the sqlite library as a dependency. This seems to be the same issue as configure: error: libproj or sqlite3 not found in standard or given locations. · Issue #1471 · r-spatial/sf · GitHub but I haven’t figured out how the Nixpkgs setup relates to that yet.

Would be useful to know if anyone gets a complete build to work!

I’ve opened a PR which adds the libiconv dependency to rPackages.classInt on darwin: rPackages.classInt: add libiconv dependency to fix build on darwin by chriswarbo · Pull Request #209297 · NixOS/nixpkgs · GitHub

Instead of your filtering the entire rPackages tree can overridden to use your altered classInt, which will propagate your changes to other packages. E.g.,:

(rPackages.override {
  overrides = {
    classInt = rPackages.classInt.overrideDerivation (old: {
      propagatedBuildInputs = old.propagatedBuildInputs ++ [libiconv];
    });
  };
})
.sf

@jbedo ah that’s a good point! I’m already using rPackages.override, but it doesn’t seem to propagate changes when multiple packages are overridden together?

In my case I used rPackages.override to add a custom package (UK2GTFS), but it failed due to its sf dependency. I added the above classInt override alongside UK2GTFS, but that didn’t fix the sf dependency. This is due to the way r-modules is defined in Nixpkgs: it ignores any overrides when finding the fixed-point of all the standard packages (including sf), then afterwards merges the overrides into the attrset.

Based on your suggestion, something like this should work better:

withFixedClassInt = rPackages.override {
  overrides.classInt = rPackages.classInt.overrideDerivation (old: {
    propagatedBuildInputs = old.propagatedBuildInputs ++ [libiconv];
  });
};

finalPackages = rPackages.override {
  overrides = {
    inherit (withFixedClassInt) classInt sf;
    UK2GTFS = withFixedClassInt.buildRPackage {...};
};

env = rWrapper.override {
  packages = [ finalPackages.UK2GTFS ];
}; 

Hi @ChrisZip and @jbedo, sorry about not replying earlier …

Would be useful to know if anyone gets a complete build to work!

It sure would!