Last active
September 12, 2026 13:29
-
-
Save mity/bb24f0625d9703911661228fab017e2a to your computer and use it in GitHub Desktop.
Helper CMake+Make/Ninja wrapper for MSYS2 environment.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Paths: | |
| TOOLCHAIN32_ROOT="/mingw32" | |
| TOOLCHAIN64_ROOT="/ucrt64" | |
| #TOOLCHAIN64_ROOT="/mingw64" # legacy, deprecated | |
| # Try to detect project root dir as a topmost dir with some of the files | |
| # which usually mark it as a project root dir: | |
| flist="CMakeLists.txt ChangeLog ChangeLog.txt ChangeLog.md LICENSE LICENSE.txt LICENSE.md COPYING COPYING.lib COPYING.txt COPYING.md" | |
| d=`pwd` | |
| while [ "$d" != "/" ]; do | |
| for f in $flist; do | |
| if [ -e "$d/$f" ]; then | |
| PRJ_ROOT="$d" | |
| fi | |
| done | |
| d=`dirname "$d"` | |
| done | |
| if [ -z "$PRJ_ROOT" ]; then | |
| echo "Cannot find project root dir." | |
| exit 1 | |
| fi | |
| # Defaults: | |
| BUILD_DIR="build" | |
| case "$MSYSTEM" in | |
| *64) BUILD_BITS="64";; | |
| *) BUILD_BITS="32";; | |
| esac | |
| BUILD_DIR_SUFFIX="debug" | |
| BUILD_TYPE="Debug" | |
| TARGET="" | |
| VERBOSE=no | |
| # Colorize our output (if stdout is terminal): | |
| if [ -t 1 ]; then | |
| red="\e[1;31m" | |
| green="\e[1;32m" | |
| cyan="\e[1;36m" | |
| endcolor="\e[0m" | |
| fi | |
| usage() | |
| { | |
| tool=`basename $0` | |
| printf "${tool}: Build the current project with CMake (and Ninja or GNU Make)\n" | |
| printf "Usage: ${tool} [option]...\n" | |
| printf "Usage: ${tool} [option]... build-target\n" | |
| printf "\nMain build options:\n" | |
| printf " --32 Build 32-bit binaries (default).\n" | |
| printf " --64 Build 64-bit binaries.\n" | |
| printf " -d --debug Build Debug (default).\n" | |
| printf " -r --release Build Release build.\n" | |
| printf "\nSpecial build options:\n" | |
| printf " -c --coverage Build with coverage profiling enabled (--coverage).\n" | |
| printf " -p --profile Build with profiling enabled (--pg).\n" | |
| printf " --pgo-generate Build auxiliary build for PGO (-fprofile-generate).\n" | |
| printf " --pgo-use Build with PGO (-fprofile-use).\n" | |
| printf " (Before using --pgo-use, the same build type has to be\n" | |
| printf " built with --pgo-generate and THAT build must be executed\n" | |
| printf " to collect profile data for --pgo-use.)\n" | |
| printf "\nAuxiliary options:\n" | |
| printf " -v --verbose Enable verbose mode.\n" | |
| printf " -h --help Write down this help.\n" | |
| } | |
| while [ $# -gt 0 ]; do | |
| case $1 in | |
| --32 | -32 | 32 ) | |
| BUILD_BITS="32" | |
| ;; | |
| --64 | -64 | 64 ) | |
| BUILD_BITS="64" | |
| ;; | |
| -d | --debug | -debug | debug ) | |
| BUILD_DIR_SUFFIX="debug" | |
| BUILD_TYPE="Debug" | |
| ;; | |
| -r | --rel | -rel | rel | --release | -release | release ) | |
| BUILD_DIR_SUFFIX="release" | |
| BUILD_TYPE="Release" | |
| ;; | |
| -c | --coverage | -coverage | coverage ) | |
| ENABLE_COVERAGE=yes | |
| ;; | |
| -p | --profile ) | |
| ENABLE_PG=yes | |
| ;; | |
| --pgo-generate | --fprofile-generate | -fprofile-generate ) | |
| ENABLE_PGO_GENERATE=yes | |
| ;; | |
| --pgo-use | --fprofile-use | -fprofile-use ) | |
| ENABLE_PGO_USE=yes | |
| ;; | |
| -v | --verbose ) | |
| VERBOSE=yes | |
| ;; | |
| -h | --help ) | |
| usage | |
| exit 0 | |
| ;; | |
| -* ) | |
| echo "Bad usage" | |
| usage | |
| exit 1 | |
| ;; | |
| * ) | |
| TARGET=$1 | |
| ;; | |
| esac | |
| shift | |
| done | |
| # Make sure the requested toolchain is the 1st in the path: | |
| if [ "$BUILD_BITS" -eq 64 ]; then | |
| export PATH="${TOOLCHAIN64_ROOT}/bin:${PATH}" | |
| else | |
| export PATH="${TOOLCHAIN32_ROOT}/bin:${PATH}" | |
| fi | |
| BUILD_DIR="${PRJ_ROOT}/${BUILD_DIR}${BUILD_BITS}-${BUILD_DIR_SUFFIX}" | |
| if [ "ENABLE_PGO_GENERATE$ENABLE_PGO_USE" = "yesyes" ]; then | |
| echo "Options --pgo-generate and --pgo-use cannot be used together." | |
| exit 1 | |
| fi | |
| if [ "$ENABLE_COVERAGE" = "yes" ]; then | |
| BUILD_DIR+="+coverage" | |
| fi | |
| if [ "$ENABLE_PGO_GENERATE" = "yes" ]; then | |
| BUILD_DIR+="+pgo_generate" | |
| fi | |
| if [ "$ENABLE_PGO_USE" = "yes" ]; then | |
| BUILD_DIR+="+pgo_use" | |
| fi | |
| if [ "$ENABLE_PG" = "yes" ]; then | |
| BUILD_DIR+="+prof" | |
| fi | |
| # Make sure the build dir exists and step into it: | |
| mkdir -p "$BUILD_DIR" | |
| cd "$BUILD_DIR" | |
| if [ "$ENABLE_COVERAGE" = "yes" ]; then | |
| CFLAGS="--coverage" | |
| LDFLAGS="--coverage" | |
| fi | |
| if [ "$ENABLE_PG" = "yes" ]; then | |
| CFLAGS="-pg -p -no-pie" | |
| LDFLAGS="-pg -p -no-pie" | |
| fi | |
| if [ "$ENABLE_PGO_GENERATE" = "yes" ]; then | |
| PROFILE_DATA_DIR="${BUILD_DIR}/data/pgo" | |
| # Make sure we don't update some stale/outdated profile data corresponding | |
| # to builds from old sources... | |
| rm -rf "${PROFILE_DATA_DIR}" | |
| CFLAGS="-fprofile-dir=${PROFILE_DATA_DIR} -fprofile-generate" | |
| LDFLAGS="-fprofile-dir=${PROFILE_DATA_DIR} -fprofile-generate" | |
| fi | |
| if [ "$ENABLE_PGO_USE" = "yes" ]; then | |
| SOURCE_PROFILE_DATA_DIR=`echo ${BUILD_DIR} | sed "s/pgo_use$/pgo_generate/"`"/data/pgo" | |
| PROFILE_DATA_DIR="${BUILD_DIR}/data/pgo" | |
| if [ ! -d "${SOURCE_PROFILE_DATA_DIR}" ]; then | |
| echo "Cannot use --pgo-use before the project is built with --pgo-generate and" | |
| echo "the profile data is collected in that build by running one or more executables." | |
| exit 1 | |
| fi | |
| # Copy PGO profile data from the corresponding pgo_generate build. | |
| rm -rf "${PROFILE_DATA_DIR}" | |
| mkdir -p "data" | |
| cp -r "${SOURCE_PROFILE_DATA_DIR}" "${PROFILE_DATA_DIR}" | |
| find "${PROFILE_DATA_DIR}" -name '*pgo_generate' | sed -e 'p;s/pgo_generate/pgo_use/' | xargs -n2 mv | |
| CFLAGS="-fprofile-dir=${PROFILE_DATA_DIR} -fprofile-use=${PROFILE_DATA_DIR}" | |
| LDFLAGS="-fprofile-dir=${PROFILE_DATA_DIR} -fprofile-use=${PROFILE_DATA_DIR}" | |
| fi | |
| printf "Building ${cyan}%s${endcolor} build in ${cyan}%s${endcolor}...\n" "$BUILD_TYPE" "$BUILD_DIR" | |
| # Use Ninja if available as it's much faster than Make: | |
| if which ninja >/dev/null 2>&1; then | |
| GENERATOR_NAME="Ninja" | |
| GENERATOR_FILE="rules.ninja" | |
| BUILDER="ninja" | |
| if [ "$VERBOSE" = "yes" ]; then | |
| BUILDER_OPTIONS="-v" | |
| fi | |
| else | |
| GENERATOR_NAME="Unix Makefiles" | |
| GENERATOR_FILE="Makefile" | |
| BUILDER="make" | |
| if [ "$VERBOSE" = "yes" ]; then | |
| BUILDER_OPTIONS="VERBOSE=1" | |
| fi | |
| fi | |
| # Generate build files: | |
| if [ ! -f "${GENERATOR_FILE}" ]; then | |
| CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" \ | |
| cmake -G "${GENERATOR_NAME}" -DCMAKE_BUILD_TYPE="$BUILD_TYPE" "$PRJ_ROOT" | |
| fi | |
| if [ "$ENABLE_COVERAGE" = "yes" ]; then | |
| printf "\n" | |
| printf "1. Now you need to execute one (or more) executable(s) in order to generate\n" | |
| printf " the profile data.\n" | |
| printf "\n" | |
| printf "2. Then you can study coverage of individual source files e.g. with command\n" | |
| printf " ${green}$ gcov PATH_TO_SOURCE -o PATH_TO_OBJFILE${endcolor}\n" | |
| printf " which creates a human readable *.gcov file.\n" | |
| printf "\n" | |
| fi | |
| if [ "$ENABLE_PROFILE" = "yes" ]; then | |
| printf "\n" | |
| printf "1. Now you need to execute one (or more) executable(s) in order to generate\n" | |
| printf " the profile data.\n" | |
| printf "\n" | |
| printf "2. Then you can create profiling report with this command:\n" | |
| printf " ${green}$ gprof path/to/the/executable gmon.out > analysis.txt${endcolor}\n" | |
| printf "\n" | |
| fi | |
| if [ "$ENABLE_PGO_GENERATE" = "yes" ]; then | |
| printf "\n" | |
| printf "1. Now you need to execute one (or more) executable(s) in order to collect\n" | |
| printf " the profile data.\n" | |
| printf "\n" | |
| printf "2. When done, start the final build with the command\n" | |
| printf " ${green}$ %s %s${endcolor}\n" "$0" `echo "$@" | sed 's/-generate/-use/g'` | |
| printf "\n" | |
| fi | |
| if [ "$ENABLE_PGO_USE" = "yes" ]; then | |
| # Clean to enforce complete rebuild with an up-to-date PGO profile. | |
| "${BUILDER}" clean | |
| fi | |
| # The build: | |
| "${BUILDER}" ${BUILDER_OPTIONS} ${TARGET} | |
| STATUS=$? | |
| exit $STATUS |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment