Reputation: 6287
I'd basically like to achieve the same as http://blog.alexrp.com/2013/09/26/clangs-static-analyzer-and-automake, but with CMake.
analyze_srcs = foo.c
analyze_plists = $(analyze_srcs:%.c=%.plist)
CLEANFILES = $(analyze_plists)
$(analyze_plists): %.plist: %.c
@echo " CCSA " $@
@$(COMPILE) --analyze $< -o $@
analyze: $(analyze_plists)
.PHONY: analyze
So you can run
make analyze
make clean
I guess I need to use add_custom_command/add_custom_target
and somehow change the "object file" extension just for that target.
Afterwards get a list of the generated files to perhaps pass them to a script for combining them into 1 output file.
Can anyone point me in the right direction?
Upvotes: 26
Views: 16213
Reputation: 606
The following solution has the drawback of compiling and analyzing the entire project, not the specific targets.
set(on_side_build_path ${CMAKE_BINARY_DIR}/clang_static_analysis)
set(scan_build_path scan-build)
set(reports_path ${CMAKE_BINARY_DIR}/clang_static_analysis_reports)
# Creates clean directory where the analysis will be built.
add_custom_target(clang_static_analysis_prepare
COMMAND ${CMAKE_COMMAND} -E rm -rf ${on_side_build_path}
COMMAND ${CMAKE_COMMAND} -E make_directory ${on_side_build_path}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
# Runs the analysis from the path created specifically for that task. Use 'my own' project source directory as the source directory.
add_custom_target(clang_static_analysis
# scan-build wants Debug build, for better analysis.
COMMAND ${scan_build_path} ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR} -DCMAKE_BUILD_TYPE=Debug
COMMAND ${scan_build_path}
-v -v -o ${reports_path}
${CMAKE_COMMAND} --build .
WORKING_DIRECTORY ${on_side_build_path}
)
# Run the *_prepare target always before the analysis
add_dependencies(clang_static_analysis clang_static_analysis_prepare)
Invoke it with:
cmake --build . --target clang_static_analysis
scan-build
injects the CC
and CXX
environment variables to specify the replaced compilers, which are ccc-analyzer
and c++-analyzer
. When defining CMAKE_C_COMPILER
and CMAKE_CXX_COMPILER
the CC
and CXX
variables will be ignored. What you need to do to support scan-build
is to point CMAKE_C*_COMPILER
variables to use the one from environment, if defined. So having that in your toolchain file:
set(CMAKE_C_COMPILER some/path/to/c_compiler)
set(CMAKE_Cxx_COMPILER some/path/to/cxx_compiler)
Replace it with:
if(DEFINED ENV{CC})
set(CMAKE_C_COMPILER $ENV{CC})
else()
set(CMAKE_C_COMPILER some/path/to/c_compiler)
endif()
if(DEFINED ENV{CXX})
set(CMAKE_CXX_COMPILER $ENV{CXX})
else()
set(CMAKE_CXX_COMPILER some/path/to/cxx_compiler)
endif()
If your custom toolchain is LLVM, then most probably you want to use the scan-build
command from the toolchain. To enable it, simply define the path to toolchain path using cmake's cache variables:
set(LLVM_TOOLCHAIN_PATH "some/path/here" CACHE PATH "Path to the LLVM toolchain")
or from the command line:
cmake -DLLVM_TOOLCHAIN_PATH=some/path/here ...
and then reuse the path from the custom target:
set(scan_build_path ${LLVM_TOOLCHAIN_PATH}/bin/scan-build)
Note: enable_testing
shall be called before add_test
. enable_testing()
must be called from the project's top level CMakeLists.txt
for ctest
to resolve paths to tests.
add_test(
NAME clang_static_analysis
COMMAND ${CMAKE_COMMAND} --build . --target clang_static_analysis
)
Run it like that:
# Fire configure and generate stages
cmake ../source/dir
ctest -R clang_static_analysis --verbose
Upvotes: 6
Reputation: 981
You can use scan-build
when running cmake
.
scan-build cmake /path/to/source
scan-build make
scan-build
sets the CC
and CXX
environment variables which are picked up by cmake
.
Upvotes: 34
Reputation: 6287
I found a way:
function(add_clang_static_analysis target)
get_target_property(SRCs ${target} SOURCES)
add_library(${target}_analyze OBJECT EXCLUDE_FROM_ALL ${SRCs})
set_target_properties(${target}_analyze PROPERTIES
COMPILE_OPTIONS "--analyze"
EXCLUDE_FROM_DEFAULT_BUILD true)
endfunction()
Combining clang's plist files (which get extension .o this way) into a report is still open ($<TARGET_OBJECTS:objlibtarget>
?).
Upvotes: 6