diff --git a/CMakeLists.txt b/CMakeLists.txt index db79e34fdfa..0265c99483f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1033,25 +1033,43 @@ Build and link with code coverage support (only for Debug targets)." mark_as_advanced(WITH_COMPILER_CODE_COVERAGE) if(WITH_COMPILER_CODE_COVERAGE) - if(NOT CMAKE_COMPILER_IS_GNUCC) - message(WARNING "WITH_COMPILER_CODE_COVERAGE only works with GCC currently.") + if(CMAKE_COMPILER_IS_GNUCC) + set(_code_coverage_defaults "--coverage") + elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") + get_filename_component(COMPILER_DIRECTORY ${CMAKE_CXX_COMPILER} DIRECTORY) + find_program(LLVM_COV "llvm-cov" ${COMPILER_DIRECTORY} NO_DEFAULT_PATH) + find_program(LLVM_PROFDATA "llvm-profdata" ${COMPILER_DIRECTORY} NO_DEFAULT_PATH) + if(NOT LLVM_COV OR NOT LLVM_PROFDATA) + message(WARNING "Could not find code coverage tools, disabling code coverage. You may explicitly specify LLVM_COV and LLVM_PROFDATA to work around this warning.") + set(WITH_COMPILER_CODE_COVERAGE OFF) + else() + set(_code_coverage_defaults "-fprofile-instr-generate -fcoverage-mapping") + endif() + else() + message("unsupported compiler ${CMAKE_C_COMPILER_ID} for WITH_COMPILER_CODE_COVERAGE, disabling.") set(WITH_COMPILER_CODE_COVERAGE OFF) endif() -endif() -if(WITH_COMPILER_CODE_COVERAGE) - set(_code_coverage_defaults "--coverage") + # The code above could have disabled the feature, so check again. + if(WITH_COMPILER_CODE_COVERAGE) set(COMPILER_CODE_COVERAGE_CFLAGS ${_code_coverage_defaults} CACHE STRING "C flags for code coverage" ) - mark_as_advanced(COMPILER_CODE_COVERAGE_CFLAGS) + mark_as_advanced(COMPILER_CODE_COVERAGE_CFLAGS) set(COMPILER_CODE_COVERAGE_CXXFLAGS ${_code_coverage_defaults} CACHE STRING "C++ flags for code coverage" ) - mark_as_advanced(COMPILER_CODE_COVERAGE_CXXFLAGS) - unset(_code_coverage_defaults) + mark_as_advanced(COMPILER_CODE_COVERAGE_CXXFLAGS) + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(_code_coverage_dir_default "${CMAKE_BINARY_DIR}/coverage") + set(COMPILER_CODE_COVERAGE_DATA_DIR ${_code_coverage_dir_default} CACHE STRING "Directory for code coverage data") + mark_as_advanced(COMPILER_CODE_COVERAGE_DATA_DIR) + unset(_code_coverage_dir_default) + endif() + unset(_code_coverage_defaults) + endif() endif() if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") @@ -1463,8 +1481,15 @@ set(PLATFORM_LINKFLAGS_RELEASE "") set(PLATFORM_LINKFLAGS_EXECUTABLE "") if(WITH_COMPILER_CODE_COVERAGE) - string(APPEND CMAKE_C_FLAGS_DEBUG " ${COMPILER_CODE_COVERAGE_CFLAGS}") - string(APPEND CMAKE_CXX_FLAGS_DEBUG " ${COMPILER_CODE_COVERAGE_CXXFLAGS}") + if(CMAKE_COMPILER_IS_GNUCC) + # GCC only supports this on debug builds. + string(APPEND CMAKE_C_FLAGS_DEBUG " ${COMPILER_CODE_COVERAGE_CFLAGS}") + string(APPEND CMAKE_CXX_FLAGS_DEBUG " ${COMPILER_CODE_COVERAGE_CXXFLAGS}") + elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") + # Clang will allow it on all builds. + string(APPEND CMAKE_C_FLAGS " ${COMPILER_CODE_COVERAGE_CFLAGS}") + string(APPEND CMAKE_CXX_FLAGS " ${COMPILER_CODE_COVERAGE_CXXFLAGS}") + endif() endif() if(NOT CMAKE_BUILD_TYPE MATCHES "Release") @@ -2509,10 +2534,10 @@ if(WITH_PYTHON) set(_numpy_include "_core/include") if(PYTHON_VERSION VERSION_LESS "3.13") set(_numpy_include "core/include") - endif() + endif() find_python_package(numpy "${_numpy_include}") unset(_numpy_include) - endif() + endif() endif() if(WIN32 OR APPLE) diff --git a/build_files/cmake/testing.cmake b/build_files/cmake/testing.cmake index bb139f3e6e0..7b04199663d 100644 --- a/build_files/cmake/testing.cmake +++ b/build_files/cmake/testing.cmake @@ -39,7 +39,9 @@ function(blender_test_set_envvars testname envvar_list) list(APPEND envvar_list "${_lsan_options}" "${_asan_options}") endif() endif() - + if(WITH_COMPILER_CODE_COVERAGE AND CMAKE_C_COMPILER_ID MATCHES "Clang") + list(APPEND envvar_list "LLVM_PROFILE_FILE=${COMPILER_CODE_COVERAGE_DATA_DIR}/raw/blender_%p.profraw") + endif() # Can only be called once per test to define its custom environment variables. set_tests_properties(${testname} PROPERTIES ENVIRONMENT "${envvar_list}") endfunction() diff --git a/lib/macos_arm64 b/lib/macos_arm64 index 61f8c3337c9..e07a7e9ab96 160000 --- a/lib/macos_arm64 +++ b/lib/macos_arm64 @@ -1 +1 @@ -Subproject commit 61f8c3337c951eef88c254f5f65f808b4ff4ce58 +Subproject commit e07a7e9ab9617d5a5ff5564a5e974c05363eea32 diff --git a/lib/windows_x64 b/lib/windows_x64 index 9bad6ade51f..cdef40845cd 160000 --- a/lib/windows_x64 +++ b/lib/windows_x64 @@ -1 +1 @@ -Subproject commit 9bad6ade51fd04ee8713dccff9e57ec5661e2578 +Subproject commit cdef40845cd1760e0361673529703bfc5c843838 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index dce54ffdcf5..842e8247cea 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -71,15 +71,70 @@ endif() add_subdirectory(gtests) if(WITH_COMPILER_CODE_COVERAGE) - set(COVERAGE_SCRIPT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/coverage/coverage.py) + if(CMAKE_COMPILER_IS_GNUCC) + set(COVERAGE_SCRIPT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/coverage/coverage.py) - add_custom_target(coverage-report - ${PYTHON_EXECUTABLE} ${COVERAGE_SCRIPT_PATH} report --build-directory ${CMAKE_BINARY_DIR} - USES_TERMINAL - ) + add_custom_target(coverage-report + ${PYTHON_EXECUTABLE} ${COVERAGE_SCRIPT_PATH} report --build-directory ${CMAKE_BINARY_DIR} --no-browser + USES_TERMINAL + ) - add_custom_target(coverage-reset - ${PYTHON_EXECUTABLE} ${COVERAGE_SCRIPT_PATH} reset --build-directory ${CMAKE_BINARY_DIR} - USES_TERMINAL - ) + add_custom_target(coverage-show + ${PYTHON_EXECUTABLE} ${COVERAGE_SCRIPT_PATH} report --build-directory ${CMAKE_BINARY_DIR} + USES_TERMINAL + ) + + add_custom_target(coverage-reset + ${PYTHON_EXECUTABLE} ${COVERAGE_SCRIPT_PATH} reset --build-directory ${CMAKE_BINARY_DIR} + USES_TERMINAL + ) + elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") + add_custom_target(coverage-reset + COMMAND ${CMAKE_COMMAND} -E + remove_directory ${COMPILER_CODE_COVERAGE_DATA_DIR} + USES_TERMINAL + ) + add_custom_target(coverage-merge + COMMENT "Merging code-coverage data." + BYPRODUCTS "${COMPILER_CODE_COVERAGE_DATA_DIR}/blender.profdata" + COMMAND "${LLVM_PROFDATA}" + merge + -sparse + ${COMPILER_CODE_COVERAGE_DATA_DIR}/raw/*.profraw + -o ${COMPILER_CODE_COVERAGE_DATA_DIR}/blender.profdata + ) + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 18.1 OR + (CMAKE_C_COMPILER_ID MATCHES "AppleClang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 17.0) + ) + # Available clang on 18.1+ only , Apple's compiler doesn't map 1:1 to clang + # versions so on apple we check for version 17+ which maps to clang + # version 19.1.4, given this is somewhat unintuitive there is a handy table on + # https://en.wikipedia.org/wiki/Xcode#Xcode_15.0_-_(since_visionOS_support)_2 + set(_cov_extra_args -show-directory-coverage) + endif() + add_custom_target(coverage-report + BYPRODUCTS "${COMPILER_CODE_COVERAGE_DATA_DIR}/report/index.html" + SOURCES "${COMPILER_CODE_COVERAGE_DATA_DIR}/blender.profdata" + COMMENT "Generating code-coverage report." + COMMAND "${LLVM_COV}" show + -format=html + -show-instantiations=true + -show-line-counts-or-regions + ${_cov_extra_args} + -instr-profile=${COMPILER_CODE_COVERAGE_DATA_DIR}/blender.profdata + --output-dir=${COMPILER_CODE_COVERAGE_DATA_DIR}/report + $ + USES_TERMINAL + ) + if(NOT WIN32) + set(_open_cmd "open") + endif() + add_custom_target(coverage-show + COMMENT "Starting browser for ${COMPILER_CODE_COVERAGE_DATA_DIR}/report/index.html" + COMMAND ${_open_cmd} "${COMPILER_CODE_COVERAGE_DATA_DIR}/report/index.html" + SOURCES "${COMPILER_CODE_COVERAGE_DATA_DIR}/report/index.html" + ) + unset(_cov_extra_args) + unset(_open_cmd) + endif() endif()