Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot generate report from Meson's out-of-tree build with GCC's coverage instrumentation #1182

Open
detly opened this issue Jun 6, 2024 · 5 comments

Comments

@detly
Copy link
Contributor

detly commented Jun 6, 2024

I've been trying to use grcov on a C project that uses Meson as a build system and GCC to compile. Meson does out-of-tree builds where binary artifacts are put in a separate build directory eg. build, possibly within the source tree. GCC seems to generate gcno files with a leading ../. I cannot figure out how to tell grcov how to handle this.

Here is an example project, with an example CI job. Note the warnings:

$ ./grcov . --binary-path build --source-dir . --output-path "$GRCOV_REPORT_DIR" --output-types html --ignore-not-existing
Warning: "../one/src/one.c" cannot be normalized because of "..", so skip it.
Warning: "../test_main.c" cannot be normalized because of "..", so skip it.
Warning: "../one/test/test_one.c" cannot be normalized because of "..", so skip it.

I have tried many combinations of the main path argument, --binary-path, --source-dir, --prefix-dir, changing the current directory to build, using absolute paths wherever possible, etc. At best, I can get coverage for the test_main.c file, but never for one/src/one.c.

The example HTML output looks like this:

Screenshot from 2024-06-06 12-42-27

Frustratingly, the cobertura output sometimes contains perfectly valid paths. They are just not present in the HTML output.

It is possible to generate a proper coverage HTML report with gcovr using the following command:

gcovr --root=. --html --output="$COVERAGE_HTML_DIR" .

...so it is possible to use the coverage information generated by Meson and GCC there:

Screenshot from 2024-06-06 12-46-28

Version information:

$ lsb_release -a
Distributor ID:	Debian
Description:	Debian GNU/Linux 12 (bookworm)
Release:	12
Codename:	bookworm
$ ./grcov --version
grcov 0.8.19
$ meson --version
1.4.1

[...]

C compiler for the host machine: cc (gcc 12.2.0 "cc (Debian 12.2.0-14) 12.2.0")
C linker for the host machine: cc ld.bfd 2.40
Host machine cpu family: x86_64
Host machine cpu: x86_64
@detly detly changed the title Support meson's out-of-tree build structure Cannot generate report from Meson's out-of-tree build with GCC's coverage instrumentation Jun 6, 2024
@detly
Copy link
Contributor Author

detly commented Jun 6, 2024

The closest I can get, by the way, is with

grcov . --binary-path build --source-dir . --output-path cov --output-types html --ignore-not-existing --prefix-dir '../'

Then my coverage report looks like:

Screenshot from 2024-06-06 12-54-35

Still no one.c though.

@lu-zero
Copy link
Collaborator

lu-zero commented Jun 6, 2024

If --source-dir is set to build does it resolve correctly?

@detly
Copy link
Contributor Author

detly commented Jun 6, 2024

If --source-dir is set to build does it resolve correctly?

Nope, it's completely empty, like in the first screenshot.

@detly
Copy link
Contributor Author

detly commented Jun 6, 2024

I am starting to think it's an issue with the HTML renderer and not the input handling. Here's Cobertura output from the following command:

