diff --git a/cmake/sca/eclair/ECL/analysis.ecl b/cmake/sca/eclair/ECL/analysis.ecl index 118c069ca42..ddca224e2b0 100644 --- a/cmake/sca/eclair/ECL/analysis.ecl +++ b/cmake/sca/eclair/ECL/analysis.ecl @@ -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") diff --git a/cmake/sca/eclair/ECL/db_generation.ecl b/cmake/sca/eclair/ECL/db_generation.ecl new file mode 100644 index 00000000000..e10fa674481 --- /dev/null +++ b/cmake/sca/eclair/ECL/db_generation.ecl @@ -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() diff --git a/cmake/sca/eclair/ECL/reports.ecl b/cmake/sca/eclair/ECL/reports.ecl deleted file mode 100644 index cd386322ed8..00000000000 --- a/cmake/sca/eclair/ECL/reports.ecl +++ /dev/null @@ -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") diff --git a/cmake/sca/eclair/eclair.template b/cmake/sca/eclair/eclair.template new file mode 100644 index 00000000000..fd7b0fe8b77 --- /dev/null +++ b/cmake/sca/eclair/eclair.template @@ -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 +) diff --git a/cmake/sca/eclair/sca.cmake b/cmake/sca/eclair/sca.cmake new file mode 100644 index 00000000000..9eb828c67b4 --- /dev/null +++ b/cmake/sca/eclair/sca.cmake @@ -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)