sca: Add ECLAIR sca cmake implementation

Add the ECLAIR calls for the zephyr cmake environment to call
ECLAIR while the firmware is build by replacing the actual compiler
call and setup the eclair environment and call the compiler through
the eclair.

The Integration accepts a kconfig file for configuring the
analysis and the generation of the reports. The path of the
kconfig file should be provided via the variable ECLAIR_CONFIG.

db_generation.ecl has be created and introduced instead of
reports.ecl because the report generation is handled by the
sca.cmake directly.

Signed-off-by: Simon Hein <Shein@baumer.com>
This commit is contained in:
Simon Hein 2024-01-19 14:02:59 +01:00 committed by Anas Nashif
commit e0db9ce948
5 changed files with 196 additions and 59 deletions

View file

@ -1,5 +1,3 @@
-project_name=getenv("ECLAIR_PROJECT_NAME")
-project_root=getenv("ECLAIR_PROJECT_ROOT")
-setq=data_dir,getenv("ECLAIR_DATA_DIR")
-setq=set,getenv("ECLAIR_RULESET")

View file

@ -0,0 +1,28 @@
# eclair_report
# NEEDED: set the variable for the binary output directory from the environment
# variable.
setq(data_dir,getenv("ECLAIR_DATA_DIR"))
# NEEDED: set the variable for the ECLAIR project database from the environment
# variable.
setq(ecd_file,getenv("ECLAIR_PROJECT_ECD"))
# NEEDED: set the variable for the output directory from the environment
# variable.
setq(output_dir,getenv("ECLAIR_OUTPUT_DIR"))
if(file_exists(ecd_file),
db(ecd_file),
create_db(ecd_file))
setq(loaded_dir,join_paths(data_dir,"loaded"))
make_dirs(loaded_dir)
# NEEDED: generate the ecd from frame files
strings_map("load_ecb",500,"",".+\\.ecb",0,setq(ecb,join_paths(data_dir,$0)),load(ecb),rename(ecb,join_paths(loaded_dir,$0)))
strings_map("load_ecb",500,"",".*",0)
loading()
map_strings("load_ecb", dir_entries(data_dir))
loaded()

View file

@ -1,57 +0,0 @@
# eclair_report
# This file must not be renamed: it is referenced by eclair-make.sh
#
# The aim of this file is to define the eclair_report configuration
# common to IDE analyses.
quiet()
# NEEDED: set the variable for the binary output directory from the environment
# variable.
setq(data_dir,getenv("ECLAIR_DATA_DIR"))
# NEEDED: set the variable for the ECLAIR project database from the environment
# variable.
setq(ecd_file,getenv("ECLAIR_PROJECT_ECD"))
# NEEDED: set the variable for the output directory from the environment
# variable.
setq(output_dir,getenv("ECLAIR_OUTPUT_DIR"))
if(file_exists(ecd_file),
db(ecd_file),
create_db(ecd_file))
server_root("")
server("changing")
setq(loaded_dir,join_paths(data_dir,"loaded"))
make_dirs(loaded_dir)
# NEEDED: generate the ecd from frame files
strings_map("load_ecb",500,"",".+\\.ecb",0,setq(ecb,join_paths(data_dir,$0)),load(ecb),rename(ecb,join_paths(loaded_dir,$0)))
strings_map("load_ecb",500,"",".*",0)
loading()
map_strings("load_ecb", dir_entries(data_dir))
loaded()
if(string_equal(or(getenv("TEXTUAL_REPORTS"),"false"),"true")
eval_file("report__textual.ecl"))
# Output report summaries in ODT format.
#-summary_odt=join_paths(output_dir,"odt")
# Output report summaries in ODT format.
#-summary_doc=join_paths(output_dir,"doc")
# Output report summaries in pure text format.
#-summary_txt=join_paths(output_dir,"txt")
# Output full report in pure text format.
#-full_txt=join_paths(output_dir,"txt")
# Output metrics for use with spreadsheet applications (if enabled).
#-metrics_tab=join_paths(output_dir,"metrics")
# Output reports for use with spreadsheet applications
#-reports_tab=join_paths(output_dir,"reports")
server("changed")

View file

@ -0,0 +1,37 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright (c) 2024, Baumer (www.baumer.com)
# Everything before `--` are arguments for cmake invocation, those must be ignored.
# The first argument after `--` is the start of the compiler call, which is
# what we want to get to invoke ECLAIR with the compiler call which is used in the zephyr
# environment
foreach(i RANGE ${CMAKE_ARGC})
if("${CMAKE_ARGV${i}}" STREQUAL "--")
math(EXPR end_of_options "${i} + 1")
break()
endif()
endforeach()
foreach(i RANGE ${end_of_options} ${CMAKE_ARGC})
list(APPEND ZEPHYR_COMPILER_CALL ${CMAKE_ARGV${i}})
endforeach()
list(APPEND ECLAIR_ARGS +incremental
-project_name=@ECLAIR_PROJECT_NAME@ -project_root=@ZEPHYR_BASE@
-eval_file=@ECLAIR_ECL_DIR@/analysis.ecl
-eval_file=@ECLAIR_ANALYSIS_ECL_DIR@/analysis_@ECLAIR_RULESET@.ecl
@ECLAIR_ENV_ADDITIONAL_OPTIONS@)
execute_process(
COMMAND @CMAKE_COMMAND@ -E env
ECLAIR_DIAGNOSTICS_OUTPUT=@ECLAIR_DIAGNOSTICS_OUTPUT@
ECLAIR_DATA_DIR=@ECLAIR_ANALYSIS_DATA_DIR@
CC_ALIASES=@CC_ALIASES@
CXX_ALIASES=@CXX_ALIASES@
AS_ALIASES=@AS_ALIASES@
LD_ALIASES=@LD_ALIASES@
AR_ALIASES=@AR_ALIASES@
@ECLAIR_ENV@ ${ECLAIR_ARGS} -- ${ZEPHYR_COMPILER_CALL}
COMMAND_ERROR_IS_FATAL ANY
)

131
cmake/sca/eclair/sca.cmake Normal file
View file

