#!/bin/bash set -e TARGET=TNL PREFIX=${HOME}/.local INSTALL="no" ROOT_DIR="." DCMTK_DIR="/usr/include/dcmtk" BUILD="" BUILD_JOBS="" CMAKE="cmake" CMAKE_ONLY="no" HELP="no" VERBOSE="" OFFLINE_BUILD="no" WITH_CLANG="no" WITH_MPI="yes" WITH_CUDA="yes" WITH_CUDA_ARCH="auto" WITH_OPENMP="yes" WITH_GMP="no" WITH_TESTS="yes" WITH_MATRIX_TESTS="yes" RUN_TESTS="yes" # whether to run tests if they were compiled (coverage script sets it to no) TESTS_JOBS="4" WITH_PROFILING="no" WITH_COVERAGE="no" WITH_DOC="yes" WITH_EXAMPLES="yes" WITH_PYTHON="yes" WITH_TOOLS="yes" WITH_BENCHMARKS="yes" WITH_CI_FLAGS="no" for option in "$@" do case $option in --prefix=* ) PREFIX="${option#*=}" ;; --install=* ) INSTALL="${option#*=}" ;; --root-dir=* ) ROOT_DIR="${option#*=}" ;; --dcmtk-dir=* ) DCMTK_DIR="${option#*=}" ;; --build=* ) BUILD="${option#*=}" ;; --build-jobs=* ) BUILD_JOBS="${option#*=}" ;; --cmake=* ) CMAKE="${option#*=}" ;; --cmake-only=* ) CMAKE_ONLY="${option#*=}" ;; --verbose ) VERBOSE="VERBOSE=1" ;; --help ) HELP="yes" ;; --offline-build ) OFFLINE_BUILD="yes" ;; --with-clang=* ) WITH_CLANG="${option#*=}" ;; --with-mpi=* ) WITH_MPI="${option#*=}" ;; --with-cuda=* ) WITH_CUDA="${option#*=}" ;; --with-cuda-arch=* ) WITH_CUDA_ARCH="${option#*=}";; --with-openmp=* ) WITH_OPENMP="${option#*=}" ;; --with-gmp=* ) WITH_GMP="${option#*=}" ;; --with-tests=* ) WITH_TESTS="${option#*=}" ;; --with-matrix-tests=* ) WITH_MATRIX_TESTS="${option#*=}" ;; --run-tests=* ) RUN_TESTS="${option#*=}" ;; --tests-jobs=* ) TESTS_JOBS="${option#*=}" ;; --with-profiling=* ) WITH_PROFILING="${option#*=}" ;; --with-coverage=* ) WITH_COVERAGE="${option#*=}" ;; --with-doc=* ) WITH_DOC="${option#*=}" ;; --with-examples=* ) WITH_EXAMPLES="${option#*=}" ;; --with-tools=* ) WITH_TOOLS="${option#*=}" ;; --with-benchmarks=* ) WITH_BENCHMARKS="${option#*=}" ;; --with-python=* ) WITH_PYTHON="${option#*=}" ;; --with-ci-flags=* ) WITH_CI_FLAGS="${option#*=}" ;; * ) echo "Unknown option ${option}. Use --help for more information." exit 1 ;; esac done if [[ ${HELP} == "yes" ]]; then echo "TNL build options:" echo "" echo " --build=Debug/Release Build type." echo " --build-jobs=NUM Number of processes to be used for the build. It is set to the number of available CPU cores by default." echo " --prefix=PATH Prefix for the installation directory. ${HOME}/local by default." echo " --install=yes/no Enables the installation of TNL files." echo " --offline-build=yes/no Disables online updates during the build. 'no' by default." echo " --with-mpi=yes/no Enables MPI. 'yes' by default (OpenMPI required)." echo " --with-cuda=yes/no Enables CUDA. 'yes' by default (CUDA Toolkit is required)." echo " --with-cuda-arch=all/auto/3.0/3.5/... Chooses CUDA architecture. 'auto' by default." echo " --with-openmp=yes/no Enables OpenMP. 'yes' by default." echo " --with-gmp=yes/no Enables the wrapper for GNU Multiple Precision Arithmetic Library. 'no' by default." echo " --with-tests=yes/no Enables compilation of unit tests. 'yes' by default." echo " --run-tests=yes/no Runs unit tests if they were compiled. 'yes' by default." echo " --tests-jobs=NUM Number of processes to be used for the unit tests. It is 4 by default." echo " --with-profiling=yes/no Enables code profiling compiler falgs. 'no' by default." echo " --with-coverage=yes/no Enables code coverage reports for unit tests. 'no' by default (lcov is required)." echo " --with-doc=yes/no Generate the documentation. 'yes' by default." echo " --with-examples=yes/no Compile the 'src/Examples' directory. 'yes' by default." echo " --with-tools=yes/no Compile the 'src/Tools' directory. 'yes' by default." echo " --with-python=yes/no Compile the Python bindings. 'yes' by default." echo " --with-benchmarks=yes/no Compile the 'src/Benchmarks' directory. 'yes' by default." echo " --cmake=CMAKE Path to cmake. 'cmake' by default." echo " --verbose It enables verbose build." echo " --root-dir=PATH Path to the TNL source code root dir." echo " --dcmtk-dir=PATH Path to the DCMTK (Dicom Toolkit) root dir." echo " --help Write this help." exit 1 fi if [[ ${WITH_CLANG} == "yes" ]]; then export CXX=clang++ export CC=clang export CUDA_HOST_COMPILER=clang++ else export CXX=g++ export CC=gcc fi if [[ ! $(command -v cmake) ]]; then echo "Error: cmake is not installed. See http://www.cmake.org/download/" >&2 exit 1 fi if [[ $(command -v ninja) ]]; then generator=Ninja make=ninja check_file="build.ninja" else generator="Unix Makefiles" make=make check_file="Makefile" fi cmake_command=( ${CMAKE} ${ROOT_DIR} -G "${generator}" -DCMAKE_BUILD_TYPE=${BUILD} -DCMAKE_INSTALL_PREFIX=${PREFIX} -DOFFLINE_BUILD=${OFFLINE_BUILD} -DWITH_CUDA=${WITH_CUDA} -DWITH_CUDA_ARCH=${WITH_CUDA_ARCH} -DWITH_OPENMP=${WITH_OPENMP} -DWITH_MPI=${WITH_MPI} -DWITH_GMP=${WITH_GMP} -DWITH_TESTS=${WITH_TESTS} -DWITH_MATRIX_TESTS=${WITH_MATRIX_TESTS} -DWITH_PROFILING=${WITH_PROFILING} -DWITH_COVERAGE=${WITH_COVERAGE} -DWITH_DOC=${WITH_DOC} -DWITH_EXAMPLES=${WITH_EXAMPLES} -DWITH_TOOLS=${WITH_TOOLS} -DWITH_PYTHON=${WITH_PYTHON} -DWITH_BENCHMARKS=${WITH_BENCHMARKS} -DWITH_CI_FLAGS=${WITH_CI_FLAGS} -DDCMTK_DIR=${DCMTK_DIR} ) # Skip running cmake if it was already run and the cmake command is the same. # The build system (e.g. make) will call it automatically if necessary (e.g. # when some CMakeLists.txt changes). if [[ -f ".cmake_command" ]]; then last_cmake_command=$(cat ".cmake_command" 2>/dev/null) else last_cmake_command="" fi if [[ ! -f "$check_file" ]] || [[ "$last_cmake_command" != "${cmake_command[@]}" ]]; then echo "Configuring ${BUILD} $TARGET ..." "${cmake_command[@]}" echo -n "${cmake_command[@]}" > ".cmake_command" fi if [[ ${CMAKE_ONLY} == "yes" ]]; then exit 0 fi # get the number of physical cores present on the system, even with multiple NUMA nodes # see https://unix.stackexchange.com/a/279354 SYSTEM_CORES=$(lscpu --all --parse=CORE,SOCKET | grep -Ev "^#" | sort -u | wc -l) if [[ "$make" == "make" ]]; then if [[ -n ${BUILD_JOBS} ]]; then # override $MAKEFLAGS from parent environment export MAKEFLAGS=-j${BUILD_JOBS} elif [[ -z ${MAKEFLAGS} ]]; then # $BUILD_JOBS and $MAKEFLAGS are not set => set default value BUILD_JOBS=$SYSTEM_CORES export MAKEFLAGS=-j${BUILD_JOBS} fi else if [[ -z ${BUILD_JOBS} ]]; then BUILD_JOBS=$SYSTEM_CORES fi make="$make -j$BUILD_JOBS" fi if [[ -n ${BUILD_JOBS} ]]; then echo "Building ${BUILD} $TARGET using $BUILD_JOBS processors ..." else # number of processors is unknown - it is encoded in $MAKEFLAGS from parent environment echo "Building ${BUILD} $TARGET ..." fi if [[ "$INSTALL" == "yes" ]]; then # install implies all make_target="install" else make_target="all" fi # make expects VERBOSE=1, ninja expects -v if [[ "$make" != "make" ]] && [[ "$VERBOSE" ]]; then VERBOSE="-v" fi if ! $make ${VERBOSE} $make_target; then exit 1 fi if [[ ${WITH_DOC} == "yes" ]]; then "$ROOT_DIR/Documentation/build" --prefix="$PREFIX" fi if [[ ${WITH_TESTS} == "yes" ]] || [[ ${WITH_MATRIX_TESTS} == "yes" ]]; then if [[ ${RUN_TESTS} == "yes" ]]; then CTEST_PARALLEL_LEVEL=${TESTS_JOBS} CTEST_OUTPUT_ON_FAILURE=1 $make test fi fi