SCF : Add manual static check framework
This patch sets up the structure for a basic static check framework for
TFM. The scripts should be called from the TFM repo and reports from the
tools will be stored under a check_reports directory in the TFM repo.
The cppcheck tool is added in this patch.
Signed-off-by: Hugo L'Hostis <hugo.lhostis@arm.com>
Change-Id: I56e648abf2c0c04cce0da3a3535481164231499f
diff --git a/static_checks/README.rst b/static_checks/README.rst
new file mode 100644
index 0000000..3fdd48a
--- /dev/null
+++ b/static_checks/README.rst
@@ -0,0 +1,33 @@
+#########################
+Static Checking Framework
+#########################
+
+This tool has been made to provide a framework to check the truster-firmware-m
+(TF-M) code base.
+
+************
+Instructions
+************
+
+This tool should be used from the root of the TF-M repository. launching
+run_all_checks.sh will launch the different checkers used :
+
+- Cppcheck
+- Copyright header check
+- clang-format
+
+Each tool will be configured using a setup.sh script located under the tool
+directory before being launched. The main script might need to be launched with
+root priviledges in order to correctly install the tools on the first time it
+is being used.
+
+The tool will return exit code of 0 if everything is compliant, and no
+new warnings are generated, and 1 in all other occasions.
+
+Output reports if produced by each corresponding script, will be stored at
+`{TFM-Root}/checks_reports``
+
+--------------
+
+*Copyright (c) 2021, Arm Limited. All rights reserved.*
+*SPDX-License-Identifier: BSD-3-Clause*
\ No newline at end of file
diff --git a/static_checks/cppcheck/README.rst b/static_checks/cppcheck/README.rst
new file mode 100644
index 0000000..bc4d54c
--- /dev/null
+++ b/static_checks/cppcheck/README.rst
@@ -0,0 +1,42 @@
+########
+Cppcheck
+########
+cppcheck is a tool used to check a number of checks on the codebase. The list
+of all the checks is available at :
+https://sourceforge.net/p/cppcheck/wiki/ListOfChecks/
+
+******************
+tool configuration
+******************
+
+This tool is using the pre-existing cppcheck configurations
+(arm-cortex-m.cfg/tfm-suppress-list.txt), implementing the developer's
+guidelines, as used by the TF-M CI.
+
+The suppression list contains:
+
+ - Files that are not guaranteed to comply with the TF-M rules.
+ - Files under directories that correspond to external libraries.
+
+The files utils.sh, arm-cortex-cfg.cfg and tfm-suppress-list.txt were copied
+from the CI scripts repo :
+https://review.trustedfirmware.org/admin/repos/ci/tf-m-ci-scripts
+
+***************
+Using this tool
+***************
+
+This script must be launched from the TFM repo and the reports will be stored
+under checks_reports if the xml option is selected. The possible parameters are
+the following:
+
+ - '-h' display the help for this tool
+ - '-r' select the raw output option. If this parameter is selected, the
+ output will be displayed in the console instead of stored in an xml file
+
+
+
+--------------
+
+*Copyright (c) 2021, Arm Limited. All rights reserved.*
+*SPDX-License-Identifier: BSD-3-Clause*
diff --git a/static_checks/cppcheck/config/arm-cortex-m.cfg b/static_checks/cppcheck/config/arm-cortex-m.cfg
new file mode 100644
index 0000000..fc554b5
--- /dev/null
+++ b/static_checks/cppcheck/config/arm-cortex-m.cfg
@@ -0,0 +1,89 @@
+<?xml version="1.0"?>
+<!--
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+-->
+<def format="2">
+ <!-- Minimum-width integer types -->
+ <podtype name="int_least8_t" sign="s" size="1"/>
+ <podtype name="uint_least8_t" sign="u" size="1"/>
+ <podtype name="int_least16_t" sign="s" size="2"/>
+ <podtype name="uint_least16_t" sign="u" size="2"/>
+ <podtype name="int_least32_t" sign="s" size="4"/>
+ <podtype name="uint_least32_t" sign="u" size="4"/>
+ <podtype name="int_least64_t" sign="s" size="8"/>
+ <podtype name="uint_least64_t" sign="u" size="8"/>
+ <!-- Greatest-width integer types -->
+ <podtype name="intmax_t" sign="s" size="8"/>
+ <podtype name="uintmax_t" sign="u" size="8"/>
+ <!-- inttypes.h -->
+ <podtype name="intptr_t" sign="s" size="4"/>
+ <podtype name="uintptr_t" sign="u" size="4"/>
+ <define name="INT8_MAX" value="0x7f"/>
+ <define name="INT8_MIN" value="(-INT8_MAX - 1)"/>
+ <define name="UINT8_MAX" value="(__CONCAT(INT8_MAX, U) * 2U + 1U)"/>
+ <define name="INT16_MAX" value="0x7fff"/>
+ <define name="INT16_MIN" value="(-INT16_MAX - 1)"/>
+ <define name="UINT16_MAX" value="(__CONCAT(INT16_MAX, U) * 2U + 1U)"/>
+ <define name="INT32_MAX" value="0x7fffffffL"/>
+ <define name="INT32_MIN" value="(-INT32_MAX - 1L)"/>
+ <define name="UINT32_MAX" value="(__CONCAT(INT32_MAX, U) * 2UL + 1UL)"/>
+ <define name="INT64_MAX" value="0x7fffffffffffffffLL"/>
+ <define name="INT64_MIN" value="(-INT64_MAX - 1LL)"/>
+ <define name="UINT64_MAX" value="(__CONCAT(INT64_MAX, U) * 2ULL + 1ULL)"/>
+ <!-- Limits of minimum-width integer types -->
+ <define name="INT_LEAST8_MAX" value="INT8_MAX"/>
+ <define name="INT_LEAST8_MIN" value="INT8_MIN"/>
+ <define name="UINT_LEAST8_MAX" value="UINT8_MAX"/>
+ <define name="INT_LEAST16_MAX" value="INT16_MAX"/>
+ <define name="INT_LEAST16_MIN" value="INT16_MIN"/>
+ <define name="UINT_LEAST16_MAX" value="UINT16_MAX"/>
+ <define name="INT_LEAST32_MAX" value="INT32_MAX"/>
+ <define name="INT_LEAST32_MIN" value="INT32_MIN"/>
+ <define name="UINT_LEAST32_MAX" value="UINT32_MAX"/>
+ <define name="INT_LEAST64_MAX" value="INT64_MAX"/>
+ <define name="INT_LEAST64_MIN" value="INT64_MIN"/>
+ <define name="UINT_LEAST64_MAX" value="UINT64_MAX"/>
+ <!-- Limits of fastest minimum-width integer types -->
+ <define name="INT_FAST8_MAX" value="INT8_MAX"/>
+ <define name="INT_FAST8_MIN" value="INT8_MIN"/>
+ <define name="UINT_FAST8_MAX" value="UINT8_MAX"/>
+ <define name="INT_FAST16_MAX" value="INT16_MAX"/>
+ <define name="INT_FAST16_MIN" value="INT16_MIN"/>
+ <define name="UINT_FAST16_MAX" value="UINT16_MAX"/>
+ <define name="INT_FAST32_MAX" value="INT32_MAX"/>
+ <define name="INT_FAST32_MIN" value="INT32_MIN"/>
+ <define name="UINT_FAST32_MAX" value="UINT32_MAX"/>
+ <define name="INT_FAST64_MAX" value="INT64_MAX"/>
+ <define name="INT_FAST64_MIN" value="INT64_MIN"/>
+ <define name="UINT_FAST64_MAX" value="UINT64_MAX"/>
+ <!-- Limits of integer types capable of holding object pointers -->
+ <define name="INTPTR_MAX" value="INT32_MAX"/>
+ <define name="INTPTR_MIN" value="INT32_MIN"/>
+ <define name="UINTPTR_MAX" value="UINT32_MAX"/>
+ <!-- Limits of greatest-width integer types -->
+ <define name="INTMAX_MAX" value="INT64_MAX"/>
+ <define name="INTMAX_MIN" value="INT64_MIN"/>
+ <define name="UINTMAX_MAX" value="UINT64_MAX"/>
+ <!-- Limits of other integer types -->
+ <define name="PTRDIFF_MAX" value="INT32_MAX"/>
+ <define name="PTRDIFF_MIN" value="INT32_MIN"/>
+ <define name="SIG_ATOMIC_MAX" value="INT8_MAX"/>
+ <define name="SIG_ATOMIC_MIN" value="INT8_MIN"/>
+ <define name="SIZE_MAX" value="(__CONCAT(INT16_MAX, U))"/>
+ <!-- Macros for integer constants -->
+ <define name="INT8_C(value)" value="((int8_t) value)"/>
+ <define name="UINT8_C(value)" value="((uint8_t) __CONCAT(value, U))"/>
+ <define name="INT16_C(value)" value="value"/>
+ <define name="UINT16_C(value)" value="__CONCAT(value, U)"/>
+ <define name="INT32_C(value)" value="__CONCAT(value, L)"/>
+ <define name="UINT32_C(value)" value="__CONCAT(value, UL)"/>
+ <define name="INT64_C(value)" value="__CONCAT(value, LL)"/>
+ <define name="UINT64_C(value)" value="__CONCAT(value, ULL)"/>
+ <define name="INTMAX_C(value)" value="__CONCAT(value, LL)"/>
+ <define name="UINTMAX_C(value)" value="__CONCAT(value, ULL)"/>
+</def>
\ No newline at end of file
diff --git a/static_checks/cppcheck/config/tfm-suppress-list.txt b/static_checks/cppcheck/config/tfm-suppress-list.txt
new file mode 100644
index 0000000..5cb7571
--- /dev/null
+++ b/static_checks/cppcheck/config/tfm-suppress-list.txt
@@ -0,0 +1,73 @@
+//-------------------------------------------------------------------------------
+// Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+//
+//-------------------------------------------------------------------------------
+
+//This file contains suppression rules for CppCheck.
+//C style comments can be used.
+//
+//Each line has three parts separated by ":"
+//<message id>:<file>:<line num>
+//Where:
+// <message id> is the message id to suppress. This equals to the "id" filed
+// of the XML message record.
+// <file> Is a file name. cppcheck understands the following wildcards:
+// * matches any number of any characters
+// ? a single character
+// Note: please use '/' as directory separator.
+// <line num> The line number for which the message shall be ignored.
+//
+//Example to convert an XML record to a line in thif file:
+// <error id="invalidPrintfArgType_sint" severity="warning" msg="%d in format string (no. 1) requires 'int' but the argument type is 'unsigned int'." verbose="%d in format string (no. 1) requires 'int' but the argument type is 'unsigned int'." cwe="686">
+// <location file0="C:\work\tf-m\test\framework\test_framework.c" file="C:\work\tf-m\test\framework\test_framework.c" line="150"/>
+// </error>
+// to
+//invalidPrintfArgType_sint:*/tf-m/test/framework/test_framework.c:150
+//
+
+//This rule conflicts the our coding style document.
+variableScope
+
+//CppCheck fails to understand macro definitions in compile_commands.json, which
+//have \ characters escaping the opening and closing ". As a result we get the
+//following false alarms.
+
+//CppCheck ignores macros defined on the command line when using a project file
+//(e.g. compile_commands.json). As a result we ca not set compiler specific
+//macros and need to suppress the following error.
+preprocessorErrorDirective:*/tfm_spm_log.h:34
+preprocessorErrorDirective:*/cmsis_compiler.h:320
+
+//While cppcheck states to work fine with missing standard library files, it
+//still reports a lot of errors regarding those.
+//So, ignore these.
+missingIncludeSystem
+
+//Stos cppcheck report errors regarding supression rules. These seem to be
+//buggy.
+unmatchedSuppression
+
+//arm_cmse.h is a special system include, stop complaining about it.
+missingInclude:*/tfm_core.h:11
+missingInclude:*/tfm_secure_api.h:11
+
+//Exclude external qcbor code which does not comply with guidelines
+*:*/lib/*
+*:*/docs/*
+*:*/tools/*
+*:*/bl2/ext/*
+*:*/platform/ext/*
+
+//cppcheck shouldn't complain about unused function.
+unusedFunction
+
+//Variables in the following file are initialised to a specific value before being
+//modified. This is good practice and complies with TF-M guidelines. It should not
+//trigger an error.
+redundantInitialization:*/security_cnt.c
+
+//Unread variables in the following files in TF-M should not be complained.
+unreadVariable:*/tfm_crypto_func_api.c
+unreadVariable:*/tfm_crypto_secure_api.c
diff --git a/static_checks/cppcheck/run_cppcheck.sh b/static_checks/cppcheck/run_cppcheck.sh
new file mode 100755
index 0000000..cbf1060
--- /dev/null
+++ b/static_checks/cppcheck/run_cppcheck.sh
@@ -0,0 +1,117 @@
+#!/bin/bash
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set -e
+
+script_path="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
+
+. "$script_path/../utils.sh"
+
+TFM_PATH="$(fix_win_path $(get_full_path ./))"
+RAW_OUTPUT=0
+FAIL=0
+
+while getopts "hr" opt ; do
+ case "$opt" in
+ h)
+ echo "[SCF cppcheck] Usage: $(basename -- "$0") [-h] [-r] [git_hash]"
+ echo "[SCF cppcheck] -r, Raw output. (Default is to create xml reports)."
+ echo "[SCF cppcheck] -h, Script help"
+ exit 0
+ ;;
+ r)
+ RAW_OUTPUT=1
+ ;;
+ esac
+done
+
+
+if command -v cppcheck &> /dev/null
+then
+ echo "[SCF cppcheck] Using $(cppcheck --version)"
+else
+ echo "[SCF cppcheck] cppcheck not found - installing cppcheck"
+ source "$script_path/setup.sh"
+fi
+
+cd "$TFM_PATH"
+
+#Library file for cppcheck
+library_file="$(fix_win_path $(get_full_path $script_path))/config/arm-cortex-m.cfg"
+suppress_file="$(fix_win_path $(get_full_path $script_path))/config/tfm-suppress-list.txt"
+toolchain_file="$TFM_PATH/toolchain_GNUARM.cmake"
+
+compile_commands_path="$TFM_PATH/build-cppcheck/compile_commands.json"
+
+if [ -f "$compile_commands_path" ]; then
+ echo "[SCF cppcheck] $compile_commands_path already generated"
+else
+ echo "[SCF cppcheck] generating $compile_commands_path"
+ generate_project "$TFM_PATH" " ./" "cppcheck" "-DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DTFM_PLATFORM=arm/mps2/an521 -DTFM_TOOLCHAIN_FILE=$toolchain_file"
+ sed -i 's/\\\\\\\"/\\\"/g' $compile_commands_path
+fi
+
+function cppcheck_failed {
+ echo "[SCF cppcheck: ERROR] cppcheck failed, errors detected. Please check" \
+ "logs for details."
+ exit 1
+}
+
+function check_ouput {
+ if grep -q "<error id" $TFM_PATH/checks_reports/cppchk-config.xml; then
+ cppcheck_failed
+ fi
+
+ if grep -q "<error id" $TFM_PATH/checks_reports/cppchk-src.xml; then
+ cppcheck_failed
+ fi
+
+ echo "[SCF cppcheck: PASS] cppcheck complete"
+ exit 0
+}
+
+EXTRA_ARGS="--error-exitcode=1"
+if [ "$RAW_OUTPUT" != "1" ] ; then
+ # If not in raw output mode, use xml output.
+ EXTRA_ARGS="--xml"
+fi
+
+trap cppcheck_failed ERR
+
+CPPCHECK_ARGS="$EXTRA_ARGS --enable=all --library="$library_file" --project=$compile_commands_path --suppressions-list="$suppress_file" --inline-suppr"
+
+if [ -d "$TFM_PATH/checks_reports/" ]; then
+ echo "[SCF cppcheck] Storing cppcheck reports to $TFM_PATH/checks_reports/"
+else
+ mkdir "$TFM_PATH/checks_reports"
+ echo "[SCF cppcheck] Storing cppcheck reports to $TFM_PATH/checks_reports/"
+fi
+
+#Now run cppcheck.
+echo
+echo '[SCF cppcheck] Checking cppcheck configuration'
+echo
+
+if [ "$RAW_OUTPUT" == "1" ] ; then
+ cppcheck $CPPCHECK_ARGS --check-config > /dev/null
+else
+ cppcheck $CPPCHECK_ARGS --check-config 2>checks_reports/cppchk-config.xml
+fi
+
+echo
+echo '[SCF cppcheck] analyzing files with cppcheck'
+echo
+if [ "$RAW_OUTPUT" == "1" ] ; then
+ cppcheck $CPPCHECK_ARGS > /dev/null
+ echo '[SCF cppcheck : PASS] cppcheck complete'
+ exit 0
+else
+ cppcheck $CPPCHECK_ARGS 2>checks_reports/cppchk-src.xml
+ check_ouput
+fi
+
diff --git a/static_checks/cppcheck/setup.sh b/static_checks/cppcheck/setup.sh
new file mode 100755
index 0000000..4eb3693
--- /dev/null
+++ b/static_checks/cppcheck/setup.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set -e
+
+if [ "$EUID" -ne 0 ]
+ then echo "Please run as root"
+ exit
+else
+ wget -q https://github.com/danmar/cppcheck/archive/refs/tags/2.3.tar.gz -O /tmp/cppcheck.tar.gz
+ tar -xf /tmp/cppcheck.tar.gz -C /tmp
+ cd /tmp/cppcheck-*
+ make FILESDIR=/usr/share/cppcheck install
+fi
+
diff --git a/static_checks/run_all_checks.sh b/static_checks/run_all_checks.sh
new file mode 100755
index 0000000..0e0a170
--- /dev/null
+++ b/static_checks/run_all_checks.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set -e
+
+script_path="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
+. "$script_path/utils.sh"
+
+TFM_PATH="$(fix_win_path $(get_full_path ./))"
+
+if [ -d "$TFM_PATH/checks_reports/" ]; then
+ echo "[SCF] Storing reports to $TFM_PATH/checks_reports/"
+else
+ mkdir "checks_reports"
+ echo "[SCF] Storing reports to $TFM_PATH/checks_reports/"
+fi
+
+echo "[SCF] Running cppcheck"
+
+. "$script_path/cppcheck/run_cppcheck.sh"
+
+# echo "[SCF] Running clang_format"
+
+# . "$script_path/clang_format/run_clang_format.sh"
+
+# echo "[SCF] Running checkpatch"
+
+# . "$script_path/checkpatch/run_checkpatch.sh"
+
+exit 0
\ No newline at end of file
diff --git a/static_checks/utils.sh b/static_checks/utils.sh
new file mode 100644
index 0000000..8ac522a
--- /dev/null
+++ b/static_checks/utils.sh
@@ -0,0 +1,299 @@
+#!/bin/bash
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+##
+##@file
+##@brief Common utility functions used by CMake related build and utility scripts
+##
+##This file can be "sourced" from other scripts to get access to variables and functions
+##defined here.
+##Example \code{.sh}. <path-to-tfm-ci-repo>/util_cmake.sh\endcode
+##or \code{.sh}source <path-to-tfm-ci-repo>/util_cmake.sh\endcode
+##
+
+##@fn fix_win_path(string path)
+##@brief Convert cygwin and msys path to windows like.
+##@param[in] path
+##@returns path in windows format
+##
+##This function converts MSYS and cygwin paths to windows like path. Can be used
+##to print paths in error message which can be used withouth conversion. This
+##way for example you can get "clickable" path in Eclipse error window.
+##
+##Usage:
+## Assuming current directory is <i>c:/somedir1/somedir2</i>
+## command | result
+## --------|-------
+## fix_win_path "/cygdrive/c/foo/bar"| c:/foo/bar
+## fix_win_path "/c/foo/bar"| c:/foo/bar
+## fix_win_path "../somedir1/foo/bar"| ../somedir1/foo/bar
+## fix_win_path `get_full_path "../somedir1/foo/bar"` | c:/somedir1/foo/bar
+##
+#This iis needed for doxygen for now.
+#!void fix_win_path(string path){};
+#
+function fix_win_path() {
+ local path="$@"
+ #See if we run on windows
+ if [ -e "c:/" ]
+ then
+ #sed:
+ # 1. match /cygdrive/c/ like paths and convert to the c:/ format
+ # 2. if 1 did not match conver /c/ path to c:/ format
+ path=`builtin echo "$path"|sed "s/\/cygdrive\/\([a-zA-Z]\)\//\1:\//;tx;s/\/\([a-zA-Z]\)\//\1:\//;:x"`
+ fi
+ builtin echo "$path"
+}
+
+##@fn get_full_path(string path)
+##@brief Convert the passed path to full path.
+##@param[in] path
+##@returns path converted to absolute full path.
+##
+##This function converts a path to absolute full path. The function will return
+##execution environment specific path (/cygdrive/ under Cygwin c:/ under MSys
+##and /foo/bar under Linux).
+##The patch to conver may or may not contain a file name.
+##
+##Usage:
+## Assuming current directory is <i>c:/somedir1/somedir2</i>
+## environment | command | result
+## --------|--------|-------
+## Cygwin|get_full_path "."| /cygdrive/c/somedir1/somedir2
+## MSys|get_full_path "."| c:/somedir1/somedir2
+## Linux|get_full_path "."| /somedir1/somedir2
+##
+#This iis needed for doxygen for now.
+#!void get_full_path(string path){};
+#
+function get_full_path {
+ local file=""
+ local dir=$1
+ #If the paramether is a file, split it to directory and file name component.
+ if [ -f "$dir" ]
+ then
+ dir=`dirname "$1"`
+ file=`basename "$1"`
+ fi
+
+ if [ -z "$dir" ]
+ then
+ dir="."
+ fi
+
+ #Enter the directory to get it's full path
+ pushd "$dir" >/dev/null
+ local path=$PWD
+ popd >/dev/null
+
+ #On windows further fixing is needed to get a windows path
+ case "$os_name" in
+ CYGWIN)
+ path=`cygpath -m $path`
+ ;;
+ MSYS)
+ path=`echo $path| sed "s/^\/\([a-zA-Z]\)\//\1:\//"`
+ ;;
+ esac
+
+ echo "$path/$file"
+}
+
+
+##@fn make_build_dir_name(path build_base_dir, string build_config_name)
+##@brief Create the location for the a build.
+##@param[in] build_base_dir
+##@param[in] build_config_name
+##@returns The generated path.
+##
+##This function will generate the name for a build directory. The generated name
+##follow the pattern "<build_base_dir>/build-<build_config_name>".
+##The generted path will be absolute.
+##
+##Usage:
+## Assuming CMakeList.txt file is in /foo/bar directory.
+## command | result
+## --------|-------
+## make_build_dir_name "/foo/bar" "test_build_st32" | Return /foo/bar/build-test_build_st32
+##
+#This iis needed for doxygen for now.
+#!void make_build_dir_name(path build_base_dir, string build_config_name){};
+#
+function make_build_dir_name() {
+ local build_base_dir=$(get_full_path $1)
+ local build_config_name=$2
+ echo "${build_base_dir}build-$build_config_name"
+}
+
+##@fn generate_project(string src_dir, string build_base_dir, string build_config_name, string cmake_params)
+##@brief Execute CMake generation phase for a project
+##@param[in] src_dir
+##@param[in] build_base_dir
+##@param[in] build_config_name
+##@param[in] cmake_params
+##@returns N/A
+##
+##This function will create a build directory named "build-<build_config_name>"
+##under the passed <build_base_dir> directory, and execute CMake inside to
+##generate "Unix Makefiles".
+##CMake output is saved to <build_base_dir>/build-<build_config_name>/build.log
+##
+##Usage:
+## Assuming CMakeList.txt file is in /foo/bar directory.
+## command | result
+## --------|-------
+## generate_project "/foo/bar" "/tmp/build" "test_build_st32" "-DCMAKE_BUILD_TYPE=Debug"| Generate makefiles under /tmp/buid/build-test_build_st32 for project /foo/bar/CMakeLists.txt
+##
+#This iis needed for doxygen for now.
+#!void generate_project(string dir, string build_base_dir, string build_config_name, string cmake_params){};
+#
+function generate_project {
+ local src_dir=$1
+ local build_base_dir=$2
+ local bcfg_name=$3
+ local cm_params=$4
+ local bdir=$(make_build_dir_name "$build_base_dir" "$bcfg_name")
+ local error=0
+
+ #If build ditrectory exists, clear it
+ if [ -e "$bdir" ]
+ then
+ rm -rf $bdir/*
+ else
+ #Create build directory
+ mkdir $bdir
+ fi
+ #Enter build directory
+ if pushd $bdir >/dev/null
+ then
+ #Start cmake to generate makefiles and start the build
+ cmake -G"Unix Makefiles" CMAKE_MAKE_PROGRAM=$CMAKE_MAKE_PROGRAM $cm_params "$src_dir" 2>&1 | tee -a build.log
+ error=$(( ${PIPESTATUS[0]} + ${PIPESTATUS[1]} ))
+ #Back to original location
+ popd >/dev/null
+ else
+ error=1
+ fi
+ return $error
+}
+
+##@fn build_project(string src_dir, string build_base_dir, string build_config_name, string cmake_params)
+##@brief Build a CMake project with gnumake.
+##@param[in] src_dir
+##@param[in] build_base_dir
+##@param[in] build_config_name
+##@param[in] cmake_params
+##@returns N/A
+##
+##This function will call \ref generate_project to generate makefiles with CMake
+##and will execute make to build the project.
+##Make output is saved to <dir>/build-<build_config_name>/build.log
+##
+##Usage:
+## Assuming CMakeList.txt file is in /foo/bar directory.
+## command | result
+## --------|-------
+## build_project "/foo/bar" "test_build_st32" "-DCMAKE_BUILD_TYPE=Debug"| Generate makefiles under /foo/bar/build-test_build_st32 for project /foo/bar/CMakeLists.txt
+##
+#This iis needed for doxygen for now.
+#!void build_project(string src_dir, string build_base_dir, string build_config_name, string cmake_params){};
+#
+function build_project {
+ local src_dir=$1
+ local build_base_dir=$2
+ local bcfg_name=$3
+ local cm_params=$4
+ local error=0
+
+ if generate_project "$src_dir" "$build_base_dir" "$bcfg_name" "$cm_params"
+ then
+ local bdir=$(make_build_dir_name "$build_base_dir" "$bcfg_name")
+ if pushd "$bdir" >/dev/null
+ then
+ cmake --build . -- -j VERBOSE=1 2>&1 | tee -a build.log
+ error=$(( ${PIPESTATUS[0]} + ${PIPESTATUS[1]} ))
+ fi
+ #Back to original location
+ popd >/dev/null
+ else
+ error=1
+ fi
+ return $error
+}
+
+##@fn proj_dir_to_name(path proj_dir)
+##@brief Convert a project directory to project name
+##@param[in] proj_dir
+##@returns The converted name.
+##
+##This function will convert a project path to project name. Conversion rules:
+## * the leading "./" is removed
+## * all '/' (directory separator's) are replaced by '-'
+## * if the result is empty, the name "top_level" is used.
+##
+##project_list.
+##
+##Usage:
+## Assuming CMakeList.txt file is in /foo/bar directory.
+## command | result
+## --------|-------
+## project_list=(./ app secure_fw test ); proj_dir_to_name "test_build_st32" "-DCMAKE_BUILD_TYPE=Debug" project_list | Build all projects listed in project_list array.
+##
+#This iis needed for doxygen for now.
+#!void proj_dir_to_name(path proj_dir){};
+#
+function proj_dir_to_name {
+ local proj=$1
+ local name=$(echo "$proj" | sed 's/^\.\///;s/\//-/g')
+ if [ -z "$name" ]
+ then
+ name="top_level"
+ fi
+ echo "$name"
+}
+
+##@fn build_proj_set(path build_base_dir, string build_config_name, string cmake_params, path project_list[])
+##@brief Build a CMake project with gnumake.
+##@param[in] build_base_dir
+##@param[in] build_config_name
+##@param[in] cmake_params
+##@param[in] project_list
+##@returns N/A
+##
+##This function will call \ref build_project for all CMake projects listed in
+##project_list.
+##
+##Usage:
+## Assuming CMakeList.txt file is in /foo/bar directory.
+## command | result
+## --------|-------
+## project_list=(./ app secure_fw test ); build_proj_set "test_build_st32" "-DCMAKE_BUILD_TYPE=Debug" project_list | Build all projects listed in project_list array.
+##
+#This iis needed for doxygen for now.
+#!void build_proj_set(path build_base_dir, string build_config_name, string cmake_params, path project_list[]){};
+#
+function build_proj_set {
+ local build_base_dir=$1
+ local bcfg_name=$2
+ local cm_params=$3
+ local -n ref_project_list
+ ref_project_list=$4
+ local error=0
+ #For all projects in the list
+ for proj in "${ref_project_list[@]}"
+ do
+ #Convert the project location to a name.
+ local bcfg_name_ext="${bcfg_name}"_$(proj_dir_to_name "$proj")
+ #Convert project location to absolute path.
+ proj=$(get_full_path "$proj")
+ echo "build_project $proj $build_base_dir $bcfg_name_ext $cm_params"
+ #Build the project
+ build_project "$proj" "$build_base_dir" "$bcfg_name_ext" "$cm_params" || error=1
+ done
+ return $error
+}
\ No newline at end of file