How to change compiler version to build an Rcpp-based package? - r

I'm authoring a package that uses an external .so library and a header file. I notice that it works with g++-4.9 but not g++5.0 or above after I compiled the demo code in pure C++ for testing. My system default is g++ 5.4.0.
I tried adding CXX=g++-4.9 to ./configure and src/Makevars but the compiler still turns out to be system default g++. I don't want to modify global configuration (e.g. in ~/.R/Makevars) because it will influence other package builds.
Is there a local way to specify the compiler version Rcpp uses to compile cpp files when I build this package?

Step 1: Set CXX for all varieties in src/Makevars this comes about because you might be using CXX_STD = CXX11 so CXX11 is used instead of CXX...
CXX=g++-4.9
CXX1X=g++-4.9
CXX11=g++-4.9
CXX14=g++-4.9
Note: This assumes you are only compiling C++ code.
Step 2: Test for gcc 4.9 in configure.ac with:
AC_PREREQ(2.61)
AC_INIT(your_package_name_here, m4_esyscmd_s([awk -e '/^Version:/ {print $2}' DESCRIPTION]))
AC_COPYRIGHT(Copyright (C) 2017 your name?)
## Determine Install Location of R
: ${R_HOME=$(R RHOME)}
if test -z "${R_HOME}"; then
AC_MSG_ERROR([Could not determine R_HOME.])
fi
## Setup RBin
RBIN="${R_HOME}/bin/R"
CXX=`"${RBIN}" CMD config CXX`
CPPFLAGS=`"${RBIN}" CMD config CPPFLAGS`
CXXFLAGS=`"${RBIN}" CMD config CXXFLAGS`
## We are using C++
AC_LANG(C++)
AC_REQUIRE_CPP
## Check the C++ compiler using the CXX value set
AC_PROG_CXX
## If the compiler is g++, then GXX is set so version information can be exaimed
if test "${GXX}" = yes; then
AC_MSG_CHECKING([whether g++ version is sufficient])
gxx_version=$(${CXX} -v 2>&1 | awk '/^.*g.. version/ {print $3}')
case ${gxx_version} in
4.9.*)
AC_MSG_RESULT([(${gxx_version}) yes])
;;
1.*|2.*|3.*|4.0.*|4.1.*|4.2.*|4.3.*|4.4.*|4.5.*|4.6.*|4.7.*|4.8.*|5.*|6.*|7.*)
AC_MSG_RESULT([no])
AC_MSG_WARN([Only g++ version 4.9.* be used to compile this package.])
AC_MSG_ERROR([Please set the default compiler to gcc++-4.9.])
;;
esac
else
AC_MSG_WARN([The package uses an external shared library that only compiles with gcc++-4.9])
AC_MSG_ERROR([Please set the default compiler to gcc++-4.9.])
fi
AC_OUTPUT

Related

gnu make - assert specific command line tools are available

In a makefile, how would I make sure that certain tools like gcov, lcov, g++ are available before executing any other targets?
I want to gracefully fail with
gcov/lcov/g++ not available
.
You could try something like:
TOOLS := gcov lcov g++
$(foreach TOOL,$(TOOLS),\
$(if $(shell command -v $(TOOL)),,\
$(error Cannot locate $(TOOL) on PATH)))
This assumes you're using a POSIX shell obviously.

Requiring OpenMP availability for use in an Rcpp package

