# Copyright Louis Dionne 2013-2016
# Copyright Gonzalo BG 2014-2017
# Copyright Julian Becker 2015
# Copyright Manu Sánchez 2015
# Copyright Casey Carter 2015-2017
# Copyright Eric Niebler 2015-2016
# Copyright Paul Fultz II 2015-2016
# Copyright Jakub Szuppe 2016.

# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSE_1_0.txt)

# Adapted from various sources, including:
# - Louis Dionne's Hana: https://github.com/ldionne/hana
# - Paul Fultz II's FIT: https://github.com/pfultz2/Fit
language: cpp
script: cmake

env:
  global:
    - DEPS_DIR=${TRAVIS_BUILD_DIR}/deps
    - BOOST_URL="http://sourceforge.net/projects/boost/files/boost/1.63.0/boost_1_63_0.tar.gz"
    - BOOST_VERSION="1_63_0"
    - CMAKE_VERSION="3.9.1"

cache:
  directories:
    - ${DEPS_DIR}/cmake-${CMAKE_VERSION}

matrix:
  include:
    - env: BUILD_TYPE=Release CPP=11 SYSTEM_LIBCXX=On
      os: osx
      compiler: clang

    # ASAN disabled for clang < 3.8 builds per resolution of
    #  https://llvm.org/bugs/show_bug.cgi?id=22757

    # clang 3.6 C++11/14 Release libc++
    - env: CLANG_VERSION=3.6 BUILD_TYPE=Release CPP=11 LIBCXX=On
      os: linux
      addons: &clang36
        apt:
          packages:
            - clang-3.6
            - g++-5
            - valgrind
          sources:
            - ubuntu-toolchain-r-test
            - llvm-toolchain-precise-3.6

    - env: CLANG_VERSION=3.6 BUILD_TYPE=Release CPP=14 LIBCXX=On HEADERS=On
      os: linux
      addons: *clang36

    # clang 3.7 C++11/14 Release libc++
    #
    # ASAN disabled: cmake'ing libc++-3.7 with -fsanitize=address fails with:
    #   CMake Error at projects/libcxx/CMakeLists.txt:164 (message):
    #     c++11 is required by libc++ but is not supported by the compiler
    - env: CLANG_VERSION=3.7 BUILD_TYPE=Release CPP=11 LIBCXX=On
      os: linux
      addons: &clang37
        apt:
          packages:
            - util-linux
            - clang-3.7
            - g++-5
            - valgrind
          sources:
            - ubuntu-toolchain-r-test
            - llvm-toolchain-precise-3.7

    # ASAN disabled (see above):
    - env: CLANG_VERSION=3.7 BUILD_TYPE=Release CPP=14 LIBCXX=On HEADERS=On
      os: linux
      addons: *clang37

    # clang 3.8 C++11/14 Release libc++
    - env: CLANG_VERSION=3.8 BUILD_TYPE=Release CPP=11 LIBCXX=On
      os: linux
      addons: &clang38
        apt:
          packages:
            - util-linux
            - clang-3.8
            - g++-5
            - valgrind
          sources:
            - ubuntu-toolchain-r-test
            - llvm-toolchain-precise-3.8

    - env: CLANG_VERSION=3.8 BUILD_TYPE=Release CPP=14 LIBCXX=On HEADERS=On
      os: linux
      addons: *clang38

    # clang 3.9 C++11/14 Release libc++
    - env: CLANG_VERSION=3.9 BUILD_TYPE=Release CPP=11 LIBCXX=On
      os: linux
      addons: &clang39
        apt:
          packages:
            - util-linux
            - clang-3.9
            - g++-5
            - valgrind
          sources:
            - ubuntu-toolchain-r-test
            - llvm-toolchain-precise-3.9

    - env: CLANG_VERSION=3.9 BUILD_TYPE=Release CPP=14 LIBCXX=On HEADERS=On
      os: linux
      addons: *clang39

    # clang 5 C++11/14/1z Debug/Release-ASAN libc++, 11 Debug libstdc++
    - env: CLANG_VERSION=5.0 BUILD_TYPE=Debug CPP=11 LIBCXX=On
      os: linux
      addons: &clang5
        apt:
          packages:
            - util-linux
            - clang-5.0
            - g++-6
            - valgrind
          sources:
            - ubuntu-toolchain-r-test
            - llvm-toolchain-precise

    - env: CLANG_VERSION=5.0 BUILD_TYPE=Release CPP=11 ASAN=On LIBCXX=On
      os: linux
      addons: *clang5

    - env: CLANG_VERSION=5.0 BUILD_TYPE=Debug CPP=14 LIBCXX=On
      os: linux
      addons: *clang5

    - env: CLANG_VERSION=5.0 BUILD_TYPE=Release CPP=14 ASAN=On LIBCXX=On
      os: linux
      addons: *clang5

    - env: CLANG_VERSION=5.0 BUILD_TYPE=Debug CPP=1z LIBCXX=On HEADERS=On
      os: linux
      addons: *clang5

    - env: CLANG_VERSION=5.0 BUILD_TYPE=Release CPP=1z ASAN=On LIBCXX=On
      os: linux
      addons: *clang5

    - env: CLANG_VERSION=5.0 BUILD_TYPE=Release CPP=11
      os: linux
      addons: *clang5

    - env: CLANG_VERSION=5.0 BUILD_TYPE=Release CPP=1z MSAN=On LIBCXX=On CLANG_MODULES=On
      os: linux
      addons: *clang5

      # gcc-4.9 C++11/C++14 Release
    - env: GCC_VERSION=4.9 BUILD_TYPE=Release CPP=11
      os: linux
      addons: &gcc49
        apt:
          packages:
            - g++-4.9
            - valgrind
          sources:
            - ubuntu-toolchain-r-test

    - env: GCC_VERSION=4.9 BUILD_TYPE=Release CPP=14 HEADERS=On
      os: linux
      addons: *gcc49

      # gcc-5 C++11/C++14 Release
    - env: GCC_VERSION=5 BUILD_TYPE=Release CPP=11
      os: linux
      addons: &gcc5
        apt:
          packages:
            - g++-5
            - valgrind
          sources:
            - ubuntu-toolchain-r-test

    - env: GCC_VERSION=5 BUILD_TYPE=Release CPP=14 HEADERS=On
      os: linux
      addons: *gcc5

    # gcc-6 C++11/14/1z Debug/Release
    - env: GCC_VERSION=6 BUILD_TYPE=Debug CPP=11
      os: linux
      addons: &gcc6
        apt:
          packages:
            - g++-6
            - valgrind
          sources:
            - ubuntu-toolchain-r-test

    - env: GCC_VERSION=6 BUILD_TYPE=Release CPP=11
      os: linux
      addons: *gcc6

    - env: GCC_VERSION=6 BUILD_TYPE=Debug CPP=14
      os: linux
      addons: *gcc6

    - env: GCC_VERSION=6 BUILD_TYPE=Release CPP=14
      os: linux
      addons: *gcc6

    - env: GCC_VERSION=6 BUILD_TYPE=Debug CPP=1z HEADERS=On
      os: linux
      addons: *gcc6

    - env: GCC_VERSION=6 BUILD_TYPE=Release CPP=1z
      os: linux
      addons: *gcc6

