Installing compiler on Mac M1 Monterey for Rcpp and other tools
I'm trying to use packages that require Rcpp
in R on my M1 Mac, which I was never able to get up and running after purchasing this computer. I updated it to Monterey in the hope that this would fix some installation issues but it hasn't. I tried running the Rcpp
check from this page but I get the following error:
> Rcpp::sourceCpp("~/github/helloworld.cpp")
ld: warning: directory not found for option '-L/opt/R/arm64/gfortran/lib/gcc/aarch64-apple-darwin20.2.0/11.0.0'
ld: warning: directory not found for option '-L/opt/R/arm64/gfortran/lib'
ld: library not found for -lgfortran
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [sourceCpp_4.so] Error 1
clang++ -arch arm64 -std=gnu++14 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I../inst/include -I"/Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/library/Rcpp/include" -I"/Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/library/RcppArmadillo/include" -I"/Users/afredston/github" -I/opt/R/arm64/include -fPIC -falign-functions=64 -Wall -g -O2 -c helloworld.cpp -o helloworld.o
clang++ -arch arm64 -std=gnu++14 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/Library/Frameworks/R.framework/Resources/lib -L/opt/R/arm64/lib -o sourceCpp_4.so helloworld.o -L/Library/Frameworks/R.framework/Resources/lib -lRlapack -L/Library/Frameworks/R.framework/Resources/lib -lRblas -L/opt/R/arm64/gfortran/lib/gcc/aarch64-apple-darwin20.2.0/11.0.0 -L/opt/R/arm64/gfortran/lib -lgfortran -lemutls_w -lm -F/Library/Frameworks/R.framework/.. -framework R -Wl,-framework -Wl,CoreFoundation
Error in Rcpp::sourceCpp("~/github/helloworld.cpp") :
Error 1 occurred building shared library.
I get that it can't "find" gfortran
. I installed this release of gfortran
for Monterey. When I type which gfortran
into Terminal, it returns /opt/homebrew/bin/gfortran
. (Maybe this version of gfortran
requires Xcode tools that are too new—it says something about 13.2 and when I run clang --version
it says 13.0—but I don't see another release of gfortran
for Monterey?)
I also appended /opt/homebrew/bin:
to PATH
in R so it looks like this now:
> Sys.getenv("PATH")
[1] "/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Library/TeX/texbin:/Applications/RStudio.app/Contents/MacOS/postback"
Other things I checked:
- Xcode command line tools is installed (
which clang
returns/usr/bin/clang
). - Files
~/.R/Makevars
and~/.Renviron
don't exist.
Here's my session info:
R version 4.1.1 (2021-08-10)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Monterey 12.1
Matrix products: default
LAPACK: /Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/lib/libRlapack.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
loaded via a namespace (and not attached):
[1] compiler_4.1.1 tools_4.1.1 RcppArmadillo_0.10.7.5.0
[4] Rcpp_1.0.7
Solution 1:
There are some obstacles on ARM-based Macs (and macOS in general) to compiling R packages containing C/C++ code from their sources, and likewise to using Rcpp
. The main issues and their fixes are documented in the R-admin
manual, but they are a bit scattered.
Your proximal problem is perhaps easier to solve than the problem you haven't mentioned, which is that the clang
toolchain provided with Apple's Command Line Tools doesn't support OpenMP. Not having OpenMP support is an issue if you want to compile a C/C++ program that makes use of multithreading. I'll discuss your proximal problem first, then provide a complete set of instructions that should address everything at once, so that you can obtain a fully enabled toolchain.
LDFLAGS, not PATH
When R (and Rcpp
, etc.) compiles C/C++ programs, it determines what compilers, compiler flags, preprocessor flags, etc. to use from make
variables set in Makefiles. The correct way to link to a specific installation of gfortran
—a library external to R—during compilation is to set the make
variable LDFLAGS
in a Makefile that R knows about. System-level default values of all make
variables used by R are stored in $(R_HOME)/etc/Makeconf
. You can query them with R CMD config
, like so:
$ R CMD config LDFLAGS --no-user-files
A user can override any Makeconf
setting by creating and modifying $(HOME)/.R/Makevars
. Since you do not have a Makevars
, R is finding LDFLAGS
in your Makeconf
, and its value there (I'm guessing) contains -L/opt/R/arm64/gfortran/lib
, because that is how CRAN configured the build of R that you have installed.
Thus, you might resolve your compilation error by setting LDFLAGS
in Makevars
or Makeconf
so that it includes -L$(F_DIR)/lib
and excludes paths that don't exist. (You would replace $(F_DIR)
with the path to your gfortran
installation.) If you are the only user on your system, then I would recommend modifying Makevars
and keeping a pristine Makeconf
.
You might also resolve the error by moving your gfortran
installation to /opt/R/arm64
and leaving Makevars
and Makeconf
alone. You should consider trying this first, especially if you are unfamiliar with Makefile syntax.
If neither of these approaches work, then read the next section.
Note: I should emphasize here that the environment variable PATH
doesn't really affect how R compiles C/C++ programs apart from telling R where to find make
. That is, the paths printed by
$ which clang clang++ gnufortran
aren't necessarily the paths to the C, C++, and Fortran compilers used by R.
Instructions for obtaining a working toolchain on ARM-based Macs
For the benefit of anyone else reading this, I'm going to assume that you are starting from nothing. Feel free to skip steps you've already taken, though you might find a fresh start helpful.
-
Download R from CRAN here and install. Be sure to select the binary built for Apple silicon.
-
Run
$ xcode-select --install
in Terminal to download and install the latest version of Xcode, which includes Apple's Command Line Tools. You can also download Xcode from your browser here. Earlier versions of Xcode are available here, but I would start with the latest. (There might be a good reason to install the exact version of Xcode than CRAN used to build your R binary, and that version might not be the newest. Not sure.)
-
Install the LLVM
clang
toolchain with Homebrew. Unlike Apple'sclang
, it supports OpenMP.$ brew update $ brew install llvm
It should unpack into
/opt/homebrew/opt
. -
Download a
gfortran
binary built for your macOS version and architecture here and unpack into/opt/R/arm64
.$ sudo mkdir -p /opt/R/arm64 $ sudo tar xvf path/to/gfortran/tarball -C /opt/R/arm64
-
Modify a symbolic link in your
gfortran
installation so that it points to your Command Line Tools SDK. If the link doesn't exist in your installation, then ignore this step.$ ln -sfn $(eval xcrun -show-sdk-path) /opt/R/arm64/gfortran/SDK
-
Add the following lines to
$(HOME)/.R/Makevars
, creating the file if necessary:LLVM_DIR=/opt/homebrew/opt/llvm LIBS_DIR=/opt/R/arm64 F_DIR=$(LIBS_DIR)/gfortran SDK_DIR=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk CC=$(LLVM_DIR)/bin/clang -isysroot $(SDK_DIR) -target arm64-apple-macos11 CXX=$(LLVM_DIR)/bin/clang++ -isysroot $(SDK_DIR) -target arm64-apple-macos11 FC=$(F_DIR)/bin/gfortran -mtune=native CFLAGS=-falign-functions=8 -g -O2 -Wall -pedantic -Wno-implicit-function-declaration CXXFLAGS=-g -O2 -Wall -pedantic FFLAGS=-g -O2 -Wall -pedantic SHLIB_OPENMP_CFLAGS=-fopenmp SHLIB_OPENMP_CXXFLAGS=-fopenmp SHLIB_OPENMP_FFLAGS=-fopenmp CPPFLAGS=-I$(LLVM_DIR)/include -I$(LIBS_DIR)/include LDFLAGS=-L$(LLVM_DIR)/lib -L$(LIBS_DIR)/lib
-
Run R and test that you can compile a C/C++ program with OpenMP support. For example:
if (!requireNamespace("Rcpp", quietly = TRUE)) { install.packages("Rcpp") } Rcpp::sourceCpp(code = ' #include <Rcpp.h> #ifdef _OPENMP # include <omp.h> #endif // [[Rcpp::plugins(openmp)]] // [[Rcpp::export]] int omp_test() { #ifdef _OPENMP return omp_get_max_threads(); #else return 0; #endif } ') omp_test()
[1] 8
If you get a compilation error or if
omp_test
returns 0 after compiling successfully, then something is wrong. Let me know if this happens...
FWIW, these steps do work for me. I am running Big Sur, not Monterey, but it shouldn't matter much. You might need -target arm64-apple-macos12
instead of -target arm64-apple-macos11
in CC
and CXX
, but I'm not sure. Let me know what works...