Last active
October 17, 2023 22:51
-
-
Save wheresjames/a34513d28679b4129084b21c0b01b8a6 to your computer and use it in GitHub Desktop.
CMake build script for Visual Studio
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 | |
# http://github.com/wheresjames | |
# Run this from the command line like | |
# | |
# $ ~/path/to/cmake-tasks.sh clean-config-build release build ./some/cmake/project | |
# | |
# OR | |
# | |
# $ cd ./some/cmake/project | |
# $ ./cmake-tasks.sh clean-config-build release | |
# | |
# OR | |
# | |
# You can use this in Visual studio by adding something like the | |
# following to your tasks.json file. | |
# On linux usually at ~/.config/Code/User/tasks.json | |
# | |
# { | |
# "label": "CMake: Release Rebuild", | |
# "type": "shell", | |
# "command": "~/code/tasks/cmake-tasks.sh", | |
# "args": [ | |
# "clean-config-build", | |
# "release", | |
# "build", | |
# "${fileDirname}", | |
# "${file}", | |
# "${workspaceFolder}" | |
# ], | |
# "problemMatcher": { | |
# "fileLocation": ["relative", "~/code/tasks"], | |
# "pattern": { | |
# "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error|note):\\s*(.*)$", | |
# "file": 1, | |
# "line": 2, | |
# "column": 3, | |
# "severity": 4, | |
# "message": 5 | |
# } | |
# }, | |
# "group": { | |
# "kind": "build", | |
# "isDefault": true | |
# } | |
# }, | |
#============================================================================== | |
# Parse arguments | |
#============================================================================== | |
ACTIONS=$1 | |
BUILDTYPE=$2 | |
BUILDSUB=$3 | |
FILEDIR=$4 | |
FILENAME=$5 | |
WORKSPACE=$6 | |
if [ -z "$ACTIONS" ]; then | |
echo "No action specified" | |
exit 1 | |
fi | |
if [ -z "$BUILDTYPE" ]; then | |
BUILDTYPE="release" | |
fi | |
if [ -z "$BUILDSUB" ]; then | |
BUILDSUB="build" | |
fi | |
#============================================================================== | |
# Functions | |
#============================================================================== | |
# Include utils | |
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" | |
. "${SCRIPT_DIR}/utils.sh" | |
#============================================================================== | |
# Variables | |
#============================================================================== | |
# Strip part of path below components with ':' or '=' in it | |
# Example: | |
# /run/user/1000/gvfs/sftp:host=192.168.50.127/Users/bob/code/some/path | |
# becomes | |
# /Users/bob/code/some/path | |
FILEDIR=$(strip_path "$FILEDIR" [:=]) | |
FILENAME=$(strip_path "$FILENAME" [:=]) | |
WORKSPACE=$(strip_path "$WORKSPACE" [:=]) | |
# Find cmake | |
CMAKEEXE= | |
CMAKEPATHS="$(which cmake),/usr/bin/cmake,/usr/local/bin/cmake,/opt/homebrew/bin/cmake" | |
for path in ${CMAKEPATHS//,/ }; do | |
if [ -f "$path" ]; then | |
CMAKEEXE="$path" | |
break | |
fi | |
done | |
if [ -z "$CMAKEEXE" ]; then | |
echo "[ERROR] !!! Could not find cmake executable" | |
exit 1 | |
fi | |
echo "-------------------------------------------" | |
echo "[::] CMake executable : $CMAKEEXE" | |
echo "[::] Actions : $ACTIONS" | |
echo "[::] Build type : $BUILDTYPE" | |
echo "[::] File directory : $FILEDIR" | |
echo "[::] File name : $FILENAME" | |
echo "[::] Workspace : $WORKSPACE" | |
echo "[::] Script directory : $SCRIPT_DIR" | |
echo "[::] Working directory: $PWD" | |
echo "-------------------------------------------" | |
# Look for cmake file in file directory | |
CMAKEFILE=$(find_file "$FILEDIR,$WORKSPACE,$PWD" \ | |
"CMakeLists.txt" \ | |
".git .editorconfig LICENSE README.md") | |
if [ -z "$CMAKEFILE" ]; then | |
echo "Could not find CMakeLists.txt" | |
exit 1 | |
fi | |
BUILDROOT=$(dirname "$CMAKEFILE") | |
# Change to cmake file directory | |
cd "$BUILDROOT" | |
# Build out directory | |
BUILDOUT="$BUILDROOT/$BUILDSUB/$BUILDTYPE" | |
echo "[::] CMake file : $CMAKEFILE" | |
echo "[::] Build root : $BUILDROOT" | |
echo "[::] Build out : $BUILDOUT" | |
echo "-------------------------------------------" | |
# Do we have a PROJECT.txt file? | |
# Example PROJECT.txt file | |
# | |
# name cmtasks | |
# version 0.1.0 | |
# description CMake build tasks | |
# company wheresjames | |
# author Robert Umbehant | |
# email [email protected] | |
# url https://github.com/wheresjames/cmtasks | |
# repo git+ssh://[email protected]/wheresjames/cmtasks.git | |
# bugs https://github.com/wheresjames/cmtasks/issues | |
# license MIT | |
# | |
PROJECTFILE="$BUILDROOT/PROJECT.txt" | |
if [ -f "$PROJECTFILE" ]; then | |
load_config "APP" "$PROJECTFILE" | |
else | |
PROJECTFILE= | |
fi | |
if [ -z "$APPNAME" ]; then | |
APPNAME=$(basename "$BUILDROOT") | |
fi | |
echo "[::] Project file : $PROJECTFILE" | |
echo "-------------------------------------------" | |
dump_vars "^APP" "[::] " " : " | |
echo "-------------------------------------------" | |
#============================================================================== | |
# Actions | |
#============================================================================== | |
#------------------------------------------------------------ | |
# Clean | |
if find_in_str "clean" "$ACTIONS"; then | |
echo "[::] --- Cleaning ---" | |
if [ -d "$BUILDOUT" ]; then | |
echo "[::] Removing $BUILDOUT" | |
rm -rf "$BUILDOUT" | |
fi | |
fi | |
#------------------------------------------------------------ | |
# Configure | |
if find_in_str "config" "$ACTIONS"; then | |
echo "[::] --- Configuring ---" | |
# search for CMAKE OPTIONS file (CMakeOpts.<$BUILDTYPE>.txt) | |
OPTS= | |
OPTSFILE=$(find_file "$BUILDROOT" "CMakeOpts.${BUILDTYPE}.txt") | |
if [ ! -f "$OPTSFILE" ]; then | |
OPTSFILE=$(find_file "$BUILDROOT" "CMakeOpts.txt") | |
fi | |
if [ ! -f "$OPTSFILE" ]; then | |
echo "[::] CMakeOpts.txt file not found" | |
else | |
OPTS=$(cat "$OPTSFILE") | |
echo "[::] CMakeOpts.txt : $OPTSFILE" | |
echo "[::] CMake options : $OPTS" | |
fi | |
if [ ! -d "$BUILDOUT" ]; then | |
mkdir -p "$BUILDOUT" | |
fi | |
$CMAKEEXE . -B "$BUILDOUT" -DCMAKE_BUILD_TYPE=$BUILDTYPE $OPTS | |
fi | |
#------------------------------------------------------------ | |
# Build | |
if find_in_str "build" "$ACTIONS"; then | |
echo "[::] --- Building ---" | |
if [ ! -d "$BUILDOUT" ]; then | |
echo "Could not find build directory: $BUILDOUT" | |
exit 1 | |
fi | |
$CMAKEEXE --build "$BUILDOUT" | |
fi | |
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 | |
# http://github.com/wheresjames | |
## Return the name of the operating system | |
os_name() | |
{ | |
if [[ "$OSTYPE" == "linux-gnu"* ]]; then | |
echo "linux" | |
elif [[ "$OSTYPE" == "darwin"* ]]; then | |
echo "darwin" | |
else | |
echo "$OSTYPE" | |
fi | |
} | |
## Converts string to all upper case | |
# @param [0] - String to convert | |
# @returns string converted to upper case | |
to_upper() | |
{ | |
if [[ $(os_name) == "darwin"* ]]; then | |
echo "$(echo "$1" | awk '{print toupper($0)}')" | |
else | |
echo "${1^^}" | |
fi | |
} | |
## Strip leading path while it matches STRIP | |
# @param [0] PATH - The path to strip | |
# @param [1] STRIP - The string to strip | |
strip_path() | |
{ | |
local PATH=$1 | |
local STRIP=$2 | |
local LAST= | |
local PREFIX= | |
while [ "$LAST" != "$PATH" ] && [[ "$PATH" =~ $STRIP ]]; do | |
LAST="${PATH}" | |
PATH="${PATH#*/}" | |
PREFIX="/" | |
done | |
echo "${PREFIX}${PATH}" | |
} | |
## Find a file in a directory or parent directory | |
# @param [0] ROOT - Comma separated list of roots to search | |
# @param [1] FILENAME - The file name to search for | |
# @param [2] DEEP - List of sub directory names, that if exists | |
# as a file or directory, use this deeper match | |
find_file() | |
{ | |
local ROOT=$1 | |
local FILENAME=$2 | |
local DEEP=$3 | |
local FOUND= | |
# Search each root | |
for root in ${ROOT//,/ }; do | |
while [ ${#root} -gt 2 ] && [ -d "${root}" ]; do | |
for file in `ls $root`; do | |
if [ -f $root"/"$file ]; then | |
if [ "$file" = "$FILENAME" ] | |
then | |
if [ -z "$DEEP" ]; then | |
echo "$root/$file" | |
return | |
else | |
if [ -z "$FOUND" ]; then | |
FOUND="$root/$file" | |
else | |
for sub in ${DEEP// / }; do | |
if [ -e "$root/$sub" ]; then | |
FOUND="$root/$file" | |
fi | |
done | |
fi | |
fi | |
fi | |
fi | |
done | |
root=$(dirname $root) | |
done | |
if [ ! -z "$FOUND" ]; then | |
echo "$FOUND" | |
return | |
fi | |
done | |
} | |
## Find a string in a string | |
# @param [0] FIND - The string to find | |
# @param [1] STR - The string to search | |
# @return The index of the first character of the first occurrence of FIND in STR | |
find_in_str() | |
{ | |
local FIND=$1 | |
local STR=$2 | |
if [ -z "$STR" ] || [ -z "$FIND" ]; then | |
return 1 | |
fi | |
if [ ${#FIND} -gt ${#STR} ]; then | |
return 1 | |
fi | |
local I=0 | |
local LEN=${#STR} | |
local FINDLEN=${#FIND} | |
local MAX=$((LEN-FINDLEN)) | |
while [ $I -le $MAX ]; do | |
if [ "${STR:$I:$FINDLEN}" = "$FIND" ]; then | |
return 0 | |
fi | |
I=$((I+1)) | |
done | |
return 1 | |
} | |
## Load a config file | |
# @param [0] PREFIX - Prefix to add to each key | |
# @param [1] CONFIG_FILE - The config file to load | |
# @return 0 on success, 1 on failure | |
# @note This function will set global variables | |
# | |
# Example config file | |
# | |
# name cmtasks | |
# version 0.1.0 | |
# description CMake build tasks | |
# company wheresjames | |
# author Robert Umbehant | |
# email [email protected] | |
# url https://github.com/wheresjames/cmtasks | |
# repo git+ssh://[email protected]/wheresjames/cmtasks.git | |
# bugs https://github.com/wheresjames/cmtasks/issues | |
# license MIT | |
# | |
load_config() | |
{ | |
local PREFIX=$1 | |
local CONFIG_FILE=$2 | |
if [ -z "$CONFIG_FILE" ]; then | |
echo "No config file specified" | |
return 1 | |
fi | |
if [ ! -f "$CONFIG_FILE" ]; then | |
echo "Config file not found: $CONFIG_FILE" | |
return 1 | |
fi | |
while read line; do | |
if [ -z "$line" ]; then | |
continue | |
fi | |
# Skip comments | |
if [ "${line:0:1}" = "#" ]; then | |
continue | |
fi | |
# Split line into key and value | |
local KEY=${line%% *} | |
local VAL=${line#* } | |
# Convert key to upercase | |
KEY=$(to_upper "$KEY") | |
# Trim leading and trailing whitespace | |
VAL="${VAL#"${VAL%%[![:space:]]*}"}" | |
# Set key | |
declare -g "${PREFIX}${KEY}=${VAL}" | |
done < "$CONFIG_FILE" | |
} | |
## Dump all variables matching FIND | |
# @param [0] FIND - Regex to match variable name | |
# @param [1] PREFIX - Prefix to add to each output line | |
# @param [2] PADDING - Padding to add to key name | |
dump_vars() | |
{ | |
local FIND=$1 | |
local PREFIX=$2 | |
local PADDING=$3 | |
local KEY= | |
local KEYSTR= | |
while IFS= read -r line; do | |
KEY="${line#declare -[\-a-zA-Z ]* }" | |
KEY="${KEY%%=*}" | |
if [[ "$KEY" =~ $FIND ]]; then | |
if [ ! -z "$PADDING" ]; then | |
local LKEY=${#KEY} | |
local LPAD=${#PADDING} | |
if [ $LKEY -gt $(($LPAD-3)) ]; then | |
LKEY=$(($LPAD-3)) | |
fi | |
KEYSTR="${KEY:0:$LKEY}${PADDING:$LKEY}" | |
else | |
KEYSTR="${KEY} ? " | |
fi | |
echo "${PREFIX}${KEYSTR}${!KEY}" | |
fi | |
done < <(declare -p) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment