rclangopenmpllvmstringi

"C compiler cannot create executables" when installing stringi in R


I often install R packages from source, and need a properly configured ~/.R/Makevars to do this. I want to be able to use OpenMP, so I copied a Makevars I found online. My Makevars ended up being this:

OPT_LOC = $(HOME)/homebrew/opt
LLVM_LOC = $(OPT_LOC)/llvm
CC=$(LLVM_LOC)/bin/clang
CXX=$(LLVM_LOC)/bin/clang++

# CFLAGS and CXXFLAGS *with* -fopenmp
CFLAGS=-fopenmp -g -O3 -Wall -pedantic -std=gnu99 -mtune=native -pipe
CXXFLAGS=-fopenmp -g -O3 -Wall -pedantic -std=c++11 -mtune=native -pipe

# CFLAGS and CXXFLAGS *without* -fopenmp
# (sometimes the package install process fails if -fopenmp is present)
# CFLAGS=-g -O3 -Wall -pedantic -std=gnu99 -mtune=native -pipe
# CXXFLAGS=-g -O3 -Wall -pedantic -std=c++11 -mtune=native -pipe

LDFLAGS=-L$(OPT_LOC)/gettext/lib -L$(LLVM_LOC)/lib -Wl,-rpath,$(LLVM_LOC)/lib
CPPFLAGS=-I$(OPT_LOC)/gettext/include -I$(LLVM_LOC)/include

I can no longer find the original source of my version, but it's similar to this one.

My Makevars works great, except for a few packages, like stringi. These packages complain that "C compiler cannot create executables". I discovered that this error generally goes away if I remove -fopenmp from CFLAGS and CXXFLAGS. As you can see, I've set up Makevars so I can easily switch back and forth between the configuration with -fopenmp and without it.

My workaround works fine, as does the workaround of "delete Makevars entirely" in the Stack Overflow post linked above. But isn't there a better way? It's annoying that I can't expect package installs to succeed because of these dependencies that hate the -fopenmp flag, while removing the flag means I might miss out on OpenMP on some package installs.


Solution

  • If you use GCC instead of Clang you should be able to install stringi with OpenMP enabled. I've tested a number of different solutions and ultimately came up with these steps to successfully install stringi from source with the -fopenmp flag (Intel macOS v11 (Big Sur)):

    1. Reinstall the Xcode command line tools (don't believe Software Update if it says 'up to date' - it lies - brew doctor said my version was actually old)

      sudo rm -rf /Library/Developer/CommandLineTools
      sudo xcode-select --install
      
    2. Install GCC and LLVM via Homebrew (instructions for installing Homebrew) or, if you already have GCC/LLVM installed, skip to the next step.

      # WARNING: This can take several hours
      brew install gcc
      brew install llvm
      
    3. If you already have GCC and LLVM installed via Homebrew:

      brew cleanup
      brew update
      brew upgrade
      brew reinstall gcc
      brew reinstall llvm
      
    4. Link some headers into /usr/local/include

      sudo ln -s /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/* /usr/local/include/
      
      # I believe you can safely ignore warnings like this:
      #ln: /usr/local/include//tcl.h: File exists
      #ln: /usr/local/include//tclDecls.h: File exists
      #ln: /usr/local/include//tclPlatDecls.h: File exists
      #ln: /usr/local/include//tclTomMath.h: File exists
      #ln: /usr/local/include//tclTomMathDecls.h: File exists
      #ln: /usr/local/include//tk.h: File exists
      #ln: /usr/local/include//tkDecls.h: File exists
      #ln: /usr/local/include//tkPlatDecls.h: File exists
      
    5. Edit your ~/.R/Makevars file (if you don't have a file called Makevars in your ~/.R/ directory, create it) and include only these lines:

      LOC = /usr/local/gfortran
      CC=$(LOC)/bin/gcc -fopenmp
      CXX=$(LOC)/bin/g++ -fopenmp
      CXX11 = $(LOC)/bin/g++ -fopenmp
      
      CFLAGS=-g -O3 -Wall -pedantic -std=gnu99 -mtune=native -pipe
      CXXFLAGS=-g -O3 -Wall -pedantic -std=c++11 -mtune=native -pipe
      LDFLAGS=-L$(LOC)/lib -Wl,-rpath,$(LOC)/lib
      CPPFLAGS=-I$(LOC)/include -I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
      
      FLIBS=-L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin19/10.2.0 -L/usr/local/gfortran/lib -lgfortran -lquadmath -lm
      CXX1X=/usr/local/gfortran/bin/g++
      CXX98=/usr/local/gfortran/bin/g++
      CXX11=/usr/local/gfortran/bin/g++
      CXX14=/usr/local/gfortran/bin/g++
      CXX17=/usr/local/gfortran/bin/g++
      
    6. Compile a package from source in R/RStudio

      # Test if OpenMP is actually enabled
      install.packages("data.table", type = "source")
      # (loading data.table will tell you if it was successful)
      
      # Compile the stringi package from source
      install.packages("stringi", type = "source")
      

    NB: Some users have commented that they had to install a 'fresh' GFortran (e.g., GFortran 10.2 for Big Sur (macOS 11), for Intel processors) to compile packages successfully, and others have commented that they didn't need LLVM, but these steps seem to work in most cases.

    Update (2022/04/05)

    I recently had an error when updating "RcppAlgos" using this ~/.R/Makevars (couldn't find gmp.h or libgmp). I checked gmp was installed (brew install gmp), then added /usr/local/include to CPPFLAGS and /usr/local/lib to LDFLAGS in the ~/.R/Makevars file to solve the problem, and hopefully prevent similar issues in the future, i.e. edit your Makevars to contain these lines only:

    LOC=/usr/local/gfortran
    CC=$(LOC)/bin/gcc -fopenmp
    CXX=$(LOC)/bin/g++ -fopenmp
    CXX11 = $(LOC)/bin/g++ -fopenmp
    
    CFLAGS=-g -O3 -Wall -pedantic -std=gnu99 -mtune=native -pipe
    CXXFLAGS=-g -O3 -Wall -pedantic -std=c++11 -mtune=native -pipe
    LDFLAGS=-L$(LOC)/lib -Wl,-rpath,$(LOC)/lib,-L/usr/local/lib
    CPPFLAGS=-I$(LOC)/include -I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include -I/usr/local/include
    
    FLIBS=-L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin19/10.2.0 -L/usr/local/gfortran/lib -lgfortran -lquadmath -lm
    CXX1X=/usr/local/gfortran/bin/g++
    CXX98=/usr/local/gfortran/bin/g++
    CXX11=/usr/local/gfortran/bin/g++
    CXX14=/usr/local/gfortran/bin/g++
    CXX17=/usr/local/gfortran/bin/g++