TiagoMSSantos/MobileRT

View on GitHub
scripts/compile_native.sh

Summary

Maintainability
Test Coverage
#!/usr/bin/env sh

###############################################################################
# README
###############################################################################
# This script compiles MobileRT (in debug or release mode) for a native
# Operating System by using the CMake to generate the Makefiles, making it
# compatible with:
# * Linux
# * MacOS
# * Windows
###############################################################################
###############################################################################


###############################################################################
# Exit immediately if a command exits with a non-zero status.
###############################################################################
set -eu;
###############################################################################
###############################################################################


###############################################################################
# Change directory to MobileRT root.
###############################################################################
env | grep -i path;
if [ $# -ge 1 ]; then
  cd "$(dirname "${0}")/.." || return 1;
fi
###############################################################################
###############################################################################


###############################################################################
# Get helper functions.
###############################################################################
# shellcheck disable=SC1091
. scripts/helper_functions.sh;
###############################################################################
###############################################################################


###############################################################################
# Execute Shellcheck on this script.
###############################################################################
if [ $# -ge 1 ] && command -v shellcheck > /dev/null; then
  shellcheck "${0}" --exclude=SC1017,SC2215 || return 1;
fi
###############################################################################
###############################################################################


###############################################################################
# Set default arguments.
###############################################################################
type='release';
compiler='g++';
recompile='no';
parallelizeBuild;

printEnvironment() {
  echo '';
  echo 'Selected arguments:';
  echo "type: ${type}";
  echo "compiler: ${compiler}";
  echo "recompile: ${recompile}";
}
###############################################################################
###############################################################################


###############################################################################
# Parse arguments.
###############################################################################
parseArgumentsToCompile "$@";
printEnvironment;
###############################################################################
###############################################################################


###############################################################################
# Get the proper C compiler for conan.
#
# For more info, check:
# https://docs.conan.io/en/1.51/reference/config_files/settings.yml.html
###############################################################################
addCompilerPathForConan() {
  if echo "${compiler}" | grep -q "clang++.*"; then
    # Possible values for clang are ['3.3', '3.4', '3.5', '3.6', '3.7', '3.8', '3.9',
    # '4.0', '5.0', '6.0', '7.0', '7.1', '8', '9', '10', '11', '12', '13', '14', '15']
    conan_compiler='clang';
    echo 'Compiler version:';
    ${compiler} --version;
    echo 'Compiler version 2:';
    ${compiler} --version | grep -i version;
    echo 'Compiler version 3:';
    ${compiler} --version | grep -i version | sed 's/[ A-Za-z]//g' | awk -F '[^0-9]*' '{print $1}';
    conan_compiler_version=$(${compiler} --version | grep -i version | sed 's/[ A-Za-z]//g' | awk -F '[^0-9]*' '{print $1}' | head -1);
    export CXX="${conan_compiler}++";
    export CC="${conan_compiler}";
    export CFLAGS='-stdlib=libc++';
    export CXXFLAGS='-stdlib=libc++';
    conan_libcxx='libc++';
  elif echo "${compiler}" | grep -q "g++.*"; then
    export CXX='g++';
    export CC='gcc';
    #  Possible compiler values are ['Visual Studio', 'apple-clang', 'clang',
    # 'gcc', 'intel', 'intel-cc', 'mcst-lcc', 'msvc', 'qcc', 'sun-cc']
    if (uname -a | grep -iq 'darwin'); then
      # Possible values for Apple clang are ['5.0', '5.1', '6.0', '6.1', '7.0', '7.3',
      # '8.0', '8.1', '9.0', '9.1', '10.0', '11.0', '12.0', '13', '13.0', '13.1']
      echo 'Detected MacOS, so the C++ compiler should be apple-clang instead of old gcc.';
      conan_compiler='apple-clang';
      export CFLAGS='-stdlib=libc++';
      export CXXFLAGS='-stdlib=libc++';
      conan_libcxx='libc++';
    else
      # Possible values for gcc (Apple clang) are ['4.1', '4.4', '4.5', '4.6', '4.7',
      # '4.8', '4.9', '5', '5.1', '5.2', '5.3', '5.4', '5.5', '6', '6.1', '6.2', '6.3',
      # '6.4', '6.5', '7', '7.1', '7.2', '7.3', '7.4', '7.5', '8', '8.1', '8.2', '8.3',
      # '8.4', '9', '9.1', '9.2', '9.3', '9.4', '10', '10.1', '10.2', '10.3', '11',
      # '11.1', '11.2', '12']
      echo "Didn't detect MacOS, so the C++ compiler should be gcc.";
      conan_compiler='gcc';
      conan_libcxx='libstdc++';
    fi
    echo 'Compiler version:';
    ${compiler} -dumpversion;
    echo 'Compiler version 2:';
    ${compiler} -dumpversion | sed 's/[ A-Za-z]//g' | awk -F '[^0-9]*' '{print $1}';
    conan_compiler_version=$(${compiler} -dumpversion | sed 's/[ A-Za-z]//g' | awk -F '[^0-9]*' '{print $1}' | head -1);
  fi

  set +u; # Because of Windows OS doesn't have clang++ nor g++.
  # Fix compiler version used.
  if [ "${conan_compiler}" = 'apple-clang' ] && [ "${conan_compiler_version}" = '12' ]; then
    conan_compiler_version='12.0';
  fi
  if [ "${conan_compiler}" = 'clang' ] && [ "${conan_compiler_version}" = '6' ]; then
    conan_compiler_version='6.0';
  fi

  echo "Detected '${conan_compiler}' '${conan_compiler_version}' '(${conan_libcxx})' compiler.";
  set -u;
}

addCompilerPathForConan;
###############################################################################
###############################################################################


###############################################################################
# Get CPU Architecture.
###############################################################################
setCpuArchitecture() {
  CPU_ARCHITECTURE=x86_64;
  if command -v uname > /dev/null; then
    CPU_ARCHITECTURE=$(uname -m);
    if [ "${CPU_ARCHITECTURE}" = 'aarch64' ]; then
      CPU_ARCHITECTURE=armv8;
    fi
  fi
}

setCpuArchitecture;
###############################################################################
###############################################################################


###############################################################################
# Add Conan remote dependencies.
###############################################################################
# Install C++ Conan dependencies.
install_conan_dependencies() {
#  ln -s configure/config.guess /home/travis/.conan/data/libuuid/1.0.3/_/_/build/b818fa1fc0d3879f99937e93c6227da2690810fe/configure/config.guess;
#  ln -s configure/config.sub /home/travis/.conan/data/libuuid/1.0.3/_/_/build/b818fa1fc0d3879f99937e93c6227da2690810fe/configure/config.sub;

  addCommandToPath 'conan';
  echo 'Checking if conan is available.';
  if command -v conan > /dev/null; then
    echo 'Setting up conan.';
    conan profile new mobilert || true;
    conan profile update settings.compiler="${conan_compiler}" mobilert;
    conan profile update settings.compiler.version="${conan_compiler_version}" mobilert;
    conan profile update settings.compiler.libcxx="${conan_libcxx}" mobilert;
    conan profile update settings.compiler.cppstd=17 mobilert;
    # Possible values for compiler.libcxx for gcc are ['libstdc++', 'libstdc++11'].
    conan profile update settings.arch="${CPU_ARCHITECTURE}" mobilert;
    conan profile update settings.os='Linux' mobilert;
    conan profile update settings.build_type='Release' mobilert;
    conan remote add conancenter http://conan.io/center/ || true;

    echo 'Installing dependencies with conan.';
    conan_os='Linux';
    if uname -a | grep -iq 'darwin'; then
      conan_os='Macos';
    fi
    conan install \
      -s compiler="${conan_compiler}" \
      -s compiler.version="${conan_compiler_version}" \
      -s compiler.libcxx="${conan_libcxx}" \
      -s compiler.cppstd=17 \
      -s arch="${CPU_ARCHITECTURE}" \
      -s os="${conan_os}" \
      -s build_type=Release \
      -o bzip2:shared=True \
      -c tools.system.package_manager:mode=install \
      -c tools.system.package_manager:sudo=True \
      --build missing \
      --profile mobilert \
      --install-folder build_conan-native \
      ./app/third_party/conan/Native;

    export CONAN='TRUE';
    echo 'Done!';
  fi
}
###############################################################################
###############################################################################


###############################################################################
# Compile for native.
###############################################################################
create_build_folder() {
  # Set path to build.
  build_path=build_${type};

  typeWithCapitalLetter=$(capitalizeFirstletter "${type}");
  echo "type: '${typeWithCapitalLetter}'";

  if [ "${recompile}" = 'yes' ]; then
    rm -rf "${build_path:?Missing build path}"/*;
  fi
  mkdir -p "${build_path}";
}

build() {
  create_build_folder;
  oldpath=$(pwd);

  cd "${build_path}" || exit 1;
  addCommandToPath 'cmake';

  conanToolchainFile='../build_conan-native/conan_toolchain.cmake';

  echo 'Calling CMake';
  cmake --version;
  if [ "${compiler}" = 'clang++' ]; then
    c_compiler='clang';
  elif [ "${compiler}" = 'icpx' ]; then
    c_compiler='icx';
  elif [ "${compiler}" = 'cl' ]; then
    c_compiler='cl';
  else
    c_compiler='gcc';
  fi

  # The compiler might redirect the output to stderr, so we also have to redirect it to the variable.
  compiler_version=$(${compiler} -v 2>&1 || true);
  echo "Compiler version: ${compiler_version}";
  cmake --help;
  # shellcheck disable=SC2063
  generator=$(cmake --help | grep -i '*' | grep -v 'default' | cut -d '=' -f1 | cut -d '*' -f2 | cut -d ' ' -f2,3,4,5,6,7,8,9 | sed 's/^[ ]*//;s/[ ]*$//');
  # shellcheck disable=SC2063
  if cmake --help | grep -i '*' | grep -iq 'default' && cmake --help | grep -i '*' | grep -iq 'Visual Studio'; then
    if [ "${compiler}" = 'cl' ]; then
      echo 'Detected Visual Studio for Windows!';
      jobsFlags="//p:Configuration=${typeWithCapitalLetter} //m:$((NCPU_CORES * 1)) //p:CL_MPCount=$((NCPU_CORES - 1))";
      JOBS_FLAGS="-- ${jobsFlags}";
      export MAKEFLAGS="${jobsFlags}";
      export CMAKE_BUILD_PARALLEL_LEVEL="$((NCPU_CORES - 1))";
    else
      echo 'Detected MinGW!';
      generator='MinGW Makefiles';
      jobsFlags="-j$((NCPU_CORES * 3))";
      JOBS_FLAGS="-- ${jobsFlags}";
      export MAKEFLAGS="${jobsFlags}";
      export CMAKE_BUILD_PARALLEL_LEVEL="$((NCPU_CORES * 3))";
    fi
  elif cmake --help | grep -i '*' | grep -iq 'default' && cmake --help | grep -i '*' | grep -iq 'unix'; then
    echo 'Detected Make!';
    jobsFlags="-j$((NCPU_CORES * 2 - 1))";
    JOBS_FLAGS="-- ${jobsFlags}";
    export MAKEFLAGS="${jobsFlags}";
    export CMAKE_BUILD_PARALLEL_LEVEL="$((NCPU_CORES * 2 - 1))";
  elif cmake --help | grep -iq 'Visual Studio'; then
    echo "Didn't find a default generator. Enforcing usage of Unix Makefiles instead!";
    jobsFlags="-j$((NCPU_CORES * 3))";
    JOBS_FLAGS="-- ${jobsFlags}";
    export MAKEFLAGS="${jobsFlags}";
    export CMAKE_BUILD_PARALLEL_LEVEL="$((NCPU_CORES * 3))";
    generator='Unix Makefiles';
  else
    echo "Assuming NMake!";
    export CL="/MP$((NCPU_CORES * 2))";
    export CMAKE_BUILD_PARALLEL_LEVEL="$((NCPU_CORES * 2))";
    JOBS_FLAGS='';
  fi

  if [ -f "${conanToolchainFile}" ]; then
    addConanToolchain="-DCMAKE_TOOLCHAIN_FILE=${conanToolchainFile}";
    cmake \
      -G "${generator}" \
      -DCMAKE_VERBOSE_MAKEFILE=ON \
      -DCMAKE_CXX_COMPILER="${compiler}" \
      -DCMAKE_C_COMPILER="${c_compiler}" \
      -DCMAKE_C_SOURCE_FILE_EXTENSIONS="c" \
      -DCMAKE_BUILD_TYPE="${typeWithCapitalLetter}" \
       "${addConanToolchain}" \
      ../app;
  else
    cmake \
      -G "${generator}" \
      -DCMAKE_VERBOSE_MAKEFILE=ON \
      -DCMAKE_CXX_COMPILER="${compiler}" \
      -DCMAKE_C_COMPILER="${c_compiler}" \
      -DCMAKE_C_SOURCE_FILE_EXTENSIONS="c" \
      -DCMAKE_BUILD_TYPE="${typeWithCapitalLetter}" \
      ../app;
  fi

  resCompile=${?};
  echo 'Called CMake';

  if [ "${resCompile}" -eq 0 ]; then
    set +u;
    echo "Calling '${generator}' with parameters: '${JOBS_FLAGS}'";
    # shellcheck disable=SC2086
    cmake --build . ${JOBS_FLAGS};
    set -u;
    resCompile=${?};
  else
    echo 'Compilation: cmake failed';
  fi
  cd "${oldpath}" || exit 1;
}
###############################################################################
###############################################################################

echo "Detected Host OS: $(uname -a)";
#install_conan_dependencies;
createReportsFolders;
build;
validateNativeLibCompiled;
du -h -d 1 build_"${type}"/bin build_"${type}"/lib;

###############################################################################
# Exit code.
###############################################################################
printCommandExitCode "${resCompile}" 'Compilation';
###############################################################################
###############################################################################