10

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?

Cœur
  • 37,241
  • 25
  • 195
  • 267
hrbrmstr
  • 77,368
  • 11
  • 139
  • 205

2 Answers2

8

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.

hrbrmstr
  • 77,368
  • 11
  • 139
  • 205
  • 1
    Sure. Been doing that for eons, see eg [here](https://github.com/eddelbuettel/rcppcctz/blob/master/.travis.yml) and in a few other repos. – Dirk Eddelbuettel Sep 27 '16 at 16:05
  • 1
    Aye. Just trying to help out others. – hrbrmstr Sep 27 '16 at 16:08
  • 1
    The nice is that it really is just like shell scripting. One additional piece that is golden is to .... add your own PPAs. But that may require the previous style of Travis use which happen to prefer. See eg [here](https://github.com/eddelbuettel/rquantlib/blob/master/.travis.yml). – Dirk Eddelbuettel Sep 27 '16 at 16:55
  • Also: you generally want 'trusty' rather than 'precise'. One is old, the other is jurassic. But that is all we get there, for free, ... – Dirk Eddelbuettel Sep 27 '16 at 16:56
  • FWIW, `CXX11=g++4.9` is needed for c++11 package. `update-alternatives` shouldn't be needed. – VitoshKa Jul 14 '18 at 20:52
  • 1
    I copy-pasted this answer and blindly used it for a long time. Unfortunately the base64 string above no longer works with travis. Specifying -std=c11 in the "CC=..." now breaks the install of devtools v2. And you can't avoid installing devtools, it's installed directly by the travis infrastructure. So you will need to make a small change to this answer. To be honest, specifying the standard there is kind of silly. – DaBookshah Oct 20 '18 at 06:29
7

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.

Kevin Ushey
  • 20,530
  • 5
  • 56
  • 88
  • 2
    Nice setup Sir Ushey! (and I'm now rly glad I started this FAQ-ish self-answered Q&A since this info really isn't documented anywhere besides in production configurations in GitHub repos :-) – hrbrmstr Sep 27 '16 at 17:11
  • 3
    Six of one, half a dozen of the other. [Some other travis files](https://github.com/skystrife/cpptoml/blob/master/.travis.yml) do this within the same file, using a matrix. I think I find that cleaner. YMMV. The main thing is that is very cool that we can do these things. – Dirk Eddelbuettel Sep 27 '16 at 19:45