diff --git a/Makefile.mk b/Makefile.mk index 3969bfbd05..218e388bb5 100644 --- a/Makefile.mk +++ b/Makefile.mk @@ -532,8 +532,8 @@ CFLAGS_common += -Wstring-compare ifeq ($(CONFIG_COMPILER_GCC),y) CFLAGS_common += -Wold-style-declaration CFLAGS_common += -Wcast-function-type -# Don't add these GCC specific flags when running scan-build -ifeq ($(CCC_ANALYZER_OUTPUT_FORMAT),) +# Don't add these GCC specific flags when running clang-tidy +ifeq ($(CLANG_TIDY),) CFLAGS_common += -Wno-packed-not-aligned CFLAGS_common += -fconserve-stack CFLAGS_common += -Wnull-dereference diff --git a/payloads/libpayload/Makefile b/payloads/libpayload/Makefile index afe38dc6e7..a8c2641dc6 100644 --- a/payloads/libpayload/Makefile +++ b/payloads/libpayload/Makefile @@ -33,7 +33,7 @@ ifneq ($(words $(CURDIR)),1) $(error ERROR: Path to the main directory cannot contain spaces) endif -ifeq ($(INNER_SCANBUILD),y) +ifeq ($(INNER_STATIC_ANALYSIS),y) CC_real:=$(CC) endif @@ -95,7 +95,7 @@ DOXYGEN_OUTPUT_DIR := doxygen all: real-all -ifeq ($(INNER_SCANBUILD),y) +ifeq ($(INNER_STATIC_ANALYSIS),y) CC:=$(CC_real) HOSTCC:=$(CC_real) --hostcc HOSTCXX:=$(CC_real) --hostcxx @@ -218,7 +218,6 @@ endif CFLAGS += -std=gnu11 $(CFLAGS_$(ARCH-y)) -ifneq ($(INNER_SCANBUILD),y) ifeq ($(CONFIG_LP_COMPILER_LLVM_CLANG),y) CC:=clang ifneq ($(CONFIG_LP_ARCH_MOCK),y) @@ -226,7 +225,6 @@ CC += -m32 endif HOSTCC:=clang endif -endif ifeq ($(CONFIG_LP_CCACHE),y) CCACHE:=$(word 1,$(wildcard $(addsuffix /ccache,$(subst :, ,$(PATH))))) @@ -244,22 +242,17 @@ strip_quotes = $(subst ",,$(subst \",,$(1))) # The primary target needs to be here before we include the # other files -ifeq ($(INNER_SCANBUILD),y) -CONFIG_LP_SCANBUILD_ENABLE:= +ifeq ($(INNER_STATIC_ANALYSIS),y) +CONFIG_LP_STATIC_ANALYSIS__ENABLE:= endif -ifeq ($(CONFIG_LP_SCANBUILD_ENABLE),y) -ifneq ($(CONFIG_LP_SCANBUILD_REPORT_LOCATION),) -CONFIG_LP_SCANBUILD_REPORT_LOCATION:=-o $(CONFIG_LP_SCANBUILD_REPORT_LOCATION) +ifeq ($(CONFIG_LP_STATIC_ANALYSIS_ENABLE),y) +ifneq ($(CONFIG_LP_STATIC_ANALYSIS_REPORT_LOCATION),) +CONFIG_LP_STATIC_ANALYSIS_LOCATION:=-o $(CONFIG_LP_STATIC_ANALYSIS_REPORT_LOCATION) endif real-all: - echo '#!/bin/sh' > .ccwrap - echo 'CC="$(CC)"' >> .ccwrap - echo 'if [ "$$1" = "--hostcc" ]; then shift; CC="$(HOSTCC)"; fi' >> .ccwrap - echo 'if [ "$$1" = "--hostcxx" ]; then shift; CC="$(HOSTCXX)"; fi' >> .ccwrap - echo 'eval $$CC $$*' >> .ccwrap - chmod +x .ccwrap - scan-build $(CONFIG_LP_SCANBUILD_REPORT_LOCATION) -analyze-headers --use-cc=$(top)/.ccwrap --use-c++=$(top)/.ccwrap $(MAKE) INNER_SCANBUILD=y + find src -name '*.c' -o -name '*.h' | xargs clang-tidy $(CONFIG_LP_CLANG_TIDY_CHECKS) + $(MAKE) INNER_STATIC_ANALYSIS=y else real-all: real-target endif diff --git a/src/arch/riscv/Makefile.mk b/src/arch/riscv/Makefile.mk index 3efd8959cc..95e439d5a9 100644 --- a/src/arch/riscv/Makefile.mk +++ b/src/arch/riscv/Makefile.mk @@ -31,7 +31,7 @@ else MARCH_SUFFIX= endif -ifeq ($(CCC_ANALYZER_OUTPUT_FORMAT),) +ifeq ($(CLANG_TIDY),) riscv_flags += -march=$(CONFIG_RISCV_ARCH)$(MARCH_SUFFIX) -mabi=$(CONFIG_RISCV_ABI) -mcmodel=$(CONFIG_RISCV_CODEMODEL) simple_riscv_flags += -march=$(CONFIG_RISCV_ARCH) -mabi=$(CONFIG_RISCV_ABI) -mcmodel=$(CONFIG_RISCV_CODEMODEL) else diff --git a/toolchain.mk b/toolchain.mk index 8d6d4496a2..dada31daf4 100644 --- a/toolchain.mk +++ b/toolchain.mk @@ -19,12 +19,10 @@ HOSTCC:=$(CCACHE) $(HOSTCC) HOSTCXX:=$(CCACHE) $(HOSTCXX) endif -# scan-build integration -ifneq ($(CCC_ANALYZER_OUTPUT_FORMAT),) - -ifeq ($(CCC_ANALYZER_ANALYSIS),) -export CCC_ANALYZER_ANALYSIS := -analyzer-opt-analyze-headers -endif +# clang-tidy integration +ifneq ($(CLANG_TIDY),) +CLANG_TIDY_CHECKS ?= -checks=* +CLANG_TIDY_ARGS ?= -extra-arg=-Wno-packed-not-aligned $(foreach arch,$(ARCH_SUPPORTED), \ $(eval CC_$(arch):=CCC_CC="$(CC_$(arch))" $(CC) )) diff --git a/util/abuild/abuild b/util/abuild/abuild index faac3eb347..8483942aed 100755 --- a/util/abuild/abuild +++ b/util/abuild/abuild @@ -85,8 +85,8 @@ mode=text # quiet mode: only print pass, failure, and 'skipped' messages quiet=false -# clang mode enabled by -sb option. -scanbuild=false +# clang-tidy mode enabled by -sb option. +clangtidy=false # Mark whether abuild was called recursively recursive=false @@ -417,6 +417,35 @@ ts_delta_string() fi } +run_clang_tidy() +{ + local build_dir="$1" + local log_file="$2" + local clang_tidy_args="" + + if [[ -n "${CLANG_TIDY_CHECKS}" ]]; then + clang_tidy_args+="-checks=${CLANG_TIDY_CHECKS} " + fi + + # Generate compilation database + printf "Generating compilation database for clang-tidy...\n" + ${MAKE} -C "${ROOT}" DOTCONFIG="${build_dir}/config.build" obj="${build_dir}" \ + objutil="${TARGET}/sharedutils" BUILD_TIMELESS=${TIMELESS} \ + compiledb >/dev/null 2>&1 + + if [[ ! -f "${build_dir}/compile_commands.json" ]]; then + printf "Error: Failed to generate compilation database\n" >> "${log_file}" + return 1 + fi + + # Run clang-tidy on all source files + find "${ROOT}/src" -type f \( -name "*.c" -o -name "*.h" \) | while read -r src_file; do + clang-tidy ${clang_tidy_args} "${src_file}" >> "${log_file}" 2>&1 + done + + return 0 +} + compile_target() { local BUILD_NAME=$1 @@ -453,6 +482,17 @@ compile_target() printf "ok\n" > compile.status printf "%s built successfully. (took %s)\n" "${BUILD_NAME}" "${duration_str}" echo "${BUILD_NAME}" >> "${PASSED_BOARDS}" + + # Run clang-tidy after successful build + if [[ "${clangtidy}" = "true" ]]; then + printf "Running clang-tidy for %s...\n" "${BUILD_NAME}" + run_clang_tidy "${build_dir}" "${build_dir}/clang-tidy.log" + if [[ $? -eq 0 ]]; then + printf "clang-tidy completed for %s\n" "${BUILD_NAME}" + else + printf "clang-tidy failed for %s (see %s/clang-tidy.log)\n" "${BUILD_NAME}" "${build_dir}" + fi + fi else junit "" junitfile make.log @@ -606,16 +646,10 @@ EOF if [[ ${BUILDENV_CREATED} -eq 0 ]] && [[ ${configureonly} -eq 0 ]]; then BUILDPREFIX= - if [[ "${scanbuild}" = "true" ]]; then - scanbuild_out="${TARGET}/${BUILD_NAME}-scanbuild" - rm -rf "${scanbuild_out}" - BUILDPREFIX="scan-build ${SCANBUILD_ARGS} -o ${scanbuild_out}tmp" + if [[ "${clangtidy}" = "true" ]]; then + printf "Enabling clang-tidy for static analysis\n" fi compile_target "${BUILD_NAME}" - if [[ "${scanbuild}" = "true" ]]; then - mv "${scanbuild_out}tmp"/* "${scanbuild_out}" - rmdir "${scanbuild_out}tmp" - fi fi junit "" @@ -720,7 +754,7 @@ Options:\n [-r|--remove] Remove output dir after build [-R|--root ] Absolute path to coreboot sources (defaults to ${ROOT}) - [--scan-build] Use clang's static analyzer + [--static-analysis] Run clang-tidy for static code analysis [--skip_set ] Skip building boards with this Kconfig set [--skip_unset ] Skip building boards with this Kconfig not set [--timeless] Generate timeless builds @@ -780,7 +814,7 @@ getoptbrand="$(getopt -V)" # shellcheck disable=SC2086 if [[ "${getoptbrand:0:6}" == "getopt" ]]; then # Detected GNU getopt that supports long options. - args=$(getopt -l version,verbose,quiet,help,all,target:,board-variant:,payloads:,cpus:,silent,junit,config,loglevel:,remove,prefix:,update,scan-build,ccache,blobs,clang,any-toolchain,clean,clean-somewhat,outdir:,chromeos,xmlfile:,kconfig:,dir:,root:,recursive,checksum:,timeless,exitcode,asserts,name:,skip_set:,skip_unset: -o Vvqhat:b:p:c:sJCl:rP:uyBLAzZo:xX:K:d:R:Ien: -- "$@") || exit 1 + args=$(getopt -l version,verbose,quiet,help,all,target:,board-variant:,payloads:,cpus:,silent,junit,config,loglevel:,remove,prefix:,update,static-analysis,ccache,blobs,clang,any-toolchain,clean,clean-somewhat,outdir:,chromeos,xmlfile:,kconfig:,dir:,root:,recursive,checksum:,timeless,exitcode,asserts,name:,skip_set:,skip_unset: -o Vvqhat:b:p:c:sJCl:rP:uyBLAzZo:xX:K:d:R:Ien: -- "$@") || exit 1 eval set -- ${args} retval=$? else @@ -828,10 +862,9 @@ while true ; do shift;; # obsolete option -s|--silent) shift;; - --scan-build) shift - scanbuild=true - customizing="${customizing}, scan-build" - SCANBUILD_ARGS=${SCANBUILD_ARGS:-'-k'} + --static-analysis) shift + clangtidy=true + customizing="${customizing}, static-analysis" configoptions="${configoptions}CONFIG_FATAL_ASSERTS=y\n" ;; --skip_set) shift @@ -1008,17 +1041,12 @@ build_targets() printf "%s" "${configoptions}" > "${TMPCFG}" ${MAKE} -j "${cpus}" DOTCONFIG="${TMPCFG}" obj="${TARGET}/temp" objutil="${TARGET}/sharedutils" olddefconfig 2>/dev/null BUILDPREFIX= - if [[ "${scanbuild}" = "true" ]]; then - scanbuild_out="${TARGET}/sharedutils-scanbuild" - rm -rf "${scanbuild_out}" - BUILDPREFIX="scan-build -o ${scanbuild_out}tmp" - fi mkdir -p "${TARGET}/abuild" ABSPATH="$(cd "${TARGET}/abuild" && pwd)" XMLFILE="${ABSPATH}/__util.xml" rm -f "${XMLFILE}" stime=$(add_timestamp) - ${BUILDPREFIX} "${MAKE}" -j "${cpus}" DOTCONFIG="${TMPCFG}" obj="${TARGET}/temp" objutil="${TARGET}/sharedutils" tools > "${TARGET}/sharedutils/make.log" 2>&1 + ${MAKE} -j "${cpus}" DOTCONFIG="${TMPCFG}" obj="${TARGET}/temp" objutil="${TARGET}/sharedutils" tools > "${TARGET}/sharedutils/make.log" 2>&1 local ret=$? etime=$(add_timestamp) duration=$(ts_delta_seconds "${stime}" "${etime}") @@ -1039,10 +1067,6 @@ build_targets() return fi - if [[ "${scanbuild}" = "true" ]]; then - mv "${scanbuild_out}"tmp/* "${scanbuild_out}" - rmdir "${scanbuild_out}tmp" - fi rm -rf "${TARGET}/temp" "${TMPCFG}" num_targets=$(wc -w <<<"${targets}") cpus_per_target=$(((${cpus:-1} + num_targets - 1) / num_targets)) @@ -1106,4 +1130,4 @@ if [[ "${recursive}" = "false" ]]; then fi fi -exit ${failed} +exit ${failed} \ No newline at end of file diff --git a/util/cbfstool/lz4/Makefile b/util/cbfstool/lz4/Makefile index 4506267ebf..d624e84703 100644 --- a/util/cbfstool/lz4/Makefile +++ b/util/cbfstool/lz4/Makefile @@ -81,7 +81,7 @@ sanitize: clean CFLAGS="-O3 -g -fsanitize=undefined" $(MAKE) test CC=clang FUZZER_TIME="-T1mn" NB_LOOPS=-i1 staticAnalyze: clean - CFLAGS=-g scan-build --status-bugs -v $(MAKE) all + CFLAGS=-g clang-tidy $(CLANG_TIDY_CHECKS) $(CLANG_TIDY_ARGS) $(SRCS) armtest: clean CFLAGS="-O3 -Werror" $(MAKE) -C $(LZ4DIR) all CC=arm-linux-gnueabi-gcc diff --git a/util/crossgcc/buildgcc b/util/crossgcc/buildgcc index a4a998536b..80b333569a 100755 --- a/util/crossgcc/buildgcc +++ b/util/crossgcc/buildgcc @@ -941,9 +941,6 @@ build_LLVM() { $MAKE install || touch .failed rm -f ../llvm ../clang ../clang-tools-extra ../compiler-rt ../cmake ../lld ../libunwind ../runtimes - - cp -a ../$CLANG_DIR/tools/scan-build/* "$DESTDIR$TARGETDIR/bin" - cp -a ../$CLANG_DIR/tools/scan-view/* "$DESTDIR$TARGETDIR/bin" } build_CMAKE() { diff --git a/util/testing/Makefile.mk b/util/testing/Makefile.mk index c73502e9bc..58ceca6a00 100644 --- a/util/testing/Makefile.mk +++ b/util/testing/Makefile.mk @@ -116,8 +116,8 @@ test-lint: util/lint/lint lint-extended $(JUNIT) test-abuild: -ifneq ($(JENKINS_SKIP_SCANBUILD_TEST),y) - NAME=scanbuild; SCANBUILD_ARGS='-k -plist-html -maxloop 10' util/abuild/abuild -o $(COREBOOT_BUILD_DIR)/$${NAME} $(ABUILD_OPTIONS) --scan-build --target EMULATION_QEMU_X86_Q35 --exitcode --name $${NAME} +ifneq ($(JENKINS_SKIP_STATIC_ANALYSIS_TEST),y) + NAME=clangtidy; util/abuild/abuild -o $(COREBOOT_BUILD_DIR)/$${NAME} $(ABUILD_OPTIONS) --static-analysis --target EMULATION_QEMU_X86_Q35 endif ifneq ($(JENKINS_SKIP_GCC_TESTS),y) ifneq ($(JENKINS_SKIP_ALLTHREAD_TEST),y) @@ -172,7 +172,7 @@ test-tools: test-cleanup: rm -rf $(COREBOOT_BUILD_DIR)/chromeos $(COREBOOT_BUILD_DIR)/default rm -rf $(COREBOOT_BUILD_DIR)/chromeos-clang $(COREBOOT_BUILD_DIR)/default-clang - rm -rf $(COREBOOT_BUILD_DIR)/scanbuild + rm -rf $(COREBOOT_BUILD_DIR)/clangtidy $(MAKE) clean $(foreach tool, $(TOOLLIST), $(MAKE) -C util/$(tool) clean ; ) $(MAKE) -C src/soc/nvidia/tegra124/lp0 clean