Created
December 9, 2015 00:50
-
-
Save tamaskenez/d4509f240f4224eb9853 to your computer and use it in GitHub Desktop.
Execute multiple `cmake` commands with a single `cmakex` command.
This file contains 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 -e | |
# | |
# cmakex | |
# ====== | |
# | |
# Execute multiple `cmake` commands with a single `cmakex` command. | |
# Also, enable the CMAKE_INSTALL_PREFIX environment variable | |
# | |
# SYNOPSYS | |
# -------- | |
# | |
# cmakex [c][b][i][t][d][r][w] [cmake-options...] | |
# | |
# The first (compulsory) parameter is a single word (the command word) | |
# which is composed of the letters listed above. It is followed by options | |
# for the `cmake` command (configure and build steps) | |
# | |
# DESCRIPTION | |
# ----------- | |
# | |
# The three dimensions of the cmake comands are: | |
# | |
# 1. steps (configure, build/install, test) | |
# 2. configuratons (Debug, Release, ...) | |
# 3. targets | |
# | |
# You can use the `cmakex` command to execute multiple `cmake` commands | |
# for the specified steps, configurations and targets. | |
# | |
# As a quick example, here's how to configure, install and test a project | |
# from scrach, for `Debug` and `Release` configurations: | |
# | |
# cd project_source_dir | |
# CMAKE_INSTALL_PREFIX=$PWD/out cmakex citdr -H. -Bb | |
# | |
# `cmakex` also hides the difference between regular and multiconfig | |
# generators (Visual Studio and Xcode) regarding the `--config` and | |
# `-DCMAKE_BUILD_TYPE` options. | |
# | |
# As an added convenience it forwards the values of the | |
# CMAKE_PREFIX_PATH, CMAKE_INSTALL_PREFIX and CMAKE_MODULE_PATH | |
# environment variable to the CMake configuration | |
# step (by setting these as cache variables) | |
# | |
# Note: CMAKE_PREFIX_PATH as an environment variable is already supported | |
# by `cmake` but is not remembered in the cache. See details below. | |
# | |
# The Command Word | |
# ---------------- | |
# | |
# The first parameter is the command word. The order of the letters is not | |
# important. The meanings of the letters are: | |
# | |
# - c: Configure step, that is `cmake ...` (no `--build`) | |
# - b: Build step, that is `cmake --build ...` | |
# - i: Install step, that is `cmake --build ... --target install ...` | |
# - t: Test step, that is `ctest` | |
# - d, r, w: | |
# Configurations `Debug`, `Release` and `RelWithDebInfo` | |
# Multiple configurations can be specified. | |
# | |
# CMake Options | |
# ------------- | |
# | |
# After the command word you can specify | |
# | |
# - any options the cmake command accepts (the normal, non-build mode) | |
# - `--target <tgt>` (also multiple times) | |
# - `--config <cfg>` (also multiple times) | |
# - `--clean-first` | |
# - double-dash "--" followed by options to the native build tool | |
# | |
# CMAKE_INSTALL_PREFIX, CMAKE_PREFIX_PATH, CMAKE_MODULE_PATH | |
# ---------------------------------------------------------- | |
# | |
# When calling the `cmake` configuration step, if any of these environment | |
# variables are defined, `cmakex` adds it to the command line: | |
# | |
# -DCMAKE_INSTALL_PREFIX=$CMAKE_INSTALL_PREFIX | |
# -DCMAKE_PREFIX_PATH=$CMAKE_PREFIX_PATH | |
# -DCMAKE_MODULE_PATH=$CMAKE_MODULE_PATH | |
# | |
# If an environment variable is not defined or empty than it won't be | |
# removed from the cache. | |
# | |
# Note that CMAKE_PREFIX_PATH is already supported by `cmake` as an | |
# environment variable but it's not retained in the cache. With `cmakex` | |
# it will be. | |
# | |
# You need to specify the 'c' step for this to work. The possible automatic | |
# cmake reconfiguration before `--build` will not pick up the environment | |
# variables. | |
# | |
# Examples: | |
# --------- | |
# | |
# Install the 'Debug' and 'Release' configs: | |
# | |
# cmakex cidr -Hsource_dir -Bbuild_dir -DMY_OPTION=something | |
# | |
# Test the 'Release' config: | |
# | |
# cd build_dir | |
# cmakex tr . | |
# | |
# Note, that the configure/build steps are omitted in that case. | |
# To execute the build step, use: | |
# | |
# cd build_dir | |
# cmakex btr . | |
# | |
# To test a project which has not been configured yet: | |
# | |
# cd build_dir | |
# cmakex cbtr . | |
# | |
# or | |
# | |
# cmakex cbtr -Hsource_dir -Bbuild_dir | |
# | |
if [[ -z $1 ]]; then | |
echo "No arguments. For help see this file ($0)" >&2 | |
exit 1 | |
fi | |
command_word=$1 | |
shift | |
unparsed=$command_word | |
for c in c b i t r d w; do | |
eval unset arg_$c | |
done | |
while [[ -n $unparsed ]]; do | |
c=${unparsed:0:1} | |
unparsed=${unparsed:1} | |
case $c in | |
c ) arg_c=1;; | |
b ) arg_b=1;; | |
i ) arg_i=1;; | |
t ) arg_t=1;; | |
r ) arg_r=1;; | |
d ) arg_d=1;; | |
w ) arg_w=1;; | |
* ) | |
echo "Invalid char in first argument: $c" >&2 | |
exit 1 | |
esac | |
done | |
unset configs | |
if [[ -n $arg_d ]]; then | |
configs="$configs Debug" | |
fi | |
if [[ -n $arg_w ]]; then | |
configs="$configs RelWithDebInfo" | |
fi | |
if [[ -n $arg_r ]]; then | |
configs="$configs Release" | |
fi | |
unset binary_dir | |
unset source_dir | |
unset config_args | |
unset build_args | |
unset native_tool_args | |
unset build_targets | |
unset config_args_besides_binary_dir | |
if [[ -n $arg_i ]]; then | |
build_targets="$build_targets install" | |
fi | |
while (( $# )); do | |
if [[ -z ${native_tool_args+1} ]]; then | |
if [[ "$1" == "--" ]]; then | |
native_tool_args=('--') | |
elif [[ "$1" == "--target" ]]; then | |
shift | |
if [[ -n "$1" ]]; then | |
build_targets="$build_targets $1" | |
else | |
echo "Missing target name after '--target'" >&2 | |
exit 1 | |
fi | |
elif [[ "$1" == "--config" ]]; then | |
shift | |
if [[ -n "$1" ]]; then | |
configs="$configs $1" | |
else | |
echo "Missing config name after '--config'" >&2 | |
exit 1 | |
fi | |
elif [[ "$1" =~ ^(--clean-first|--use-stderr)$ ]]; then | |
build_args+=("$1") | |
else | |
config_args+=("$1") | |
if [[ "$1" =~ ^-H.+ ]]; then | |
source_dir="${1:2}" | |
config_args_besides_binary_dir=1 | |
elif [[ "$1" =~ ^-B.+ ]]; then | |
binary_dir="${1:2}" | |
elif [[ "$1" =~ ^(-C|-D|-U|-G|-T|-A)$ ]]; then | |
shift | |
config_args+=("$1") | |
config_args_besides_binary_dir=1 | |
elif [[ "${1:0:1}" != '-' ]]; then | |
if [[ -f "$1/CMakeLists.txt" ]]; then | |
source_dir="$1" | |
config_args_besides_binary_dir=1 | |
elif [[ -f "$1/CMakeCache.txt" ]]; then | |
binary_dir="$1" | |
else | |
echo "$1 is neither a valid source dir (no CMakeLists.txt), " \ | |
"nor an existing binary dir (no CMakeCache.txt)" >&2 | |
exit 1 | |
fi | |
else | |
config_args_besides_binary_dir=1 | |
fi | |
fi | |
else | |
native_tool_args+=("$1") | |
fi | |
shift | |
done | |
if [[ -z "$binary_dir" ]]; then | |
binary_dir="$PWD" | |
fi | |
if [[ -n "$source_dir" ]]; then | |
echo "CMAKE_SOURCE_DIR: $source_dir" | |
fi | |
echo "CMAKE_BINARY_DIR: $binary_dir" | |
if [[ -n "$build_targets" ]]; then | |
echo "targets: $build_targets" | |
fi | |
if [[ -n "$configs" ]]; then | |
echo "configurations: $configs" | |
fi | |
#echo "config_args: ${config_args[@]}" | |
#echo "build_args: ${build_args[@]}" | |
#echo "native_tool_args: ${native_tool_args[@]}" | |
if [[ -z "$configs" ]]; then | |
configs=- | |
fi | |
if [[ -n $arg_b && -z "$build_targets" ]]; then | |
build_targets=- | |
fi | |
unset config_env_arg | |
if [[ -n "$CMAKE_INSTALL_PREFIX" ]]; then | |
config_env_arg+=("-DCMAKE_INSTALL_PREFIX:PATH=$CMAKE_INSTALL_PREFIX") | |
fi | |
if [[ -n "$CMAKE_PREFIX_PATH" ]]; then | |
config_env_arg+=("-DCMAKE_PREFIX_PATH:STRING=$CMAKE_PREFIX_PATH") | |
fi | |
if [[ -n "$CMAKE_MODULE_PATH" ]]; then | |
config_env_arg+=("-DCMAKE_MODULE_PATH:STRING=$CMAKE_MODULE_PATH") | |
fi | |
for config in $configs; do | |
if [[ $config == - ]]; then | |
unset config_config_arg | |
unset build_config_arg | |
unset test_config_arg | |
else | |
config_config_arg="-DCMAKE_BUILD_TYPE=$config" | |
build_config_arg="--config $config" | |
test_config_arg="-C $config" | |
fi | |
# configure step | |
if [[ -n $arg_c ]]; then | |
(set -x; cmake $config_config_arg "${config_env_arg[@]}" "${config_args[@]}") | |
elif [[ -n $config_args_besides_binary_dir ]]; then | |
echo -e "You specified args for the cmake configuration step besides binary dir:\n"\ | |
"\t${config_args[@]}\n"\ | |
"but the 'c' option is missing from the command word: \"$command_word\"" >&2 | |
exit 1 | |
fi | |
# build step | |
for target in $build_targets; do | |
if [[ $target == - ]]; then | |
unset build_target_arg | |
else | |
build_target_arg="--target $target" | |
fi | |
echo "bta $build_target_arg" | |
(set -x; cmake --build "$binary_dir" $build_args $build_target_arg $build_config_arg "${native_tool_args[@]}") | |
done | |
# test step | |
if [[ -n $arg_t ]]; then | |
pushd "$binary_dir" >/dev/null | |
(set -x; ctest $test_config_arg) | |
popd >/dev/null | |
fi | |
done | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment