mirror of
https://github.com/Kitware/CMake.git
synced 2025-12-31 19:00:54 -06:00
IAR: Add support for C-STAT static analysis
The IAR platform offers an integrated static analysis tool named IAR C-STAT. Closes: #26844
This commit is contained in:
committed by
Brad King
parent
a970c5cfdb
commit
c7d2a17253
@@ -318,6 +318,7 @@ Properties on Targets
|
||||
/prop_tgt/LANG_CPPCHECK
|
||||
/prop_tgt/LANG_CPPLINT
|
||||
/prop_tgt/LANG_EXTENSIONS
|
||||
/prop_tgt/LANG_ICSTAT
|
||||
/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE
|
||||
/prop_tgt/LANG_LINKER_LAUNCHER
|
||||
/prop_tgt/LANG_STANDARD
|
||||
|
||||
@@ -489,6 +489,7 @@ Variables that Control the Build
|
||||
/variable/CMAKE_LANG_COMPILER_LAUNCHER
|
||||
/variable/CMAKE_LANG_CPPCHECK
|
||||
/variable/CMAKE_LANG_CPPLINT
|
||||
/variable/CMAKE_LANG_ICSTAT
|
||||
/variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE
|
||||
/variable/CMAKE_LANG_LINK_GROUP_USING_FEATURE
|
||||
/variable/CMAKE_LANG_LINK_GROUP_USING_FEATURE_SUPPORTED
|
||||
|
||||
@@ -6,11 +6,11 @@ SKIP_LINTING
|
||||
This property allows you to exclude a specific source file
|
||||
from the linting process. The linting process involves running
|
||||
tools such as :prop_tgt:`<LANG>_CPPLINT`, :prop_tgt:`<LANG>_CLANG_TIDY`,
|
||||
:prop_tgt:`<LANG>_CPPCHECK`, and :prop_tgt:`<LANG>_INCLUDE_WHAT_YOU_USE`
|
||||
on the source files, as well as compiling header files as part of
|
||||
:prop_tgt:`VERIFY_INTERFACE_HEADER_SETS`. By setting ``SKIP_LINTING`` on a
|
||||
source file, the mentioned linting tools will not be executed for that
|
||||
particular file.
|
||||
:prop_tgt:`<LANG>_CPPCHECK`, :prop_tgt:`<LANG>_ICSTAT` and
|
||||
:prop_tgt:`<LANG>_INCLUDE_WHAT_YOU_USE` on the source files, as well
|
||||
as compiling header files as part of :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS`.
|
||||
By setting ``SKIP_LINTING`` on a source file, the mentioned linting tools
|
||||
will not be executed for that particular file.
|
||||
|
||||
Example
|
||||
^^^^^^^
|
||||
@@ -33,8 +33,9 @@ command as shown below:
|
||||
In the provided code snippet, the ``SKIP_LINTING`` property is set to true
|
||||
for the ``generatedBindings.cpp`` source file. As a result, when the linting
|
||||
tools specified by :prop_tgt:`<LANG>_CPPLINT`, :prop_tgt:`<LANG>_CLANG_TIDY`,
|
||||
:prop_tgt:`<LANG>_CPPCHECK`, or :prop_tgt:`<LANG>_INCLUDE_WHAT_YOU_USE`
|
||||
are executed, they will skip analyzing the ``generatedBindings.cpp`` file.
|
||||
:prop_tgt:`<LANG>_CPPCHECK`, :prop_tgt:`<LANG>_ICSTAT` or
|
||||
:prop_tgt:`<LANG>_INCLUDE_WHAT_YOU_USE` are executed, they will skip analyzing
|
||||
the ``generatedBindings.cpp`` file.
|
||||
|
||||
By using the ``SKIP_LINTING`` property, you can selectively exclude specific
|
||||
source files from the linting process. This allows you to focus the
|
||||
|
||||
20
Help/prop_tgt/LANG_ICSTAT.rst
Normal file
20
Help/prop_tgt/LANG_ICSTAT.rst
Normal file
@@ -0,0 +1,20 @@
|
||||
<LANG>_ICSTAT
|
||||
-------------
|
||||
|
||||
.. versionadded:: 4.1
|
||||
|
||||
This property is supported only when ``<LANG>`` is ``C`` or ``CXX``.
|
||||
|
||||
Specify a :ref:`semicolon-separated list <CMake Language Lists>`
|
||||
containing a command line for the ``icstat`` static analysis tool.
|
||||
The :ref:`Makefile Generators` and the :ref:`Ninja Generators` will
|
||||
run ``icstat`` along with the compiler and report any problems.
|
||||
The build will fail if the ``icstat`` tool returns non-zero.
|
||||
|
||||
This property is initialized by the value of the
|
||||
:variable:`CMAKE_<LANG>_ICSTAT` variable if it is set when a target is
|
||||
created. It also supports
|
||||
:manual:`generator expressions <cmake-generator-expressions(7)>`.
|
||||
|
||||
This lint may be suppressed for individual source files by setting
|
||||
the :prop_sf:`SKIP_LINTING` source file property.
|
||||
8
Help/release/dev/iar-add-icstat-support.rst
Normal file
8
Help/release/dev/iar-add-icstat-support.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
iar-add-icstat-support
|
||||
----------------------
|
||||
|
||||
* The :variable:`CMAKE_<LANG>_ICSTAT` variable and corresponding
|
||||
:prop_tgt:`<LANG>_ICSTAT` target property were added to tell
|
||||
the :ref:`Makefile Generators` and the :ref:`Ninja Generators`
|
||||
to run the IAR ``icstat`` tool along with the compiler for
|
||||
``C`` and ``CXX`` languages.
|
||||
8
Help/variable/CMAKE_LANG_ICSTAT.rst
Normal file
8
Help/variable/CMAKE_LANG_ICSTAT.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
CMAKE_<LANG>_ICSTAT
|
||||
-------------------
|
||||
|
||||
.. versionadded:: 4.1
|
||||
|
||||
Default value for :prop_tgt:`<LANG>_ICSTAT` target property. This variable
|
||||
is used to initialize the property on each target as it is created. This
|
||||
is done only when ``<LANG>`` is ``C`` or ``CXX``.
|
||||
@@ -360,6 +360,7 @@ std::string cmCommonTargetGenerator::GenerateCodeCheckRules(
|
||||
std::string iwyu;
|
||||
std::string cpplint;
|
||||
std::string cppcheck;
|
||||
std::string icstat;
|
||||
|
||||
auto evaluateProp = [&](std::string const& prop) -> std::string {
|
||||
auto const value = this->GeneratorTarget->GetProperty(prop);
|
||||
@@ -383,9 +384,12 @@ std::string cmCommonTargetGenerator::GenerateCodeCheckRules(
|
||||
|
||||
std::string const cppcheck_prop = cmStrCat(lang, "_CPPCHECK");
|
||||
cppcheck = evaluateProp(cppcheck_prop);
|
||||
|
||||
std::string const icstat_prop = cmStrCat(lang, "_ICSTAT");
|
||||
icstat = evaluateProp(icstat_prop);
|
||||
}
|
||||
if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) ||
|
||||
cmNonempty(cppcheck)) {
|
||||
cmNonempty(cppcheck) || cmNonempty(icstat)) {
|
||||
std::string code_check = cmakeCmd + " -E __run_co_compile";
|
||||
if (!compilerLauncher.empty()) {
|
||||
// In __run_co_compile case the launcher command is supplied
|
||||
@@ -481,6 +485,24 @@ std::string cmCommonTargetGenerator::GenerateCodeCheckRules(
|
||||
code_check +=
|
||||
this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(cppcheck);
|
||||
}
|
||||
if (cmNonempty(icstat)) {
|
||||
code_check += " --icstat=";
|
||||
std::string checksParam{};
|
||||
std::string dbParam{};
|
||||
// Set default values for mandatory parameters
|
||||
std::string checksFile{ "cstat_sel_checks.txt" };
|
||||
std::string dbFile{ "cstat.db" };
|
||||
// Populate the command line with C-STAT
|
||||
// mandatory parameters unless specified
|
||||
if (icstat.find("--checks=") == std::string::npos) {
|
||||
checksParam = cmStrCat(";--checks=", checksFile);
|
||||
}
|
||||
if (icstat.find("--db=") == std::string::npos) {
|
||||
dbParam = cmStrCat(";--db=", dbFile);
|
||||
}
|
||||
code_check += this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(
|
||||
cmStrCat(icstat, checksParam, dbParam));
|
||||
}
|
||||
if (cmNonempty(tidy) || (cmNonempty(cpplint)) || (cmNonempty(cppcheck))) {
|
||||
code_check += " --source=";
|
||||
code_check +=
|
||||
|
||||
@@ -463,12 +463,14 @@ TargetProperty const StaticTargetProperties[] = {
|
||||
{ "C_CLANG_TIDY_EXPORT_FIXES_DIR"_s, IC::CanCompileSources },
|
||||
{ "C_CPPLINT"_s, IC::CanCompileSources },
|
||||
{ "C_CPPCHECK"_s, IC::CanCompileSources },
|
||||
{ "C_ICSTAT"_s, IC::CanCompileSources },
|
||||
{ "C_INCLUDE_WHAT_YOU_USE"_s, IC::CanCompileSources },
|
||||
// -- C++
|
||||
{ "CXX_CLANG_TIDY"_s, IC::CanCompileSources },
|
||||
{ "CXX_CLANG_TIDY_EXPORT_FIXES_DIR"_s, IC::CanCompileSources },
|
||||
{ "CXX_CPPLINT"_s, IC::CanCompileSources },
|
||||
{ "CXX_CPPCHECK"_s, IC::CanCompileSources },
|
||||
{ "CXX_ICSTAT"_s, IC::CanCompileSources },
|
||||
{ "CXX_INCLUDE_WHAT_YOU_USE"_s, IC::CanCompileSources },
|
||||
// -- Objective C
|
||||
{ "OBJC_CLANG_TIDY"_s, IC::CanCompileSources },
|
||||
@@ -1783,6 +1785,7 @@ void cmTarget::CopyImportedCxxModulesProperties(cmTarget const* tgt)
|
||||
"CXX_CLANG_TIDY_EXPORT_FIXES_DIR",
|
||||
"CXX_CPPLINT",
|
||||
"CXX_CPPCHECK",
|
||||
"CXX_ICSTAT",
|
||||
"CXX_INCLUDE_WHAT_YOU_USE",
|
||||
|
||||
// Build graph properties
|
||||
|
||||
@@ -513,6 +513,55 @@ int HandleCppCheck(std::string const& runCmd, std::string const& sourceFile,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int HandleIcstat(std::string const& runCmd, std::string const& sourceFile,
|
||||
std::vector<std::string> const& orig_cmd)
|
||||
{
|
||||
// Construct the IAR C-STAT command line.
|
||||
cmList icstat_cmd{ runCmd, cmList::EmptyElements::Yes };
|
||||
std::string icstat_analyze{ "analyze" };
|
||||
std::string icstat_dashdash{ "--" };
|
||||
std::string stdOut;
|
||||
std::string stdErr;
|
||||
int ret;
|
||||
|
||||
icstat_cmd.push_back(icstat_analyze);
|
||||
icstat_cmd.push_back(sourceFile);
|
||||
icstat_cmd.push_back(icstat_dashdash);
|
||||
|
||||
for (auto const& cmd : orig_cmd) {
|
||||
icstat_cmd.push_back(cmd);
|
||||
}
|
||||
|
||||
// Create the default manifest ruleset file when not found
|
||||
if (!cmSystemTools::FileExists("cstat_sel_checks.txt")) {
|
||||
std::string ichecks_cmd = cmSystemTools::GetFilenamePath(orig_cmd[0]);
|
||||
ichecks_cmd = cmStrCat(ichecks_cmd, "/ichecks --default stdchecks");
|
||||
if (!cmSystemTools::RunSingleCommand(ichecks_cmd, &stdOut, &stdErr, &ret,
|
||||
nullptr,
|
||||
cmSystemTools::OUTPUT_NONE)) {
|
||||
std::cerr << "Error generating default manifest file '" << ichecks_cmd
|
||||
<< "'. " << stdOut << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Run the IAR C-STAT command line. Capture its output.
|
||||
if (!cmSystemTools::RunSingleCommand(icstat_cmd, &stdOut, &stdErr, &ret,
|
||||
nullptr, cmSystemTools::OUTPUT_NONE)) {
|
||||
std::cerr << "Error running '" << icstat_cmd[0] << "': " << stdOut << '\n';
|
||||
return 1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
std::cerr << "Warning: C-STAT static analysis reported diagnostics:\n";
|
||||
} else {
|
||||
std::cerr << "Error: C-STAT static analysis reported failure:\n";
|
||||
}
|
||||
std::cerr << stdOut;
|
||||
std::cerr << stdErr;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
using CoCompileHandler = int (*)(std::string const&, std::string const&,
|
||||
std::vector<std::string> const&);
|
||||
|
||||
@@ -523,10 +572,11 @@ struct CoCompiler
|
||||
bool NoOriginalCommand;
|
||||
};
|
||||
|
||||
std::array<CoCompiler, 5> const CoCompilers = {
|
||||
std::array<CoCompiler, 6> const CoCompilers = {
|
||||
{ // Table of options and handlers.
|
||||
{ "--cppcheck=", HandleCppCheck, false },
|
||||
{ "--cpplint=", HandleCppLint, false },
|
||||
{ "--icstat=", HandleIcstat, false },
|
||||
{ "--iwyu=", HandleIWYU, false },
|
||||
{ "--lwyu=", HandleLWYU, true },
|
||||
{ "--tidy=", HandleTidy, false } }
|
||||
|
||||
@@ -1361,7 +1361,11 @@ if(WIN32)
|
||||
endif()
|
||||
|
||||
if(CMake_TEST_IAR_TOOLCHAINS)
|
||||
add_RunCMake_test(IAR -DCMake_TEST_IAR_TOOLCHAINS=${CMake_TEST_IAR_TOOLCHAINS})
|
||||
add_executable(pseudo_icstat pseudo_icstat.c)
|
||||
add_RunCMake_test(IAR
|
||||
-DCMake_TEST_IAR_TOOLCHAINS=${CMake_TEST_IAR_TOOLCHAINS}
|
||||
-DPSEUDO_ICSTAT=$<TARGET_FILE:pseudo_icstat>
|
||||
)
|
||||
set_property(TEST RunCMake.IAR APPEND PROPERTY LABELS "IAR")
|
||||
endif()
|
||||
if(CMake_TEST_TICLANG_TOOLCHAINS)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
^__run_co_compile missing command to run. Looking for one or more of the following:
|
||||
--cppcheck=
|
||||
--cpplint=
|
||||
--icstat=
|
||||
--iwyu=
|
||||
--lwyu=
|
||||
--tidy=
|
||||
|
||||
@@ -10,8 +10,9 @@ endif()
|
||||
|
||||
function(run_toolchain case)
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
|
||||
run_cmake_with_options(${case} ${ARGN})
|
||||
run_cmake_with_options(${case} "-DPSEUDO_ICSTAT=${PSEUDO_ICSTAT}" ${ARGN})
|
||||
set(RunCMake_TEST_NO_CLEAN 1)
|
||||
set(RunCMake_TEST_OUTPUT_MERGE 1)
|
||||
run_cmake_command(${case}-build ${CMAKE_COMMAND} --build .)
|
||||
endfunction()
|
||||
|
||||
@@ -61,12 +62,24 @@ foreach(_iar_toolchain IN LISTS _iar_toolchains)
|
||||
-DCMAKE_EXE_LINKER_FLAGS=${LINK_OPTS}
|
||||
)
|
||||
|
||||
run_toolchain(iar-c-bad
|
||||
-DCMAKE_SYSTEM_NAME=Generic
|
||||
-DCMAKE_C_COMPILER=${_iar_toolchain}
|
||||
-DCMAKE_EXE_LINKER_FLAGS=${LINK_OPTS}
|
||||
)
|
||||
|
||||
run_toolchain(iar-cxx
|
||||
-DCMAKE_SYSTEM_NAME=Generic
|
||||
-DCMAKE_CXX_COMPILER=${_iar_toolchain}
|
||||
-DCMAKE_EXE_LINKER_FLAGS=${LINK_OPTS}
|
||||
)
|
||||
|
||||
run_toolchain(iar-cxx-bad
|
||||
-DCMAKE_SYSTEM_NAME=Generic
|
||||
-DCMAKE_CXX_COMPILER=${_iar_toolchain}
|
||||
-DCMAKE_EXE_LINKER_FLAGS=${LINK_OPTS}
|
||||
)
|
||||
|
||||
run_toolchain(iar-asm
|
||||
-DCMAKE_SYSTEM_NAME=Generic
|
||||
-DCMAKE_ASM_COMPILER=${IAR_ASSEMBLER}
|
||||
|
||||
1
Tests/RunCMake/IAR/iar-c-bad-build-result.txt
Normal file
1
Tests/RunCMake/IAR/iar-c-bad-build-result.txt
Normal file
@@ -0,0 +1 @@
|
||||
[^0]
|
||||
3
Tests/RunCMake/IAR/iar-c-bad-build-stdout.txt
Normal file
3
Tests/RunCMake/IAR/iar-c-bad-build-stdout.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Error: C-STAT static analysis reported failure:
|
||||
stdout from bad command line arg '-bad'
|
||||
stderr from bad command line arg '-bad'
|
||||
5
Tests/RunCMake/IAR/iar-c-bad.cmake
Normal file
5
Tests/RunCMake/IAR/iar-c-bad.cmake
Normal file
@@ -0,0 +1,5 @@
|
||||
enable_language(C)
|
||||
set(CMAKE_C_ICSTAT "${PSEUDO_ICSTAT}" -bad)
|
||||
add_executable(exec-c module.c)
|
||||
target_compile_options(exec-c PRIVATE -e)
|
||||
target_link_options(exec-c PRIVATE ${LINKER_OPTS})
|
||||
1
Tests/RunCMake/IAR/iar-c-build-stdout.txt
Normal file
1
Tests/RunCMake/IAR/iar-c-build-stdout.txt
Normal file
@@ -0,0 +1 @@
|
||||
Warning: C-STAT static analysis reported diagnostics.*Severity
|
||||
@@ -1,5 +1,5 @@
|
||||
enable_language(C)
|
||||
|
||||
set(CMAKE_C_ICSTAT "${PSEUDO_ICSTAT}" -some -args)
|
||||
add_executable(exec-c module.c)
|
||||
target_compile_options(exec-c PRIVATE -e)
|
||||
target_link_options(exec-c PRIVATE ${LINKER_OPTS})
|
||||
|
||||
1
Tests/RunCMake/IAR/iar-cxx-bad-build-result.txt
Normal file
1
Tests/RunCMake/IAR/iar-cxx-bad-build-result.txt
Normal file
@@ -0,0 +1 @@
|
||||
[^0]
|
||||
3
Tests/RunCMake/IAR/iar-cxx-bad-build-stdout.txt
Normal file
3
Tests/RunCMake/IAR/iar-cxx-bad-build-stdout.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Error: C-STAT static analysis reported failure:
|
||||
stdout from bad command line arg '-bad'
|
||||
stderr from bad command line arg '-bad'
|
||||
5
Tests/RunCMake/IAR/iar-cxx-bad.cmake
Normal file
5
Tests/RunCMake/IAR/iar-cxx-bad.cmake
Normal file
@@ -0,0 +1,5 @@
|
||||
enable_language(CXX)
|
||||
set(CMAKE_CXX_ICSTAT "${PSEUDO_ICSTAT}" -bad)
|
||||
add_executable(exec-cxx module.cxx)
|
||||
target_compile_options(exec-cxx PRIVATE -e)
|
||||
target_link_options(exec-cxx PRIVATE ${LINKER_OPTS})
|
||||
1
Tests/RunCMake/IAR/iar-cxx-build-stdout.txt
Normal file
1
Tests/RunCMake/IAR/iar-cxx-build-stdout.txt
Normal file
@@ -0,0 +1 @@
|
||||
Warning: C-STAT static analysis reported diagnostics.*Severity
|
||||
@@ -1,5 +1,5 @@
|
||||
enable_language(CXX)
|
||||
|
||||
set(CMAKE_CXX_ICSTAT "${PSEUDO_ICSTAT}" -some -args)
|
||||
add_executable(exec-cxx module.cxx)
|
||||
target_compile_options(exec-cxx PRIVATE -e)
|
||||
target_link_options(exec-cxx PRIVATE ${LINKER_OPTS})
|
||||
|
||||
29
Tests/RunCMake/pseudo_icstat.c
Normal file
29
Tests/RunCMake/pseudo_icstat.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int i;
|
||||
int result = 0;
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "-bad") == 0) {
|
||||
fprintf(stdout, "stdout from bad command line arg '-bad'\n");
|
||||
fprintf(stderr, "stderr from bad command line arg '-bad'\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
fprintf(stderr,
|
||||
"\"foo/bar.c\",2 Severity-High[SPC-uninit-var-some]:"
|
||||
"Variable `i' may be uninitialized.\n\n");
|
||||
fprintf(stderr,
|
||||
"\"foo/bar.c\",2 Severity-Medium[MISRAC2012-Rule-8.2_a]:"
|
||||
"`main' does not have a valid prototype.\n\n");
|
||||
fprintf(stderr,
|
||||
"\"foo/bar.c\",2 Severity-Low[MISRAC2012-Rule-21.6]:"
|
||||
"Use of `stdio.h' is not compliant.\n\n");
|
||||
fprintf(stderr,
|
||||
"\"foo/bar.c\",2 Severity-Low[MISRAC2012-Rule-17.7]:"
|
||||
"The return value of this call to `printf()' is discarded.\n\n");
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user