diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df8cadb26..91129d22f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,7 +42,6 @@ jobs: - name: Test run: cargo xtask test --build-type ${{env.BUILD_TYPE}} - build_with_hash: runs-on: ubuntu-latest @@ -55,4 +54,43 @@ jobs: run: cargo xtask build --build-type ${{env.BUILD_TYPE}} --with-rust false --with-hash true --verbose true - name: Test - run: cargo xtask test --build-type ${{env.BUILD_TYPE}} --with-rust false + run: cargo xtask test --build-type ${{env.BUILD_TYPE}} + + coverage: + strategy: + matrix: + with_rust: ['true', 'false'] + runs-on: ubuntu-latest + name: with_rust=${{ matrix.with_rust }} + + steps: + - uses: actions/checkout@v3 + with: + submodules: 'true' + + - name: Setup rustup + run: | + rustup default stable + rustup update + rustup component add llvm-tools + + - name: Setup grcov + run: | + curl -LO https://github.com/mozilla/grcov/releases/download/v0.8.19/grcov-x86_64-unknown-linux-gnu.tar.bz2 + echo 098be4d60b8016913542d58456fea6e771890096d1bf86e7f83dac650ba4b58a grcov-x86_64-unknown-linux-gnu.tar.bz2 | sha256sum -c - + tar xf grcov-x86_64-unknown-linux-gnu.tar.bz2 + + - name: Build + env: + CC: clang + run: cargo xtask build --build-type Debug --with-rust ${{matrix.with_rust}} --with-coverage true --verbose true + + - name: Test + run: | + cargo xtask test --build-type Debug + ./grcov . -s . -b . --keep-only 'src/*' --llvm -t lcov -o coverage.lcov + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 05fb63613..6b2ea79dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,11 @@ if(${CMAKE_C_COMPILER_ID} STREQUAL "GNU" OR add_compile_definitions(_GNU_SOURCE) option(ENABLE_GCOV "Coverage support" false) if(ENABLE_GCOV) - set(CMAKE_C_FLAGS "-coverage ${CMAKE_C_FLAGS}") + if (WITH_RUST AND ${CMAKE_C_COMPILER_ID} STREQUAL "Clang") + set(CMAKE_C_FLAGS "-fprofile-instr-generate -fcoverage-mapping ${CMAKE_C_FLAGS}") + else() + set(CMAKE_C_FLAGS "--coverage ${CMAKE_C_FLAGS}") + endif() endif() # Use NO_UNDEFINED=no when running with address sanitizer @@ -55,6 +59,7 @@ elseif(MSVC) set(BUILD_DLL false) endif() + check_c_compiler_flag(-fvisibility=hidden FVISIBILITY_HIDDEN) if(${FVISIBILITY_HIDDEN}) set(CMAKE_C_FLAGS "-fvisibility=hidden ${CMAKE_C_FLAGS}") @@ -80,13 +85,18 @@ option(USE_VALGRIND "Use valgrind when testing" true) option(WITH_RUST "Use rust implemented internals (experimental)" false) if (WITH_RUST) add_subdirectory(cmake/corrosion) - if (${CMAKE_BUILD_TYPE} STREQUAL "Debug") + if (CMAKE_BUILD_TYPE MATCHES DEBUG) corrosion_import_crate(MANIFEST_PATH Cargo.toml CRATES chewing FEATURES capi test-tracing) else() corrosion_import_crate(MANIFEST_PATH Cargo.toml CRATES chewing FEATURES capi) endif() corrosion_import_crate(MANIFEST_PATH Cargo.toml CRATES chewing-tools) add_compile_definitions(WITH_RUST) + corrosion_set_env_vars(chewing CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}) + if(ENABLE_GCOV) + corrosion_set_env_vars(chewing CARGO_INCREMENTAL=0) + corrosion_add_target_local_rustflags(chewing -Cinstrument-coverage -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort) + endif() endif() # Feature probe @@ -287,8 +297,8 @@ if (BUILD_DLL OR NOT MSVC) $ ) if (WITH_RUST) - corrosion_set_env_vars(chewing CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}) - if (${CMAKE_C_COMPILER_ID} STREQUAL "GNU") + if (${CMAKE_C_COMPILER_ID} STREQUAL "GNU" OR + ${CMAKE_C_COMPILER_ID} STREQUAL "Clang") target_link_options(chewing_shared PRIVATE "-Wl,-version-script,${CMAKE_BINARY_DIR}/symbols.map") target_link_options(chewing_shared PRIVATE "-Wl,--gc-sections") elseif (${CMAKE_C_COMPILER_ID} STREQUAL "AppleClang") diff --git a/xtask/src/cli.rs b/xtask/src/cli.rs index 0a964d6dd..57837765c 100644 --- a/xtask/src/cli.rs +++ b/xtask/src/cli.rs @@ -26,6 +26,10 @@ pub struct CmdBuild { #[argh(option, default = "false")] pub with_hash: bool, + /// instrument binary to generate coverage infomation + #[argh(option, default = "false")] + pub with_coverage: bool, + /// show more information during build #[argh(option, default = "false")] pub verbose: bool, diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 982bd602c..8c4e9f8f9 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -12,6 +12,7 @@ use cli::{Cli, Cmds}; struct BuildOpts { with_rust: bool, with_hash: bool, + with_coverage: bool, verbose: bool, build_type: String, } @@ -28,10 +29,11 @@ impl BuildOpts { // Configure CMake let with_rust: String = format!("-DWITH_RUST={}", self.with_rust); let with_sqlite3: String = format!("-DWITH_SQLITE3={}", !self.with_hash); + let with_coverage: String = format!("-DENABLE_GCOV={}", self.with_coverage); let build_type: String = format!("-DCMAKE_BUILD_TYPE={}", self.build_type); cmd!( sh, - "cmake -B ./build {with_rust} {build_type} {with_sqlite3}" + "cmake -B ./build {with_rust} {build_type} {with_sqlite3} {with_coverage}" ) .run() .with_context(|| "cannot configure cmake")?; @@ -70,6 +72,7 @@ fn main() -> Result<()> { BuildOpts { with_rust: cmd.with_rust, with_hash: cmd.with_hash, + with_coverage: cmd.with_coverage, verbose: cmd.verbose, build_type: cmd.build_type.clone(), }