grcov . --binary-path build --source-dir . --output-path cov.xml --output-types cobertura --ignore-not-existing --prefix-dir '../'
<?xml version="1.0"?>
<!DOCTYPE  coverage SYSTEM 'http://cobertura.sourceforge.net/xml/coverage-04.dtd'>
<coverage lines-covered="14" lines-valid="14" line-rate="1" branches-covered="0" branches-valid="0" branch-rate="0" complexity="0" version="1.9" timestamp="1717653619">
    <sources>
        <source>/home/jason/Code/meson-grcov</source>
    </sources>
    <packages>
        <package name="one/src/one.c" line-rate="1" branch-rate="0" complexity="0">
            <classes>
                <class name="one" filename="one/src/one.c" line-rate="1" branch-rate="0" complexity="0">
                    <methods>
                        <method name="one" signature="" line-rate="1" branch-rate="0" complexity="0">
                            <lines>
                                <line number="3" hits="1">
                                </line>
                                <line number="5" hits="1">
                                </line>
                            </lines>
                        </method>
                    </methods>
                    <lines>
                        <line number="3" hits="1">
                        </line>
                        <line number="5" hits="1">
                        </line>
                    </lines>
                </class>
            </classes>
        </package>
        <package name="one/test/test_one.c" line-rate="1" branch-rate="0" complexity="0">
            <classes>
                <class name="test_one" filename="one/test/test_one.c" line-rate="1" branch-rate="0" complexity="0">
                    <methods>
                        <method name="test_one_a" signature="" line-rate="1" branch-rate="0" complexity="0">
                            <lines>
                                <line number="6" hits="1">
                                </line>
                                <line number="8" hits="1">
                                </line>
                                <line number="9" hits="1">
                                </line>
                                <line number="10" hits="1">
                                </line>
                                <line number="11" hits="1">
                                </line>
                                <line number="12" hits="1">
                                </line>
                            </lines>
                        </method>
                        <method name="test_one" signature="" line-rate="1" branch-rate="0" complexity="0">
                            <lines>
                                <line number="14" hits="1">
                                </line>
                                <line number="16" hits="1">
                                </line>
                                <line number="17" hits="1">
                                </line>
                            </lines>
                        </method>
                    </methods>
                    <lines>
                        <line number="6" hits="1">
                        </line>
                        <line number="8" hits="1">
                        </line>
                        <line number="9" hits="1">
                        </line>
                        <line number="10" hits="1">
                        </line>
                        <line number="11" hits="1">
                        </line>
                        <line number="12" hits="1">
                        </line>
                        <line number="14" hits="1">
                        </line>
                        <line number="16" hits="1">
                        </line>
                        <line number="17" hits="1">
                        </line>
                    </lines>
                </class>
            </classes>
        </package>
        <package name="test_main.c" line-rate="1" branch-rate="0" complexity="0">
            <classes>
                <class name="test_main" filename="test_main.c" line-rate="1" branch-rate="0" complexity="0">
                    <methods>
                        <method name="main" signature="" line-rate="1" branch-rate="0" complexity="0">
                            <lines>
                                <line number="3" hits="1">
                                </line>
                                <line number="5" hits="1">
                                </line>
                                <line number="6" hits="1">
                                </line>
                            </lines>
                        </method>
                    </methods>
                    <lines>
                        <line number="3" hits="1">
                        </line>
                        <line number="5" hits="1">
                        </line>
                        <line number="6" hits="1">
                        </line>
                    </lines>
                </class>
            </classes>
        </package>
    </packages>
</coverage>

All of the appropriate paths are present, and can be joined up to perfectly match the source tree. Why aren't they in the HTML output though?

@detly
Copy link
Contributor Author

detly commented Jun 6, 2024

I thought I'd try to work around this by using gcovr to generate lcov data, and consume that with grcov:

$ gcovr --root=. --lcov cov.info --lcov-test-name gcovr
(INFO) Reading coverage data...
(INFO) Writing coverage report...
$ lcov -l cov.info
                           |Lines       |Functions  |Branches    
Filename                   |Rate     Num|Rate    Num|Rate     Num
=================================================================
[/home/jason/Code/meson-grcov/]
one/src/one.c              |50.0%      2| 0.0%     1|    -      0
one/test/test_one.c        |22.2%      9| 0.0%     2|    -      0
test_main.c                |33.3%      3| 0.0%     1|    -      0
=================================================================
                     Total:|28.6%     14| 0.0%     4|    -      0
$ grcov cov.info --binary-path build --source-dir . --output-path cov --output-types html --ignore-not-existing

I still have the missing paths, but now I also have extremely suspicious line hit counts:

Screenshot from 2024-06-06 15-13-19

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants