NAME

Devel::XSCover::Gcov - the counters the compiler wrote, read through gcov

SYNOPSIS

use Devel::XSCover::Gcov;
my $reader  = Devel::XSCover::Gcov->new(dir => '.', gcov => ['gcov']);
my @objects = $reader->read;

DESCRIPTION

Finds every counter file the instrumented objects wrote, runs gcov on each from the distribution directory, and parses its text into one structure per object that knows nothing of Devel::Cover: the executable lines with their counts, the functions with their first line and call count, and the blocks that end in a jump with the count of each arm.

METHODS

new

my $reader = Devel::XSCover::Gcov->new(%options);

Options: dir, gcov (the tool as a list of words), conditions (ask gcov for condition coverage, gcc 14 and later), ignore (patterns on the relative path), generated (the generated C files to keep aside), skip (directories not searched, blib, cover_db and .git by default), save (a directory to keep each object's gcov text in), dry and silent.

find_gcda

Every .gcda under the directory, relative to it, sorted.

run_gcov

my $text = $reader->run_gcov('src/helper.gcda');

Runs the tool from the distribution directory with -abct and the counter file, and returns the text. The source paths gcov records are relative to the directory the object was compiled in, so it must run there.

parse

my $files = $reader->parse($text);

The structure, keyed by source file as gcov names it:

{ 'Spike.xs' => {
    lines     => { 27 => 353062, 37 => 1 },
    functions => [ { name => 'only_from_one', line => 8, count => 2 } ],
    blocks    => [ { line => 36, arms => [2, 1] }, { line => 47, arms => [1, 1, 1, 0, 1] } ],
    conditions => [ { line => 36, covered => 3, total => 4, terms => [ { true => 1, false => 1 }, { true => 1, false => 0 } ] } ],
} }

A count of - is not an executable line. ##### and ===== are zero, a trailing * is dropped. A function's line is the first source line after its summary. A block's arms are the branch lines after it, a never executed arm counting zero, and blocks without arms are dropped. Branch lines without a block of their own make one block for the line. A condition outcomes covered N/M line, which gcc 14's gcov --conditions writes under a line, is a decision of M/2 terms, and the condition K not covered (true) lines after it say which outcome of which term never decided the result. Each term ends up with a true and a false flag.

filter

my ($kept, $aside) = $reader->filter($files);

Drops every file outside the distribution directory, ppport.h, and files matching an ignore pattern. Files in generated are returned apart, as the second value, for the XS map. Absolute paths under the directory become relative.

read

Runs the three steps for every counter file and returns a list of hashes with object (the counter file), files and generated.

SEE ALSO

Devel::XSCover