@ -0,0 +1,131 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright (c) 2023, BUGSENG Srl
find_program(ECLAIR_ENV eclair_env REQUIRED)
message(STATUS "Found eclair_env: ${ECLAIR_ENV}")
find_program(ECLAIR_REPORT eclair_report REQUIRED)
message(STATUS "Found eclair_report: ${ECLAIR_REPORT}")
# ECLAIR Settings
set(ECLAIR_PROJECT_NAME "Zephyr-${BOARD}${BOARD_QUALIFIERS}")
set(ECLAIR_OUTPUT_DIR "${CMAKE_BINARY_DIR}/sca/eclair")
set(ECLAIR_ECL_DIR "${ZEPHYR_BASE}/cmake/sca/eclair/ECL")
set(ECLAIR_ANALYSIS_ECL_DIR "${ZEPHYR_BASE}/cmake/sca/eclair/ECL")
set(ECLAIR_DIAGNOSTICS_OUTPUT "${ECLAIR_OUTPUT_DIR}/DIAGNOSTIC.txt")
set(ECLAIR_ANALYSIS_DATA_DIR "${ECLAIR_OUTPUT_DIR}/analysis_data")
set(ECLAIR_PROJECT_ECD "${ECLAIR_OUTPUT_DIR}/PROJECT.ecd")
set(CC_ALIASES "${CMAKE_C_COMPILER}")
set(CXX_ALIASES "${CMAKE_CXX_COMPILER}")
set(AS_ALIASES "${CMAKE_AS}")
set(LD_ALIASES "${CMAKE_LINKER}")
set(AR_ALIASES "${CMAKE_ASM_COMPILER_AR} ${CMAKE_C_COMPILER_AR} ${CMAKE_CXX_COMPILER_AR}")
set(ECLAIR_ENV_ADDITIONAL_OPTIONS "")
set(ECLAIR_REPORT_ADDITIONAL_OPTIONS "")
# Default value
set(ECLAIR_RULESET first_analysis)
# ECLAIR env
if(ECLAIR_RULESET_FIRST_ANALYSIS)
set(ECLAIR_RULESET first_analysis)
elseif(ECLAIR_RULESET_STU)
set(ECLAIR_RULESET STU)
elseif(ECLAIR_RULESET_STU_HEAVY)
set(ECLAIR_RULESET STU_heavy)
elseif(ECLAIR_RULESET_WP)
set(ECLAIR_RULESET WP)
elseif(ECLAIR_RULESET_STD_LIB)
set(ECLAIR_RULESET std_lib)
elseif(ECLAIR_RULESET_USER)
set(ECLAIR_RULESET ${ECLAIR_USER_RULESET_NAME})
if(IS_ABSOLUTE ${ECLAIR_USER_RULESET_PATH})
set(ECLAIR_ANALYSIS_ECL_DIR ${ECLAIR_USER_RULESET_PATH})
else()
set(ECLAIR_ANALYSIS_ECL_DIR ${APPLICATION_CONFIG_DIR}/${ECLAIR_USER_RULESET_PATH})
endif()
endif()
# ECLAIR report
if (ECLAIR_METRICS_TAB)
list(APPEND ECLAIR_REPORT_ADDITIONAL_OPTIONS "-metrics_tab=${ECLAIR_OUTPUT_DIR}/metrics")
endif()
if (ECLAIR_REPORTS_TAB)
list(APPEND ECLAIR_REPORT_ADDITIONAL_OPTIONS "-reports_tab=${ECLAIR_OUTPUT_DIR}/reports")
endif()
if (ECLAIR_REPORTS_SARIF)
list(APPEND ECLAIR_REPORT_ADDITIONAL_OPTIONS "-reports_sarif=${ECLAIR_OUTPUT_DIR}/reports.sarif")
endif()
if (ECLAIR_SUMMARY_TXT)
list(APPEND ECLAIR_REPORT_ADDITIONAL_OPTIONS "-summary_txt=${ECLAIR_OUTPUT_DIR}/summary_txt")
endif()
if (ECLAIR_SUMMARY_DOC)
list(APPEND ECLAIR_REPORT_ADDITIONAL_OPTIONS "-summary_doc=${ECLAIR_OUTPUT_DIR}/summary_doc")
endif()
if (ECLAIR_SUMMARY_ODT)
list(APPEND ECLAIR_REPORT_ADDITIONAL_OPTIONS "-summary_odt=${ECLAIR_OUTPUT_DIR}/summary_odt")
endif()
if (ECLAIR_FULL_TXT_ALL_AREAS)
list(APPEND ECLAIR_REPORT_ADDITIONAL_OPTIONS "-setq=report_areas,areas")
endif()
if (ECLAIR_FULL_TXT_FIRST_AREA)
list(APPEND ECLAIR_REPORT_ADDITIONAL_OPTIONS "-setq=report_areas,first_area")
endif()
if (ECLAIR_FULL_TXT)
list(APPEND ECLAIR_REPORT_ADDITIONAL_OPTIONS "-full_txt=${ECLAIR_OUTPUT_DIR}/report_full_txt")
endif()
if (ECLAIR_FULL_DOC_ALL_AREAS)
list(APPEND ECLAIR_REPORT_ADDITIONAL_OPTIONS "-setq=report_areas,areas")
endif()
if (ECLAIR_FULL_DOC_FIRST_AREA)
list(APPEND ECLAIR_REPORT_ADDITIONAL_OPTIONS "-setq=report_areas,first_area")
endif()
if (ECLAIR_FULL_DOC)
list(APPEND ECLAIR_REPORT_ADDITIONAL_OPTIONS "-full_doc=${ECLAIR_OUTPUT_DIR}/report_full_doc")
endif()
if (ECLAIR_FULL_ODT)
list(APPEND ECLAIR_REPORT_ADDITIONAL_OPTIONS "-full_odt=${ECLAIR_OUTPUT_DIR}/report_full_odt")
endif()
message(STATUS "ECLAIR outputs have been written to: ${ECLAIR_OUTPUT_DIR}")
message(STATUS "ECLAIR ECB files have been written to: ${ECLAIR_ANALYSIS_DATA_DIR}")
add_custom_target(eclair_setup_analysis_dir ALL
COMMAND ${CMAKE_COMMAND} -E remove_directory ${ECLAIR_ANALYSIS_DATA_DIR}
COMMAND ${CMAKE_COMMAND} -E make_directory ${ECLAIR_ANALYSIS_DATA_DIR}
VERBATIM
USES_TERMINAL
)
# configure the camke script which will be used to replace the compiler call with the eclair_env
# call which calls the compiler and to generate analysis files.
configure_file(${CMAKE_CURRENT_LIST_DIR}/eclair.template ${ECLAIR_OUTPUT_DIR}/eclair.cmake @ONLY)
set(launch_environment ${CMAKE_COMMAND} -P ${ECLAIR_OUTPUT_DIR}/eclair.cmake --)
set(CMAKE_C_COMPILER_LAUNCHER ${launch_environment} CACHE INTERNAL "")
# This target is used to generate the ECLAIR database when all the compilation is done and the
# elf file was generated with this we cane make sure that the analysis is completed.
add_custom_target(eclair_report ALL
COMMAND ${CMAKE_COMMAND} -E env
ECLAIR_DATA_DIR=${ECLAIR_ANALYSIS_DATA_DIR}
ECLAIR_OUTPUT_DIR=${ECLAIR_OUTPUT_DIR}
ECLAIR_PROJECT_ECD=${ECLAIR_PROJECT_ECD}
${ECLAIR_REPORT} -quiet -eval_file=${ECLAIR_ECL_DIR}/db_generation.ecl
DEPENDS ${CMAKE_BINARY_DIR}/zephyr/zephyr.elf
VERBATIM
USES_TERMINAL
COMMAND_EXPAND_LISTS
)
# This command is used to generate the final reports from the database and print the overall results
add_custom_target(eclair_summary_print ALL
COMMAND ${ECLAIR_REPORT}
-db=${ECLAIR_PROJECT_ECD} ${ECLAIR_REPORT_ADDITIONAL_OPTIONS}
-overall_txt=${ECLAIR_OUTPUT_DIR}/summary_overall.txt
COMMAND ${CMAKE_COMMAND} -E cat ${ECLAIR_OUTPUT_DIR}/summary_overall.txt
)
add_dependencies(eclair_summary_print eclair_report)