Code Monkey home page Code Monkey logo

multi-ghc-travis's Introduction

Multiple GHC Versions for Travis-CI

The purpose of this document is to describe how to set up the .travis.yml script in order to build and test your cabalized Haskell package with multiple GHC configurations. At time of writing Travis-CI has support for building Haskell packages but only for a single GHC configuration (i.e. Haskell Platform 2012.2.0.0 with GHC 7.4.1). By following this guide, you can set up Travis-CI jobs which have access to the following GHC versions (all compiled for Ubuntu Linux 12.04 LTS 64-bit):

  • GHC 6.12.3,
  • GHC 7.0.1, GHC 7.0.2, GHC 7.0.3, GHC 7.0.4,
  • GHC 7.2.1, GHC 7.2.2,
  • GHC 7.4.1, GHC 7.4.2,
  • GHC 7.6.1, GHC 7.6.2, GHC 7.6.3,
  • GHC 7.8.1, GHC 7.8.2, GHC 7.8.3, GHC 7.8.4
  • GHC 7.10.1, GHC 7.10.2, GHC 7.10.3 (prerelease)
  • GHC HEAD.

Each GHC version is provided in a separate ghc-<version> .deb package installing into /opt/ghc/<version> (thus allowing to be installed at the same time if needed) published in a PPA. The easiest way to "activate" a particular GHC version is to prepend its bin-folder to the $PATH environment variable (see example in next section).

Note: For actually enabling continuous integration for a GitHub hosted project, see section Getting Started in Travis-CI's online documentation.

Add-on Packages

For convenience, a few add-on packages are available to provide more recent versions of cabal, alex and happy than are available in Ubuntu 12.04.

They install into a respective /opt/<name>/<version>/bin folder which can be put into the search $PATH.

.deb Package Name Executable
cabal-install-1.16 /opt/cabal/1.16/bin/cabal
cabal-install-1.18 /opt/cabal/1.18/bin/cabal
cabal-install-1.20 /opt/cabal/1.20/bin/cabal
cabal-install-1.22 /opt/cabal/1.22/bin/cabal
cabal-install-head /opt/cabal/head/bin/cabal
alex-3.1.3 /opt/alex/3.1.3/bin/alex
alex-3.1.4 /opt/alex/3.1.4/bin/alex
happy-1.19.3 /opt/happy/1.19.3/bin/happy
happy-1.19.4 /opt/happy/1.19.4/bin/happy
happy-1.19.5 /opt/happy/1.19.5/bin/happy

See examples below for how to use those.

.travis.yml (for container-based infrastructure)

Since 2015, Travis-CI is migrating build-jobs towards a contained-based infrastructure which requires a different way to setup the build-matrix in the first half of the .travis.yml.

The following .travis.yml snippet shows the different matrix and before_install sections (relative to the non-container .travis.yml):

language: c

# explicitly request container-based infrastructure
sudo: false

matrix:
  include:
    - env: CABALVER=1.16 GHCVER=7.6.3
      addons: {apt: {packages: [cabal-install-1.16,ghc-7.6.3], sources: [hvr-ghc]}}
    - env: CABALVER=1.18 GHCVER=7.8.4
      addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4], sources: [hvr-ghc]}}
    - env: CABALVER=1.22 GHCVER=7.10.1
      addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.1],sources: [hvr-ghc]}}
    - env: CABALVER=head GHCVER=head
      addons: {apt: {packages: [cabal-install-head,ghc-head],  sources: [hvr-ghc]}}

  allow_failures:
   - env: CABALVER=head GHCVER=head

before_install:
 - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH

Caching dependencies & .travis.yml script generator

There's also a runghc script provided in this repository to automate the generation of such a .travis.yml script based on the tested-with: property of your .cabal file. Moreover, the generated script contains a simple caching logic which allows to cache build-dependencies between builds (as long as the install-plan doesn't change by e.g. new packages being available from Hackage).

The top-level tested-with: field has a similiar syntax to the build-depends: field but with compilers instead of packages. The script contains a list of known GHC versions and emits entries for all matching versions. Here are a few examples:

tested-with: GHC >= 7.4 && < 7.8
-- selects GHC 7.4.1, 7.4.2, 7.6.1, 7.6.2, and 7.6.3

tested-with: GHC == 7.4.2, GHC == 7.6.3, GHC == 7.8.4, GHC == 7.11.*
-- selects GHC 7.4.2, 7.6.3, 7.8.4, and GHC HEAD

If you need additional Ubuntu packages installed (e.g. alex-3.1.5 or libxml-dev), you can pass the Ubuntu package names as additional commandline arguments after the .cabal filename argument.

Known Issues

  • The container environment reports 16 cores, causing cabal's default configuration (jobs: $ncpus) to run into the GHC #9221 bug which can result in longer build-times. This can be workarounded by commenting out the jobs: $ncpus right after cabal update creates that file:

    install:
    # ...
      - travis_retry cabal update
      - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
    # ...

.travis.yml Template (for non-container-based infrastructure)

Below is a commented .travis.yml example that can be used as a template:

# NB: don't set `language: haskell` here

# explicitly request legacy non-sudo based build environment
sudo: required

