HTML2LCOV(1)
πΈ NAME πΈ
This is html2lcov(1) from the LCOV manual β manual section 1, manual group LCOV Tools. The docs say html2lcov is html2lcov documentation, and bestie, it's here to recover lcov .info coverage data and a source diff from an HTML report. That's the whole assignment. π
β¨ SYNOPSIS β¨
html2lcov [--output filename] [--source-directory dir]+ [--current-file file]+ [options] report_directory+
π DESCRIPTION π
Okay so html2lcov screen-scrapes a genhtml-generated HTML coverage report to recover these two things:
- The LCOV
.infocoverage data that was used to produce the report.genhtmlcopies its input.infofiles into the top level of the report directory when it is run with--save;html2lcovfinds and aggregates those files, using the same layout definition thatgenhtml --saveuses to write them (so the reader and writer cannot drift). It is an error if the report does not contain any such.infofile. π¨ - The source code that was embedded in the per-file HTML pages. This is compared against the source found under
--source-directoryto produce a universal diff and a human-readable difference report. Note thathtml2lcovneeds to see all of the original source code: the input HTML report must not be a subset report containing only part of the source code (i.e., not a report generated using a--select-scriptcallback). No half-report shenanigans, bestie. π
The source directory may contain new files that were not in the report, and may omit files that were in the report; these differences are documented in the difference report rather than being treated as errors. It is an error if the source directory contains no file that matches any file in the report. So like, zero matches = nope. π
Because genhtml expands tabs and normalizes some whitespace when it renders source into HTML, the comparison is run with diff -b, which ignores differences in the amount of whitespace (a tab and any run of spaces compare equal), so re-indented or tab-vs-space-only changes do not appear as spurious differences. Slay for not being fake-dramatic about indentation. β¨
π¦ USE CASES π¦
The common use case for html2lcov is when the user has code and/or test changes in their sandbox, has a coverage report from earlier in the day, and now wants to see whether subsequent changes are adequately tested. Unfortunately: the user isnβt entirely sure what the code looked like when the report was generated β and does not have a corresponding label. In that case: file diffs and baseline coverage data can be extracted from the report, and then used as the genhtml --diff-file and --baseline-file inputs. Iconic little rescue mission, honestly. π«Ά
Another common case is when some or all of the source code is generated and not under revision control β but the user wants to verify that it is properly tested after configuration and/or generator changes. Very "trust me, the generator made it, now prove it's tested" energy. π
π OPTIONS π
html2lcov supports the options that are common to the other tools in the LCOV suite, and honours the corresponding lcovrc(5) settings. In particular:
- file selection and path manipulation:
--include,--exclude,--erase-functions,--substitute,--filter,--omit-lines,--demangle-cpp. These apply to the coverage data recovered from the report exactly as they do when the same data is read bylcovβ so a file which is excluded is also absent from the universal diff and from the difference report. Exclusion goes hard, no cap. π« - parallelism and resource limits:
--parallel(-j),--memory,--tempdir,--preserve.html2lcovforks children both to read the reportβs saved.infofile(s) and to scrape and diff the reportβs source pages, so--parallelspeeds up both phases of a large report; see PARALLELISM. Multi-core moment. π₯ - message control and diagnostics:
--ignore-errors,--keep-going,--expect-message-count,--msg-log,--quiet,--verbose,--debug. - configuration and provenance:
--config-file,--rc,--comment,--version,--help.
The tool-specific options are:
--outputfilename,-ofilename β Name a base for the output files. Any extension is stripped from filename to formbase, and each artifact then appends its own extension: the aggregated coverage is written tobase.info, the human-readable difference report tobase.rpt, the universal diff tobase.udiff(unless--diff-fileredirects it), and the profile (if--profileis used) tobase.json. When--outputis omittedbaseishtml2lcovand the universal diff is written to standard output. Cute little naming system, tbh. π--source-directorydir β Search dir for the current source files to diff against the reportβs embedded source. May be used more than once. Files are matched by their path relative to the reportβs recovered source root. When--source-directoryis not specified it defaults to.(the current directory). Bestie, it's literally right there. π--current-filefilename β Anlcov.infofile whoseSF:records name the current source files. May be specified more than once, and each value may itself be a list separated by the configured list separator (seelcovrc(5)).
When any --current-file is given, its union of SF: paths becomes an authoritative whitelist of the current source files:
- Only files named in a
SF:record may appear in the universal diff (as changed or added). Every other file found under--source-directoryis ignored. - A file present in the report (baseline) but not in the current set is treated as removed.
- A file present in the current set but not in the report is treated as added.
html2lcov uses the .info only as a file list; its coverage data is not merged into any output. The expected workflow is to feed the html2lcov universal diff to genhtml --diff-file and the aggregated .info output to genhtml --baseline-file, using this same --current-file .info as the genhtml current input. Workflow slay. π
A current SF: path is matched to a report file when it equals either the report fileβs recovered path or its report-root-relative path (after any --substitute rules are applied); relative and absolute path styles are preserved on output. If a file appears in both sets under names that differ only in path (a shared basename or path tail), html2lcov emits an ignorable mismatch warning. Use --substitute (or an external tool such as sed(1)) to reconcile path differences the tool cannot resolve on its own. Path drama is real, but manageable. π
If a SF: path names a file that cannot be read from disk under --source-directory, html2lcov reports an ignorable source error; when that error is ignored, the file is dropped from the universal diff and its record is removed from the aggregated .info output.
A missing --current-file is a fatal error; an empty file raises an ignorable empty error; a non-empty file that contains no SF: record is not an LCOV file and is a fatal error. So like, don't hand it a random file and call it a day. π¨
--diff-filefilename β Write the universal diff to filename instead of the defaultbase.udiff(or standard output when--outputis omitted). Redirect that diff, bestie. π--profile[filename] β Write timing and statistics data as JSON to filename (default isbase.json). Stats girlies stay winning. π
See lcov(1) and lcovrc(5) for details of other supported options and configuration settings. iykyk. β¨
π OUTPUTS π
html2lcov produces up to four distinct artifacts:
- universal diff (
base.udiff) β written tobase.udiff, or to standard output when--outputis omitted;--diff-fileredirects it elsewhere. Standarddiff -uformat, so it can be consumed bygenhtml --diff. Files only under--source-directoryappear as additions (versus/dev/null); files only in the report appear as removals. May be empty when there are no code changes. For a changed file both diff headers (---and+++) name the same path β the source path recovered from the report, which is exactly theSF:record in the aggregated.infoβ sogenhtmlcan associate the diff with the recovered baseline coverage. Matching headers = the pipeline understands each other. π₯ - aggregated coverage (
base.info) β the current coverage recovered from the reportβs saved.infofile(s). The main character artifact, honestly. π - difference report (
base.rpt) β a human-readable table listing every changed, added, removed, and unchanged file, with added/deleted line counts. Receipts in table form. π§Ύ - profile (
base.json) β timing/statistics data, when--profileis used.
π₯ PARALLELISM π₯
Both of the expensive phases of html2lcov are parallelized, and both are governed by --parallel (-j) and --memory:
- reading the
.infofile(s) saved in the report β the same parallel parse thatlcov --add-tracefileuses. - scraping the source out of the reportβs HTML pages and diffing it against
--source-directory. Each child scrapes and diffs a group of files and returns only the classification and the udiff text, so the recovered source never accumulates in the parent. Files are grouped by the size of the HTML page each is scraped from, so that the groups cost roughly the same; a report with only a handful of files is processed in this process rather than paying for a fork. Smart grouping, no wasted forks. π§
The output does not depend on --parallel: the .info, .udiff and .rpt artifacts are identical for any value. So you can crank the parallel knob and the receipts stay the same. Periodt. π
π EXAMPLES π
Recover coverage and diff current source against a saved report:
# Generate coverage and an HTML report, saving the input .info files
$ lcov --capture -d . -o cov.info
$ genhtml cov.info --save -o html_report
# make code and/or test changes
...
# capture new coverage data
$ lcov --capture -d . -o current.info
# Recover the .info data and diff the current source tree
$ html2lcov -o changes html_report --source-directory ./src --current-file current.info
# 'changes.udiff' is the universal diff (diff -u format)
# 'changes.info' is the recovered coverage data
# 'changes.rpt' is the human-readable difference report
# now generate a differential report - to see what has changed:
$ genhtml -o differential --baseline-file changes.info --diff-file changes.udiff current.info
Also see the example_html2lcov in the example directory |ToolName|_HOME/share/lcov/example:
$ cd |ToolName|_HOME/share/lcov/example
$ make example_html2lcov
πΈ NOTES πΈ
Okay bestie, this part is important, so pay attention. π
Coverage literally cannot be recovered from a report that was built without --save, because the .info files just aren't there in the report directory. Like, they're not hiding, they're not in the group chat, they're gone. π And html2lcov treats this as a full-on error rather than attempting a lossy scrape of the coverage counts from the HTML. No sketchy workarounds here β she said no cap or nothing. π«
Now for the second vibe check: if the source under --source-directory is identical to the source embedded in the report, there are no differences to emit. That's not a bug, bestie, that's a normal, expected outcome β for example, when the current source has not changed since the report was built. β¨ So html2lcov reports it as a non-fatal empty warning (No source code differences found) and still exits successfully. Slay, she's being gentle. π«Ά
Want her to fully stop talking about it? Use --ignore-errors empty to suppress the warning entirely. Peace and quiet, periodt. π€«
π AUTHOR π
Henry Cox <henry.cox@mediatek.com>
(Yes, a real human made this. Give him his flowers. π)
π¦ SEE ALSO π¦
lcov(1) <file://../man/lcov.1.html>genhtml(1) <file://../man/genhtml.1.html>geninfo(1) <file://../man/geninfo.1.html>lcovrc(5) <file://../man/lcovrc.5.html>
Go read the whole friend group, iykyk. πβ¨
π Copyright π
2024-2026, LCOV Project
And that's the whole page, bestie β this is HTML2LCOV(1) from LCOV version 2.6, dated 2026-10-03. Bookmark it, screenshot it, send it to the group chat, whatever you gotta do. π
β¨
π¦ where this page comes from
- arch rolling: lcov 2.6-1 Β· GPL
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms