diff --git a/.github/workflows/linux-build-and-test.yaml b/.github/workflows/linux-build-and-test.yaml index 79595029a..54fe611ba 100644 --- a/.github/workflows/linux-build-and-test.yaml +++ b/.github/workflows/linux-build-and-test.yaml @@ -65,8 +65,6 @@ jobs: sudo apt-get update sudo apt-get install flex bison lcov systemd-coredump gdb libipc-run-perl \ libtest-most-perl ${{ matrix.extra_packages }} - # The GCC 11 gcov segfaults with the coverage info generated by clang. - sudo ln -sf $(which llvm-cov-14) $(which gcov) - name: Install macOS Dependencies if: runner.os == 'macOS' @@ -173,12 +171,19 @@ jobs: if: matrix.coverage run: make -j $MAKE_JOBS -k -C build coverage - - name: Upload coverage report + - name: Send coverage report to Codecov.io app if: matrix.coverage uses: codecov/codecov-action@v3 with: file: ./build/codecov/timescaledb-codecov.info + - name: Save LCOV coverage report + if: matrix.coverage + uses: actions/upload-artifact@v3 + with: + name: LCOV coverage report ${{ matrix.os }} ${{ matrix.name }} ${{ matrix.pg }} + path: ./build/codecov/codecov-report + - name: Show regression diffs if: always() id: collectlogs diff --git a/CMakeLists.txt b/CMakeLists.txt index 56aad0411..7e2eac926 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -644,6 +644,7 @@ add_custom_target(licensecheck if(CODECOVERAGE) add_subdirectory(codecov) endif() + if(IS_DIRECTORY ${PROJECT_SOURCE_DIR}/.git) configure_file(${PROJECT_SOURCE_DIR}/scripts/githooks/commit_msg.py ${PROJECT_SOURCE_DIR}/.git/hooks/commit-msg COPYONLY) diff --git a/codecov/CMakeLists.txt b/codecov/CMakeLists.txt index f6f3c7439..024718ec9 100644 --- a/codecov/CMakeLists.txt +++ b/codecov/CMakeLists.txt @@ -5,7 +5,7 @@ # the --coverage option for the compiler and this is done in the top-level # CMakeLists.txt so that the option covers all build targets in the project. # -# Given that all dependencies (lcov, genhtml) are installed, and CMake is +# Given that all dependencies (lcov, gcov, genhtml) are installed, and CMake is # initialized with -DCODECOVERAGE=ON, it should be possible to generate a code # coverage report by running: # @@ -13,16 +13,43 @@ # # The report is generated in REPORT_DIR and can be viewed in a web browser. +# If we use clang, prefer the LLVM gcov. The "normal" gcov segfaults with the +# coverage info generated by clang, and the LLVM gcov with GCC-generated +# coverage gives weird errors like GCOV_TAG_COUNTER_ARCS mismatch. +set(GCOV_NAMES "gcov") +if(CMAKE_C_COMPILER_ID MATCHES "Clang|AppleClang") + string(REGEX MATCH "^[0-9]+" CMAKE_C_COMPILER_VERSION_MAJOR + ${CMAKE_C_COMPILER_VERSION}) + list(PREPEND GCOV_NAMES "llvm-cov-${CMAKE_C_COMPILER_VERSION_MAJOR}") +endif() + +find_program(GCOV NAMES ${GCOV_NAMES}) + # Find lcov for html output find_program(LCOV lcov) -if(LCOV) +if(NOT GCOV) + message(STATUS "Install gcov to generate code coverage reports") +elseif(NOT LCOV) + message(STATUS "Install lcov to generate code coverage reports") +else() + message(STATUS "Using lcov ${LCOV}:") + execute_process(COMMAND ${LCOV} --version) + message(STATUS "Using gcov ${GCOV}:") + execute_process(COMMAND ${GCOV} --version) + # Final tracefile for code coverage set(OUTPUT_FILE "timescaledb-codecov.info") # Directory where to generate the HTML report set(REPORT_DIR "codecov-report") + # We can't directly use llvm-cov as --gcov-tool, because it has to be called + # like "llvm-cov gcov " for that. Thankfully, if its $0 is gcov, it + # will understand that we want it to operate like gcov. Just create a symlink. + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/gcov + COMMAND ln -s ${GCOV} ${CMAKE_CURRENT_BINARY_DIR}/gcov) + # The baseline run needs to run before tests to learn what zero coverage looks # like add_custom_command( @@ -32,12 +59,12 @@ if(LCOV) ${LCOV} --capture --initial # Initial run --no-external # Do not include external source files --base-directory ${CMAKE_SOURCE_DIR} --directory ${CMAKE_BINARY_DIR} - --output-file ${OUTPUT_FILE}.base - DEPENDS timescaledb-tsl timescaledb timescaledb-loader) + --output-file ${OUTPUT_FILE}.base --gcov-tool + ${CMAKE_CURRENT_BINARY_DIR}/gcov + DEPENDS timescaledb-tsl timescaledb timescaledb-loader + ${CMAKE_CURRENT_BINARY_DIR}/gcov) - add_custom_target( - coverage_base DEPENDS timescaledb-tsl timescaledb timescaledb-loader - ${OUTPUT_FILE}.base) + add_custom_target(coverage_base DEPENDS ${OUTPUT_FILE}.base) # Ensure baseline file is generated before tests add_dependencies(installcheck coverage_base) @@ -46,8 +73,10 @@ if(LCOV) add_custom_command( OUTPUT ${OUTPUT_FILE}.test COMMENT "Generating code coverage test file" - COMMAND ${LCOV} --capture --no-external --base-directory ${CMAKE_SOURCE_DIR} - --directory ${CMAKE_BINARY_DIR} --output-file ${OUTPUT_FILE}.test + COMMAND + ${LCOV} --capture --no-external --base-directory ${CMAKE_SOURCE_DIR} + --directory ${CMAKE_BINARY_DIR} --output-file ${OUTPUT_FILE}.test + --gcov-tool ${CMAKE_CURRENT_BINARY_DIR}/gcov DEPENDS ${OUTPUT_FILE}.base coverage_base) # Make sure coverage_test runs after tests (installcheck) finish @@ -59,8 +88,10 @@ if(LCOV) add_custom_command( OUTPUT ${OUTPUT_FILE} COMMENT "Generating final code coverage file" - COMMAND ${LCOV} --add-tracefile ${OUTPUT_FILE}.base --add-tracefile - ${OUTPUT_FILE}.test --output-file ${OUTPUT_FILE} + COMMAND + ${LCOV} --add-tracefile ${OUTPUT_FILE}.base --add-tracefile + ${OUTPUT_FILE}.test --output-file ${OUTPUT_FILE} --gcov-tool + ${CMAKE_CURRENT_BINARY_DIR}/gcov DEPENDS ${OUTPUT_FILE}.test coverage_test) add_custom_target(coverage_final DEPENDS ${OUTPUT_FILE}) @@ -90,14 +121,12 @@ if(LCOV) add_dependencies(coverage coverage_final) add_custom_command( - TARGET coverage - POST_BUILD - COMMENT + COMMAND + echo "Open file://${CMAKE_CURRENT_BINARY_DIR}/${REPORT_DIR}/index.html in a browser to view the report" - ) + TARGET coverage POST_BUILD + COMMENT) else() message(STATUS "Install genhtml to generate code coverage reports") endif(GENHTML) -else() - message(STATUS "Install lcov to generate code coverage reports") -endif(LCOV) +endif()