# The following enables several GHC versions to be tested; often it's enough to test only against the last release in a major GHC version. Feel free to omit lines listings versions you don't need/want testing for.
env:
 - CABALVER=1.16 GHCVER=6.12.3
 - CABALVER=1.16 GHCVER=7.0.1
 - CABALVER=1.16 GHCVER=7.0.2
 - CABALVER=1.16 GHCVER=7.0.3
 - CABALVER=1.16 GHCVER=7.0.4
 - CABALVER=1.16 GHCVER=7.2.1
 - CABALVER=1.16 GHCVER=7.2.2
 - CABALVER=1.16 GHCVER=7.4.1
 - CABALVER=1.16 GHCVER=7.4.2
 - CABALVER=1.16 GHCVER=7.6.1
 - CABALVER=1.16 GHCVER=7.6.2
 - CABALVER=1.18 GHCVER=7.6.3
 - CABALVER=1.18 GHCVER=7.8.1  # see note about Alex/Happy for GHC >= 7.8
 - CABALVER=1.18 GHCVER=7.8.2
 - CABALVER=1.18 GHCVER=7.8.3
 - CABALVER=1.18 GHCVER=7.8.4
 - CABALVER=1.22 GHCVER=7.10.1
 - CABALVER=1.22 GHCVER=7.10.2
 - CABALVER=head GHCVER=head   # see section about GHC HEAD snapshots

# Note: the distinction between `before_install` and `install` is not important.
before_install:
 - travis_retry sudo add-apt-repository -y ppa:hvr/ghc
 - travis_retry sudo apt-get update
 - travis_retry sudo apt-get install cabal-install-$CABALVER ghc-$GHCVER # see note about happy/alex
 - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH

install:
 - cabal --version
 - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
 - travis_retry cabal update
 - cabal install --only-dependencies --enable-tests --enable-benchmarks

# Here starts the actual work to be performed for the package under test; any command which exits with a non-zero exit code causes the build to fail.
script:
 - if [ -f configure.ac ]; then autoreconf -i; fi
 - cabal configure --enable-tests --enable-benchmarks -v2  # -v2 provides useful information for debugging
 - cabal build   # this builds all libraries and executables (including tests/benchmarks)
 - cabal test
 - cabal check
 - cabal sdist   # tests that a source-distribution can be generated

# Check that the resulting source distribution can be built & installed.
# If there are no other `.tar.gz` files in `dist`, this can be even simpler:
# `cabal install --force-reinstalls dist/*-*.tar.gz`
 - SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&
   (cd dist && cabal install --force-reinstalls "$SRC_TGZ")

For more information about the .travis.yml script please consult the official documentation.

Haskell Platform Configurations

Basic idea: Generate a cabal.config file during the build job (before installing the build-dependencies) constraining to HP package versions, e.g. for HP 2013.2.0.0 the cabal.config would need to contain the following constraints definition:

constraints: async==2.0.1.4,attoparsec==0.10.4.0,case-insensitive==1.0.0.1,cgi==3001.1.7.5,fgl==5.4.2.4,GLUT==2.4.0.0,GLURaw==1.3.0.0,haskell-src==1.0.1.5,hashable==1.1.2.5,html==1.0.1.2,HTTP==4000.2.8,HUnit==1.2.5.2,mtl==2.1.2,network==2.4.1.2,OpenGL==2.8.0.0,OpenGLRaw==1.3.0.0,parallel==3.2.0.3,parsec==3.1.3,QuickCheck==2.6,random==1.0.1.1,regex-base==0.93.2,regex-compat==0.95.1,regex-posix==0.95.2,split==0.2.2,stm==2.4.2,syb==0.4.0,text==0.11.3.1,transformers==0.3.0.0,unordered-containers==0.2.3.0,vector==0.10.0.1,xhtml==3000.2.1,zlib==0.5.4.1

Use this .travis.yml script as a template if you want to test against Haskell Platform configurations.

Alex & Happy with GHC โ‰ฅ 7.8

If your package (or one of its dependencies) contain Alex/Happy generated parsers, GHC 7.8.1 and later require a more recent alex/happy executable installed (see Happy, Alex, and GHC 7.8 for the gory details). The following snipped (stolen from lens's .travis.yaml) illustrates how to this can be accomplished:

 - |
   if [ $GHCVER = "head" ] || [ ${GHCVER%.*} = "7.8" ] || [ ${GHCVER%.*} = "7.10" ]; then
     travis_retry sudo apt-get install happy-1.19.4 alex-3.1.3
     export PATH=/opt/alex/3.1.3/bin:/opt/happy/1.19.4/bin:$PATH
   else
     travis_retry sudo apt-get install happy alex
   fi

GHC HEAD Snapshots

  • Snapshots of current GHC development snapshots from the master branch (aka GHC HEAD) are uploaded at irregular intervals to the PPA

  • You can select GHC HEAD at your own risk by setting GHCVER=head

  • As GHC HEAD is experimental and likely to cause build failures, you might want to tolerate failures by adding the following snippet to your .travis.yml:

    matrix:
      allow_failures:
       - env: CABALVER=head GHCVER=head
  • NB: the line in matrix.allow_failures.env must match exactly (including any whitespace) the line specified in env

Ideas for Additional Checks

  • Check for code-smell via hlint
  • Check for build-depends excluding latest package versions with packdeps
  • Check for unused build-depends with packunused
  • Check for 100% Haddock coverage
  • Check for trailing whitespaces and/or tabs in source files

Random Remarks

  • If you want to know which core library version each GHC used (e.g. for deciding on what upper/lower bounds to declare for build-depends), see GHC Boot Library Version History
  • Supporting GHC versions prior to 7.0.1 requires more effort:
    • GHC 7.0.1 was the first version to support default-language: Haskell2010
    • Declaring cabal-version >= 1.10 makes it more difficult to compile with GHC 6.12.3's default cabal-install
    • cabal-install falls back to top-down solver for GHC < 7 which may require additional tweaks to the build script to compensate for (e.g. installing QuickCheck via cabal install --only-dep is known to fail)

Real-world Examples

multi-ghc-travis's People

Contributors

23skidoo avatar asr avatar bergey avatar emwap avatar hamishmack avatar hvr avatar nomeata avatar phadej avatar rufflewind avatar tebello-thejane avatar thomasdziedzic-pd avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.