# Install dependencies
before_install:
  - export CHECKOUT_PATH=`pwd`;
  - |
    if [ "$TRAVIS_OS_NAME" == "osx" ]; then
      brew update
      brew install valgrind
      brew install gnu-sed --with-default-names
      brew install gnu-which --with-default-names
    fi
  - |
    if [ "${TRAVIS_OS_NAME}" == "linux" ]; then
      if [ -z "$(ls -A ${DEPS_DIR}/cmake-${CMAKE_VERSION}/cached)" ]; then
        CMAKE_URL="https://cmake.org/files/v3.9/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz"
        mkdir -p ${DEPS_DIR}/cmake-${CMAKE_VERSION}
        travis_retry wget --no-check-certificate --quiet -O - "${CMAKE_URL}" | tar --strip-components=1 -xz -C ${DEPS_DIR}/cmake-${CMAKE_VERSION}
        touch ${DEPS_DIR}/cmake-${CMAKE_VERSION}/cached
      else
        echo "Using cached cmake version ${CMAKE_VERSION}."
      fi
      export PATH="${DEPS_DIR}/cmake-${CMAKE_VERSION}/bin:${PATH}"
    else
      if ! brew ls --version cmake &>/dev/null; then brew install cmake; fi
    fi
  - if [ -n "$GCC_VERSION" ]; then export CXX="g++-${GCC_VERSION}" CC="gcc-${GCC_VERSION}"; fi
  - if [ -n "$CLANG_VERSION" ]; then export CXX="clang++-${CLANG_VERSION}" CC="clang-${CLANG_VERSION}"; fi
  - which $CXX
  - which $CC
  - which valgrind
  - $CXX --version
  - if [ "$ASAN" == "On" ]; then export SANITIZER="Address;Undefined"; fi
  - if [ "$MSAN" == "On" ]; then export SANITIZER="MemoryWithOrigins"; fi
  - if [ -n "$CLANG_VERSION" ]; then sudo PATH="${PATH}" CXX="$CXX" CC="$CC" ./install_libcxx.sh; fi

  # Download and install Boost
  # Adapted from Boost.Compute (under the Boost License)
  # Copyright Jakub Szuppe 2016.
  - |
    if [[ ${TRAVIS_OS_NAME} == "linux" && ${BOOST} == "On" ]]; then
      if [ ! -f "${DEPS_DIR}/boost/${BOOST_VERSION}_cached" ]; then
        # create dirs for source and install
        mkdir -p ${DEPS_DIR}/boost${BOOST_VERSION}
        mkdir -p ${DEPS_DIR}/boost
        rm -rf ${DEPS_DIR}/boost/*
        # download
        travis_retry wget --no-check-certificate --quiet -O - ${BOOST_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR}/boost${BOOST_VERSION}
        pushd ${DEPS_DIR}/boost${BOOST_VERSION}
        # configure and install
        ./bootstrap.sh --prefix=${DEPS_DIR}/boost/ --with-libraries=program_options,date_time
        ./b2 toolset=clang cxxflags="-stdlib=libc++ -nostdinc++ -cxx-isystem /usr/include/c++/v1/" linkflags="-stdlib=libc++"
        ./b2 -d0 install
        popd
        touch ${DEPS_DIR}/boost/${BOOST_VERSION}_cached
      else
        echo 'Using cached Boost ${BOOST_VERSION} libraries.'
      fi
    fi

install:
  - cd $CHECKOUT_PATH

  # Workaround for valgrind bug: https://bugs.kde.org/show_bug.cgi?id=326469.
  # It is fixed in valgrind 3.10 so this won't be necessary if someone
  # replaces the current valgrind (3.7) with valgrind-3.10
  - if [ "$BUILD_TYPE" == "Release" -a "$ASAN" != "On" ]; then sed -i 's/march=native/msse4.2/' cmake/ranges_flags.cmake; fi
  - mkdir -p build
  - cd build
  - if [ "$GCC_VERSION" == "5" ]; then CXX_FLAGS="${CXX_FLAGS} -DRANGES_CXX_CONSTEXPR=RANGES_CXX_CONSTEXPR11"; fi
  - |
    if [ "$LIBCXX" == "On" ]; then
      CXX_FLAGS="${CXX_FLAGS} -stdlib=libc++ -nostdinc++ -cxx-isystem /usr/include/c++/v1/ -Wno-unused-command-line-argument"
      CXX_LINKER_FLAGS="${CXX_LINKER_FLAGS} -lc++abi"
    fi
  # Required to test the C++ compiler since libc++ is compiled with ASan enabled:
  - if [ -n "$CLANG_VERSION" -a "$ASAN" == "On" -a "$LIBCXX" == "On" ]; then CXX_FLAGS="${CXX_FLAGS} -fsanitize=address"; fi
  # Required to test the C++ compiler since libc++ is compiled with MSan enabled:
  - if [ -n "$CLANG_VERSION" -a "$MSAN" == "On" -a "$LIBCXX" == "On" ]; then CXX_FLAGS="${CXX_FLAGS} -fsanitize=memory"; fi
  - if [ "$HEADERS" == "On" ]; then NO_HEADER_CHECK=0; else NO_HEADER_CHECK=1; fi
  - cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_FLAGS="${CXX_FLAGS}" -DCMAKE_EXE_LINKER_FLAGS="${CXX_LINKER_FLAGS}" -DRANGES_CXX_STD=$CPP -DRANGE_V3_NO_HEADER_CHECK=$NO_HEADER_CHECK -DRANGES_VERBOSE_BUILD=On -DRANGES_ASAN=$ASAN -DRANGES_MSAN=$MSAN -Wdev
  - cat CMakeFiles/CMakeError.log
  - cat CMakeFiles/CMakeOutput.log
  - |
    if [ "$BOOST" == "On" ]; then
      export LD_LIBRARY_PATH=$DEPS_DIR/boost/lib:$LD_LIBRARY_PATH
      cmake .. -DRANGES_BUILD_CALENDAR_EXAMPLE=On -DBOOST_ROOT=${DEPS_DIR}/boost
    fi
  - if [ "$CLANG_MODULES" == "On" -a "$LIBCXX" == "On" ]; then cmake .. -DRANGES_MODULES=On -DRANGES_LIBCXX_MODULE="/usr/include/c++/v1/module.modulemap"; fi
  - make -j2 VERBOSE=1

script:
  # Only enable valgrind for non-ASAN Release builds (keep this in sync with line 309)
  - if [ "$BUILD_TYPE" == "Release" -a "$ASAN" != "On" -a "$MSAN" != "On" ]; then CTEST_FLAGS="-D ExperimentalMemCheck"; fi
  - ctest -j2 -VV ${CTEST_FLAGS}

notifications:
  email: false
