为Travis-CI R项目构建使用替代编译器

Using an alternate compiler for Travis-CI R project builds

本文关键字:编译器 构建 Travis-CI 项目      更新时间:2023-10-16

Travis-CI的官方R项目在Ubuntu上使用(在这个问题出现的时候)gcc 4.6版本。

CRAN使用gcc 4.9,一些在CRAN上运行良好的包将无法在gcc 4.6的Travis上运行。

如何更改R项目/包构建的默认gcc编译器以更紧密地镜像CRAN构建?

我真的希望能够使用Travis来测试我的ndjson包,但是我使用的c++库在gcc 4.6下无法编译。

ndjson在CRAN上是, CRAN构建很好(除了Windows上的R -oldrel,这一点也不困扰我),所以我需要一种方法来改变R在Travis上使用的编译器。

我在下面的例子中使用 gcc.5,但是您可以使用工具链测试构建中可用的任何版本。理想情况下,应该模仿CRAN的gcc版本,这可能是Travis的人可能会考虑将其默认为R版本。

.travis.yml开头相同:

language: r
warnings_are_errors: true
sudo: required
env:
 global:
   - CRAN: http://cran.rstudio.com

我添加了一个矩阵构建配置来添加新的包源以及指定需要安装的包。我把它留在矩阵配置中,因为我要尝试(最终)添加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

接下来,我确保自动默认编译器设置为这个较新的gcc,并确保R将通过创建一个本地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

base64字符串等于:

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

和(IMO)这样更干净。

理论上,我所要做的就是创建Makevars(即不需要用update-alternatives更改默认的gcc),但事实证明Travis在安装依赖项时使用了Makevars gcc设置,而不是为实际的包构建本身。因此,update-alternatives是必要的。我还必须添加-std=c11以确保编译了一些依赖项(构建错误)。

在对.travis.yml的配置进行了这些修改之后,ndjson构建得很好

只是为了提供另一种方法,我在我的一个包sourcetools中使用了一个自定义shell脚本。我的目标是确保包可以使用(现在已经过时的)gcc-4.4编译器构建。在.travis.yml,我有:

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

travis/before-install.sh中,我有:

#!/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

最终结果基本上是相同的,但在我看来,将"设置"逻辑分离到完全脱离环境变量的自己的脚本中是更干净的。这也使得构建R矩阵更容易,因为Travis在这里自动组合了renv的排列(不需要"手工")。

我想象我使用的before-install.sh脚本可以被清理/更通用,但我还没有需要这样做。