I have prepared a package in R by using RcppArmadillo and OpenMP libraries and following commands:
RcppArmadillo.package.skeleton("mypackage")
compileAttributes(verbose=TRUE)
Also, in the DESCRIPTION file I added:
Imports: Rcpp (>= 0.12.8), RcppArmadillo
LinkingTo:Rcpp, RcppArmadillo
Depends: RcppArmadillo
and in the NAMESPACE file I added:
import(RcppArmadillo)
importFrom(Rcpp, evalCpp)
Then I run the following codes in cmd:
R CMD build mypackage
R CMD INSTALL mypackage.tar.gz
I build and install the package in my computer and I use it now. But my colleges and friends are not able to install the package. The error messages is about RcppArmadillo and OpenMPlibraries.
For instance:
fatal error: 'omp.h' file not found
Does anyone have previous experience in this case? Which type of settings I have to do in my package for solving this problem?
Congratulations! You've most likely stumbled across macOS' lack OpenMP support. This has been documented in the Rcpp FAQ as entry 2.10.3.
Defensive coding
The reason for the error being apparent is you did not protect the OpenMP code appropriately... e.g.
Header inclusions are protected with:
#ifdef _OPENMP
#include <omp.h>
#endif
Code has protections given by:
#ifdef _OPENMP
// multithreaded OpenMP version of code
#else
// single-threaded version of code
#endif
This assumes you are not using the preprocessor #omp tags but more indepth omp function calls. If it is the prior, then the code protection is not important as the preprocessor tags will be discarded.
(For those long time users of the above macro schemes coming here, please note that as of R 3.4.0, the SUPPORT_OPENMP definition was removed completely in favor of _OPENMP.)
Creating a package requirement for OpenMP via configure.ac
However, the above is just good defensive coding. If your package requires a specific feature, then it may be time to consider using an autoconf file called configure.ac to generate a configure script.
Place the configure.ac in the top level of your package.
packagename/
|- data/
|- inst/
|- man/
|- src/
|- Makevars
|- HelloWorld.cpp
|- DESCRIPTION
|- NAMESPACE
|- configure.ac
|- configure
The configure.ac should contain the following:
AC_PREREQ(2.61)
AC_INIT(your_package_name_here, m4_esyscmd_s([awk -e '/^Version:/ {print $2}' DESCRIPTION]))
AC_COPYRIGHT(Copyright (C) 2017 your name?)
## Determine Install Location of R
: ${R_HOME=$(R RHOME)}
if test -z "${R_HOME}"; then
AC_MSG_ERROR([Could not determine R_HOME.])
fi
## Setup RBin
RBIN="${R_HOME}/bin/R"
CXX=`"${RBIN}" CMD config CXX`
CPPFLAGS=`"${RBIN}" CMD config CPPFLAGS`
CXXFLAGS=`"${RBIN}" CMD config CXXFLAGS`
## Package Requires C++
AC_LANG(C++)
AC_REQUIRE_CPP
## Compiler flag check
AC_PROG_CXX
## Borrowed from BHC/imager/icd/randomForest
# Check for OpenMP
AC_OPENMP
# since some systems have broken OMP libraries
# we also check that the actual package will work
ac_pkg_openmp=no
if test -n "${OPENMP_CFLAGS}"; then
AC_MSG_CHECKING([OpenMP detected, checking if viable for package use])
AC_LANG_CONFTEST([AC_LANG_PROGRAM([[#include <omp.h>]], [[ return omp_get_num_threads (); ]])])
"$RBIN" CMD SHLIB conftest.c 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD && "$RBIN" --vanilla -q -e "dyn.load(paste('conftest',.Platform\$dynlib.ext,sep=''))" 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD && ac_pkg_openmp=yes
AC_MSG_RESULT([${ac_pkg_openmp}])
fi
# if ${ac_pkg_openmp} = "yes" then we have OMP, otherwise it will be "no"
if test "${ac_pkg_openmp}" = no; then
AC_MSG_WARN([No OpenMP support. If using GCC, upgrade to >= 4.2. If using clang, upgrade to >= 3.8.0])
AC_MSG_ERROR([Please use a different compiler.])
fi
# Fin
AC_OUTPUT
To generate the configure script, run:
autoconf
Once this is done, you will need to rebuild your package. Note, you may need to install autoconf if on Windows and on macOS you likely need to install it via homebrew.
Helping users get a viable OpenMP compiler
Now, you may want to ensure your colleagues are able to get the speedup gain from your OpenMP-enabled code. To do so, one must enable OpenMP by having your colleagues shift away from using the default system compiler to either a "true" gcc or a viable omp enabled clang compiler.
Instructions for both on macOS are given here:
http://thecoatlessprofessor.com/programming/openmp-in-r-on-os-x/

gcc not found by win-builder

I've built an R package which includes C/C++ code. I am now trying to test this package on win-builder. Unfortunately, the following error is returned in 00install.out:
* installing *source* package 'mypackage' ...
** libs
running 'src/Makefile.win' ...
/usr/bin/make --directory=lib/mylib/
gcc -g -Wall -fPIC -c mycode.c
make[1]: gcc: Command not found
make[1]: *** [mycode.o] Error 127
make: *** [mylib] Error 2
Warning: running command 'make --no-print-directory -f "Makefile.win"' had status 2
ERROR: compilation failed for package 'mypackage'
* removing 'd:/RCompile/CRANguest/R-release/lib/mypackage'
Trying with gcc, gcc.exe, and cc yielded similar results.
Accordingly, I set up a testing environment on a Windows virtual machine according to these instructions. Running R CMD INSTALL . on the code from the command line within this environment resulted in the code compiling and the package installing without issue. (Running R CMD build . also yielded no errors.)
What's up with win-builder, and how can I achieve compilation on it?
Or, more importantly, is being able to build the package on Windows sufficient, regardless of whether it worked on win-builder?
My Makefile.win is as follows:
export CCOMP = gcc
export CPPCOMP = c++
export ADD_CC_FLAGS = -O3
APP_DIR = ./apps/myapp
LIB_DIR = ./lib/mylib
.PHONY: all $(APP_DIR) $(LIB_DIR)
all: $(APP_DIR) $(LIB_DIR)
$(APP_DIR) $(LIB_DIR): mylib
$(MAKE) --directory=$#
$(APP_DIR): $(LIB_DIR) mylib
mylib:
$(MAKE) --directory=lib/mylib
Inserting echo %PATH% into the make file under the mylib target yielded:
Makefile.win:24: *** missing separator. Stop.
You get an obscure error here because you included a file Makefile.win.
But the semantics of make, if such a file is found, it will be used ... which is not what you want here. R builds its own Makefile.win and you are supposed to only supply a snippet to be included -- which must be called Makevars.win.
That is rule number one. Rules number two is to not included all the material you would include in a Makefile -- as you would clobber what R already brings to the table. All this is in Writing R Extensions but could of course be clearer.
My pragmatic suggestion: take a package you know and like which has a working R build in win-builder, and modify it. You can test locally should you have access to an R system with Rtools etc pp.
Edit from OP:
I needed to compile an executable which relied on several libraries. The library codes were in src/libs and the executable's code was in src/apps. I ensured that running make within each subdirectory worked and set src/apps/Makefile to use relative paths to pull in the results of src/libs. The only problem then, was getting the whole chain running. To do so, I created a file src/Makevars.win which had the following structure:
.PHONY: all myprogram sublib1 sublib2
all: sublib1 sublib2 myprogram
myprogram: sublib1 sublib2
#(cd apps/myprogram && $(MAKE) CXX="$(CXX)" CC="$(CC)" CFLAGS="$(CFLAGS) $(CPICFLAGS)" AR="$(AR)" RANLIB="$(RANLIB)")
sublib1:
#(cd lib/sublib1 && $(MAKE) CXX="$(CXX)" CC="$(CC)" CFLAGS="$(CFLAGS) $(CPICFLAGS)" AR="$(AR)" RANLIB="$(RANLIB)")
sublib2:
#(cd lib/sublib2 && $(MAKE) CXX="$(CXX)" CC="$(CC)" CFLAGS="$(CFLAGS) $(CPICFLAGS)" AR="$(AR)" RANLIB="$(RANLIB)")
As I understand it, Makevars.win gets embedded in a dynamically generated Makefile that R produces. So, $(CC) is actually referencing this hidden code.
(There are probably more clever ways to do this.)

Sqlite load extension disabled?

I'm trying to use this sqlite extension to calculate stdev in Sqlite dbs, on Linux, I use this command to compile the lib
gcc -fPIC -lm -shared extension-functions.c -o libsqlitefunctions.so
but seems that the .load command is not in the sqlite .help command list, and I got error:
unknown command or invalid arguments: "load". Enter ".help" for help
Same thing happens when I use the command:
sqlite> SELECT load_extension('./libsqlitefunctions.so');
SQL error: no such function: load_extension
I tried to use this instruction to compile sqlite:
0. untar latest sqlite3 source code in a new directory
1. cd to the newly untarred sqlite directory
2. Comment out the line in Makefile.in to enable loadable extensions:
# TCC += -DSQLITE_OMIT_LOAD_EXTENSION=1
3. ./configure LIBS=-ldl && make sqlite3
4. export LD_LIBRARY_PATH="`pwd`:$LD_LIBRARY_PATH"
5. gcc -I`pwd` -shared src/test_loadext.c -o half.so
6. ./sqlite3
But couldn't find the line "TCC += -DSQLITE_OMIT_LOAD_EXTENSION=1" in the newest Sqlite source code.
It looks like configure was updated but not the documentation. Try
./configure --enable-dynamic-extensions
The reference is the configure source code. Digging further, it looks like the dynamic extensions are enabled by default. From README:
The generic installation instructions for autoconf/automake are found
in the INSTALL file.
The following SQLite specific boolean options are supported:
--enable-readline use readline in shell tool [default=yes]
--enable-threadsafe build a thread-safe library [default=yes]
--enable-dynamic-extensions support loadable extensions [default=yes]
So I think load is present. It's the second part of the error invalid arguments that's the problem.
The cause seems to be that you're using Linux instructions. That won't work. Macs don't generally have .so files, which is what your compilation command is generating.
The method of compiling and loading a Mac dynamic library, loadable as an extension, is at this location. The compile command is going to look something like
gcc -bundle -fPIC -I/path-to-sqlite/sqlite3 -o filename.sqlext filename.c
Note the -bundle and -fPIC that are important for dynamic loading, but which you were missing. The resulting filename will be filename.sqlext, so use that in your path.
It may be worth noting that you may get a "missing symbols" error when you load the library - this is due to the fact that the -lm flag needs to be at the end of the compile command thus:
gcc -fPIC -shared extension-functions.c -o libsqlitefunctions.so -lm
Regards Fat jonnie

Compiling R extension with third-party DLL

I am writing an R extension that includes C code that relies on a third-party DLL. Compilation is being done on Windows using Rtools with R 2.11.0. My plan is that the DLL will be distributed with the source package and stored in the extension's src directory. My question then is how I can cause the compiler to look in the the src directory when it tries to link to the third-party DLL.
Currently, I am building the package with the command:
R CMD build --binary MyPackage
I also have a file src/Makevars with the following line:
PKG_LIBS = -ldlxapi32
This ensures that the third-party DLL, dlxapi32.dll, is included in compilation. However, the compiler cannot find the DLL, since my package's src directory is not part of the standard library search path.
I have tried to remedy this by changing src/Makevars to read:
PKG_LIBS = -L$(CURDIR) -ldlxapi32
But this fails with output like the following:
gcc -shared -s -static-libgcc -o MyPackage.dll tmp.def dlx.o -L/cygdrive/c/DOCUME~1/abiel/LOCALS~1/Temp/Rbuild709236257/MyPackage/src -ldlxapi32 -Lc:/PROGRA~1/R/R-211~1.0/bin -lR
c:/mingw/bin/../lib/gcc/mingw32/4.5.0/../../../../mingw32/bin/ld.exe: cannot find -ldlxapi32
Here, we can see that $(CURDIR) evaluated to /cygdrive/c.DOCUME~1/... I was hoping that instead it would evaluate to C:/programming/r/MyPackage/src, which is the actual location of the src directory. Is there a way to fix this?
Instead of the overly complicated -L$(CURDIR), why don't you just use the equivalent -L. ?
Also, the Rtools suite uses MinGW which is not Cygwin so I'd avoid paths like /cygdrive/c/... as to MinGW this is still c:/....

Resources