10
votes

Travis-CI's official R project build support on Ubuntu uses (at the time of this question) gcc version 4.6.

CRAN uses gcc 4.9 and some packages that build fine on CRAN will not build on Travis with gcc 4.6.

How does one change the default gcc compiler for R project/package builds to more closely mirror CRAN builds?

2

2 Answers

8
votes

I really wanted to be able to use Travis to test my ndjson package but the C++ library I'm using won't compile under gcc 4.6.

The ndjson package is on CRAN and the CRAN builds are fine (except for r-oldrel on Windows which doesn't bother me a bit), so I needed a way to change the compiler that R uses on Travis.

I'm using gcc 5 in the example below, but you can use any version available in the toolchain test builds. Ideally, one should mimic CRAN's gcc version and this may be something the Travis folks might consider making default for R builds.

The .travis.yml starts off the same:

language: r
warnings_are_errors: true
sudo: required

env:
 global:
   - CRAN: http://cran.rstudio.com

I added a matrix build configuration to add the new package source as well as specify the package(s) that needed to be installed. I left it in a matrix configuration since I'm going to try to (eventually) add clang.

matrix:
  include:
    - os: linux
      compiler: gcc
      addons:
        apt:
          sources: ['ubuntu-toolchain-r-test']
          packages: ['g++-5']
      env:
        - COMPILER=g++-5
        - CC=gcc=5
        - CXX=g++-5

Next, I made sure the auto default compiler is set to this newer gcc and also made doubly sure that R would use it by creating a local Makevars:

before_install:
  - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-5 100
  - mkdir -p ~/.R
  - echo "VkVSPS01CkNDPWdjYyQoVkVSKSAtc3RkPWMxMSAKQ1hYPWcrKyQoVkVSKQpTSExJQl9DWFhMRD1nKyskKFZFUikKRkM9Z2ZvcnRyYW4KRjc3PWdmb3J0cmFuCg==" | base64 -d > ~/.R/Makevars
  - cat ~/.R/Makevars

The base64 string equates to:

VER=-5
CC=gcc$(VER) -std=c11
CXX=g++$(VER)
SHLIB_CXXLD=g++$(VER)
FC=gfortran
F77=gfortran

and is just (IMO) cleaner this way.

In theory, all I would have had to do is create the Makevars (i.e. not have to change the default gcc with update-alternatives) but it turned out that Travis used the Makevars gcc setting when installing the dependencies but not for the actual package build itself. So, the update-alternatives is necessary. I also had to add the -std=c11 to ensure a few of the dependencies compiled (the build errored w/o it).

After these modifications to the .travis.yml configuration, ndjson built fine.

7
votes

Just to give an alternate approach, I use a custom shell script in one of my packages sourcetools. My goal there was to ensure the package would build using the (now ancient) gcc-4.4 compiler. In .travis.yml, I have:

language: r
cache: packages
sudo: false
warnings_are_errors: true

before_install:
  - source travis/before-install.sh

addons:
  apt:
    packages:
      - gcc-4.4
      - g++-4.4
      - clang

r:
  - oldrel
  - release
  - devel

env:
  - COMPILER=gcc-4.4
  - COMPILER=gcc
  - COMPILER=clang

And in travis/before-install.sh, I have:

#!/usr/bin/env sh

mkdir -p ~/.R

if [ "${COMPILER}" = "gcc-4.4" ]; then
    echo "CC=gcc-4.4 -std=gnu99"    >> ~/.R/Makevars
    echo "CXX=g++-4.4"              >> ~/.R/Makevars
    echo "CXX1X=g++-4.4 -std=c++0x" >> ~/.R/Makevars
fi

if [ "${COMPILER}" = "gcc" ]; then
    echo "CC=gcc -std=gnu99"    >> ~/.R/Makevars
    echo "CXX=g++"              >> ~/.R/Makevars
    echo "CXX1X=g++ -std=c++0x" >> ~/.R/Makevars
fi

if [ "${COMPILER}" = "clang" ]; then
    echo "CC=clang -std=gnu99"      >> ~/.R/Makevars
    echo "CXX=clang++"              >> ~/.R/Makevars
    echo "CXX1X=clang++ -std=c++0x" >> ~/.R/Makevars
fi

The end result is basically the same, but IMHO it's somewhat cleaner to separate the 'setup' logic into its own script that's driven entirely off of environment variables. It also makes it easier to construct the R matrix builds, since Travis automatically combines the permutations of r and env here (no need to do it 'by hand').

I imagine the before-install.sh script I use could be cleaned up / made more general, but I haven't had the need to do that yet.