Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / DevOps / continuous-build

C++ Continuous Integration Setup

3.77/5 (4 votes)
14 Mar 2016CPOL1 min read 21.1K  
C++ continuous integration setup using Travis CI, AppVeyor, CMake, and the Boost Test Library

Introduction

Acording to ThoughtWorks, Continuous Integration (CI) is a development practice that requires developers to integrate code into a shared repository several times a day. Each check-in is then verified by an automated build, allowing teams to detect problems early. By integrating regularly, you can detect errors preemptively, and locate them more easily.

Commonly used CI services in the open source community are Travis CI and AppVeyor. Travis CI supports numerous languages as well as builds on Linux and OS X. AppVeyor, on the other hand, is a Windows build system. Many people use them simultaneously to support cross-platform development. In this article, in addition to a CI service, CMake is used to manage the build process while unit testing is done via the Boost Test Library.

Example

The example code is arranged in a common folder structure. The first three code blocks contain the C++11 source code, header file, and a boost unit test. The last three code blocks are the CMake, Travis CI, and AppVeyor build scripts. If you place the code on GitHub and add the project to Travis CI and AppVeyor, then successful builds should occur. Furthermore, Travis CI will run two builds (gcc and clang) and AppVeyor one (VS2015).

src/foo.cpp

C++
int foo()
{
  auto x = 1; // C++11 feature
  return x;
}

include/foo.hpp

C++
#ifndef FOO_HPP
#define FOO_HPP

int foo();

#endif

test/test.cpp

C++
#define BOOST_TEST_MODULE test
#include <boost/test/unit_test.hpp>
#include "foo.hpp"

BOOST_AUTO_TEST_CASE(testFoo)
{
    BOOST_CHECK(foo() == 1);
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(myProject)

# Add source code and setup folder structure.
set(src src/foo.cpp)
set(test test/test.cpp)
set(include include/foo.hpp)
include_directories(include)

# Add Boost unit test library.
set(Boost_USE_STATIC_LIBS on)
find_package(Boost COMPONENTS unit_test_framework REQUIRED)
include_directories(${Boost_INCLUDE_DIR})

# Add C++11 compiler flags.
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
    add_definitions(-std=c++11 -stdlib=libc++ -O3 -Wall)
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
    add_definitions(-std=c++11 -O3 -Wall)
endif()

# Create executable that links the source code, unit test, header file, and Boost.
add_executable(exe ${src} ${test} ${include})
target_link_libraries(exe ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})

# Add support for unit tests e.g. ctest.
enable_testing()
add_test(myTest exe)

.travis.yml

matrix:
  include:

    # Build with Linux and gcc.
    # The default gcc compiler does not support C++11 so install a higher version.
    - os: linux
      env: CC=gcc-5 CXX=g++-5
      addons: &gcc5
        apt:
          packages:
            - libstdc++-5-dev
          sources:
            - ubuntu-toolchain-r-test
      install:
        - sudo apt-get update -qq
        - sudo apt-get install -qq g++-5
        - sudo apt-get install -y libboost-test-dev

    # Build with OS X and clang.
    # The default clang compiler supports C++11.
    - os: osx
      env: COMPILER=clang++

script:
  - mkdir build
  - cd build
  - cmake ..
  - make
  - ctest

appveyor.yml

os: Visual Studio 2015

# Boost is already installed on AppVeyor.
environment:
  BOOST_ROOT: C:\Libraries\boost_1_59_0
  BOOST_LIBRARYDIR: C:\Libraries\boost_1_59_0\lib64-msvc-14.0

build_script:
  - md build
  - cd build
  - cmake -G "Visual Studio 14 2015 Win64" ..
  - cmake --build . --config Release
  - ctest

Discussion

To speed up the build process, only a subset of the boost library is used, namely, unit_test_framework. However, this code can be modified to support other parts of the boost library.

Sometimes, you'll see dynamic linking to the boost library. However, it was necessary to statically link to the library on AppVeyor. This was accomplished by not including in test/test.cpp.

C++
#define BOOST_TEST_DYN_LINK

and including in CMakeLists.txt:

set(Boost_USE_STATIC_LIBS on)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)