You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让CMake Ninja生成器将gcno文件放入对应目标目录?

Fix gcno File Placement with CMake + Ninja for Coverage Builds

Okay, let's tackle this issue—you’re exactly right that the root cause is how Make vs. Ninja handles working directories during compilation. Make switches to the target’s specific build directory before running the compiler, so GCC drops .gcno files right where they belong. Ninja runs all commands from the root build directory, which dumps those files in the top level and causes conflicts when you have duplicate source filenames across targets.

Here are the most reliable ways to fix this:

1. Explicitly Set the Profile Output Directory with -fprofile-dir

The simplest and most maintainable fix is to tell GCC exactly where to generate .gcno files using the -fprofile-dir flag, tied to each target’s build directory via CMake generator expressions.

Instead of global compile options, use a target-specific function to ensure coverage settings are applied correctly per project:

function(target_enable_coverage target)
    # Set compile flags for coverage
    target_compile_options(${target} PRIVATE
        "$<$<CONFIG:COVERAGE>:-g;-O0;-ftest-coverage;-fprofile-arcs;-fno-builtin>"
        # Direct gcno files to the target's CMakeFiles directory
        "$<$<CONFIG:COVERAGE>:-fprofile-dir=$<TARGET_FILE_DIR:${target}>/../CMakeFiles/${target}.dir>"
    )
    # Don't forget link flags for coverage
    target_link_options(${target} PRIVATE
        "$<$<CONFIG:COVERAGE>:-ftest-coverage;-fprofile-arcs>"
    )
endfunction()

# Apply to your targets (repeat for each target needing coverage)
target_enable_coverage(libblake2)

This ensures every target’s .gcno files land in its own CMakeFiles/<target>.dir subdirectory, matching the behavior you get with Makefiles.

2. Force Ninja to Compile in the Target’s Build Directory

If you prefer to mimic Make’s working directory behavior directly, you can override CMake’s compile command variables to make Ninja switch to the target’s build directory before running the compiler.

For C projects:

if(CMAKE_GENERATOR STREQUAL "Ninja" AND CMAKE_BUILD_TYPE STREQUAL "COVERAGE")
    set(CMAKE_C_COMPILE_OBJECT
        "cd ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/$<TARGET_NAME>.dir && <CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>"
    )
endif()

For C++ projects, replace CMAKE_C_COMPILE_OBJECT with CMAKE_CXX_COMPILE_OBJECT. The generator expression $<TARGET_NAME> dynamically inserts the target’s name, so this works across all your projects without hardcoding paths.

Why This Works

When using -ftest-coverage without -fprofile-dir, GCC generates .gcno files in the directory where the compiler was executed (the working directory). Make handles this by changing directories first; with either method above, we either explicitly tell GCC where to put the files or make Ninja replicate Make’s directory-switching behavior.

3. Verify the Fix

After applying either solution, rebuild your project with coverage enabled to confirm:

# Clean previous build artifacts
cmake --build . --config COVERAGE --clean-first
# Rebuild with coverage
cmake --build . --config COVERAGE

Check the CMakeFiles/<your-target>.dir subdirectories—your .gcno files should now be there instead of cluttering the root build directory.

内容的提问来源于stack exchange,提问作者Marnix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:28:30