diff --git a/CMakeLists.txt b/CMakeLists.txt index a7935904..074b80ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,11 +61,17 @@ set(CMAKE_C_EXTENSIONS TRUE) if(RMM_STATIC_ANALYSIS_CPPCHECK) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) endif() + # # Include the platform makefile # include("cmake/Platforms.cmake") +# +# Include Coverage report framework +# +include("cmake/CoverageReport.cmake") + # # Include the Unit Test Framework # diff --git a/cmake/CoverageReport.cmake b/cmake/CoverageReport.cmake new file mode 100644 index 00000000..67c901db --- /dev/null +++ b/cmake/CoverageReport.cmake @@ -0,0 +1,151 @@ +# +# SPDX-License-Identifier: BSD-3-Clause +# SPDX-FileCopyrightText: Copyright TF-RMM Contributors. +# + +arm_config_option( + NAME RMM_COVERAGE + HELP "Enable coverage tests" + TYPE BOOL + DEFAULT "OFF") + +arm_config_option( + NAME RMM_HTML_COV_REPORT + HELP "Enable html coverage report" + TYPE BOOL + DEPENDS RMM_COVERAGE + DEFAULT "ON") + +arm_config_option( + NAME COVERAGE_REPORT_NAME + HELP "Canonical name for the coverage report" + TYPE STRING + DEPENDS RMM_COVERAGE + DEFAULT "tf-rmm-coverage" + ADVANCED) + +macro(check_and_prepare_c_coverage_flags) + # Store a copy of CMAKE_C_FLAGS + set(CMAKE_C_FLAGS_BACKUP "${CMAKE_C_FLAGS}") + + foreach(flag ${ARGN}) + string(REPLACE "-" "_" flag_no_hyphen ${flag}) + check_c_compiler_flag("-${flag}" COVERAGE_C_FLAG_${flag_no_hyphen}) + if (COVERAGE_C_FLAG_${flag_no_hyphen}) + # Some of the coverage flags depend on the previous ones being + # enabled, so add them to the C Flags now for the next check. + string(APPEND CMAKE_C_FLAGS " -${flag}") + string(APPEND COVERAGE_C_FLAGS " -${flag}") + else() + set(COVERAGE_SUPPORTED "FALSE") + endif() + endforeach() + + # Restore CMAKE_C_FLAGS + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_BACKUP}") +endmacro(check_and_prepare_c_coverage_flags) + +macro(check_and_prepare_cxx_coverage_flags) + # Store a copy of CMAKE_CXX_FLAGS + set(CMAKE_CXX_FLAGS_BACKUP "${CMAKE_CXX_FLAGS}") + + foreach(flag ${ARGN}) + string(REPLACE "-" "_" flag_no_hyphen ${flag}) + check_cxx_compiler_flag("-${flag}" COVERAGE_CXX_FLAG_${flag_no_hyphen}) + if (COVERAGE_CXX_FLAG_${flag_no_hyphen}) + # Some of the coverage flags depend on the previous ones being + # enabled, so add them to the CXX Flags now for the next check. + string(APPEND CMAKE_CXX_FLAGS " -${flag}") + string(APPEND COVERAGE_CXX_FLAGS " -${flag}") + endif() + endforeach() + + # Restore CMAKE_CXX_FLAGS + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_BACKUP}") +endmacro(check_and_prepare_cxx_coverage_flags) + +if(RMM_COVERAGE) + + find_program(GCOVR_EXECUTABLE "gcovr" DOC "Path to gcovr") + + if(${GCOVR_EXECUTABLE} STREQUAL "GCOVR_EXECUTABLE-NOTFOUND") + message (WARNING "gcovr executable not found. Coverage tests disabled") + return() + endif() + + include(CheckCCompilerFlag) + include(CheckCXXCompilerFlag) + + if(CMAKE_C_COMPILER_ID STREQUAL "Clang") + # Using LLVM. Select the coverage flags to test + set(COVERAGE_FLAGS + ftest-coverage + fprofile-instr-generate + fprofile-arcs + fcoverage-mapping) + + # Setup the right coverage tool if using llvm + set(GCOVR_EXE_OPTION --gcov-executable "llvm-cov gcov" + CACHE INTERNAL "GCOV_EXECUTABLE") + + elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU") + # Using GNU. Select the coverage flags to test + set(COVERAGE_FLAGS + -coverage) + + # Flags needed to enable coverage testing + string(APPEND CMAKE_EXE_LINKER_FLAGS " -coverage -lgcov ") + else() + message(WARNING "Toolchain ${CMAKE_C_COMPILER_ID} does not support coverage") + return() + endif() + + set(COVERAGE_SUPPORTED "TRUE") + check_and_prepare_c_coverage_flags(${COVERAGE_FLAGS}) + check_and_prepare_cxx_coverage_flags(${COVERAGE_FLAGS}) + + # If coverage is not supported by the C compiler, or the C and C++ + # compilers do not support the same set of coverage flags (which can + # lead to link problems), abort. + if ((COVERAGE_SUPPORTED STREQUAL "FALSE") OR + (NOT (COVERAGE_C_FLAGS STREQUAL COVERAGE_CXX_FLAGS))) + message (WARNING "Toolchain ${CMAKE_C_COMPILER_ID} does not support coverage") + return() + endif() + + # Setup flags for coverage + foreach(language in ITEMS C CXX) + string(APPEND CMAKE_${language}_FLAGS + " ${COVERAGE_${language}_FLAGS} ") + endforeach() + + # Directory where to store the results + set(COVERAGE_DIRECTORY + "${CMAKE_BINARY_DIR}/$/coverage") + + set(COVERAGE_OUTPUT "${COVERAGE_DIRECTORY}/${COVERAGE_REPORT_NAME}") + + if(RMM_HTML_COV_REPORT) + set(HTML_REPORT --html-details ${COVERAGE_OUTPUT}.html) + endif() + + # + # Rules for coverage report generation + # + add_custom_target(run-coverage + COMMAND ${CMAKE_COMMAND} -E make_directory "${COVERAGE_DIRECTORY}" + COMMAND ${GCOVR_EXECUTABLE} + ${GCOVR_EXE_OPTION} + --exclude "'((.+)ext(.+))|((.+)CMakeFiles(.+)\..)|((.+)\.cpp)|((.+)test(.+))'" + -r ${CMAKE_SOURCE_DIR} + -x ${COVERAGE_OUTPUT}.xml + ${HTML_REPORT} + ${CMAKE_BINARY_DIR}) + # + # Add dependency on unit test target if being invoked in a + # multi-target build command line. + # + if(RMM_UNITTESTS) + add_dependencies(run-coverage run-unittests) + endif() +endif() # RMM_COVERAGE diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst index d41a145a..0db4cdc7 100644 --- a/docs/getting_started/build-options.rst +++ b/docs/getting_started/build-options.rst @@ -162,7 +162,7 @@ Run checkincludes on entire codebase: cmake -DRMM_CONFIG=fvp_defcfg -S ${RMM_SOURCE_DIR} -B ${RMM_BUILD_DIR} cmake --build ${RMM_BUILD_DIR} -- checkincludes-codebase -14. Perform unit tests on development host: +14. Perform unit tests on development host: Build and run unit tests on host platform. It is recommended to do the Debug build of RMM. @@ -172,6 +172,17 @@ build of RMM. cmake -DRMM_CONFIG=host_defcfg -DHOST_VARIANT=host_test -DCMAKE_BUILD_TYPE=Debug -S ${RMM_SOURCE_DIR} -B ${RMM_BUILD_DIR} cmake --build ${RMM_BUILD_DIR} -- run-unittests +Run coverage analysis on unit tests. + +.. code-block:: bash + + cmake -DRMM_CONFIG=host_defcfg -DHOST_VARIANT=host_test -DRMM_COVERAGE=ON -DCMAKE_BUILD_TYPE=Debug -S ${RMM_SOURCE_DIR} -B ${RMM_BUILD_DIR} + cmake --build ${RMM_BUILD_DIR} -- run-coverage + +The above commands will automatically generate the HTML coverage report in folder +`build/Debug/coverage` within build directory. The HTML generation can be +disabled by setting `RMM_HTML_COV_REPORT=OFF`. + .. _build_options_table: ################### @@ -208,9 +219,9 @@ The |RMM| build system supports the following CMake build options. MBEDTLS_ECP_MAX_OPS ,248 - ,1000 ,"Number of max operations per ECC signing iteration" RMM_FPU_USE_AT_REL2 ,ON | OFF ,OFF(fake_host) ON(aarch64),"Enable FPU/SIMD usage in RMM." RMM_MAX_GRANULES , ,0 ,"Maximum number of memory granules available to the system" - HOST_VARIANT ,host_build | host_test ,host_build , "Variant to build for the host platform. Only available when RMM_PLATFORM=host" - - + HOST_VARIANT ,host_build | host_test ,host_build ,"Variant to build for the host platform. Only available when RMM_PLATFORM=host" + RMM_COVERAGE ,ON | OFF ,OFF ,"Enable coverage analysis" + RMM_HTML_COV_REPORT ,ON | OFF ,ON ,"Enable HTML output report for coverage analysis" .. _llvm_build: diff --git a/docs/getting_started/getting-started.rst b/docs/getting_started/getting-started.rst index 4e8e07b3..88747c9e 100644 --- a/docs/getting_started/getting-started.rst +++ b/docs/getting_started/getting-started.rst @@ -49,6 +49,7 @@ The following tools are required to obtain and build |RMM|: "Git",, "Firmware, Documentation" "Graphviz dot",">v2.38.0","Documentation" "docutils",">v2.38.0","Documentation" + "gcovr",">=v4.2","Tools(Coverage analysis)" .. _getting_started_toolchain: @@ -143,6 +144,30 @@ Install them with ``pip3``: cd pip3 install -r docs/requirements.txt +############################################ +Install coverage tools analysis dependencies +############################################ + +.. note:: + + This is an optional step only needed if you intend to run coverage + analysis on the source code. + +On Ubuntu, ``gcovr`` tool can be installed in two different ways: + +Using the pagckage manager: + +.. code-block:: bash + + sudo apt-get install gcovr + +The second (and recommended) way is install it with ``pip3``: + +.. code-block:: bash + + pip3 install --upgrade pip + pip3 install gcovr + .. _getting_started_get_source: ######################### diff --git a/plat/host/host_test/CMakeLists.txt b/plat/host/host_test/CMakeLists.txt index c28fb13a..0e477c6d 100644 --- a/plat/host/host_test/CMakeLists.txt +++ b/plat/host/host_test/CMakeLists.txt @@ -9,6 +9,7 @@ add_library(rmm-plat-host_test) arm_config_option( NAME RMM_UNITTESTS HELP "Enable Unitests for the build" + TYPE BOOL DEFAULT "ON" TYPE INTERNAL)