JACOCO2LCOV(1)

πŸ“¦ version 2.6, in arch rolling

πŸ’… JACOCO2LCOV β€” the jacoco2lcov manual, bestie edition πŸŽ€

okay so this is jacoco2lcov(1), manual section 1, manual group LCOV Tools, and we're translating JaCoCo execution data to lcov format. buckle up, it's giving documentation but make it cute ✨

✨ NAME ✨

jacoco2lcov β€” translate JaCoCo execution data to lcov format πŸ¦‹

🌸 SYNOPSIS 🌸

jacoco2lcov [--output mydata.info] [options] execfile+

πŸ’– DESCRIPTION πŸ’–

jacoco2lcov takes the execution data that JaCoCo collected while your Java tests were out there doing their thing and translates it into LCOV .info format. iconic behavior, honestly πŸ‘‘

And the tea is: it does none of the translation itself. it's a wrapper, a little main-character middleman that runs, in order, the two commands you'd otherwise be running by hand 😭

  • java -jar jacococli.jar report ... --xml tmp.xml β€” this one turns the .exec execution data files into a JaCoCo XML report, and
  • xml2lcov --format jacoco ... tmp.xml β€” this one translates that report into LCOV .info format

...and then jacoco2lcov reads the LCOV format .info file that xml2lcov generated, applies the common LCOV options β€” filtering, exclusions, etc. β€” and writes the result to the output file. no cap, the data is read and written by the same code every other tool in the suite uses, so jacoco2lcov supports every common option β€” see OPTIONS, babe πŸ’…

The intermediate files are temporary and get yeeted when jacoco2lcov finishes, so don't go looking for them. use --xml if you want to keep the XML report 🫢

Either of the two steps can be run independently if you want or need to β€” say, because you need additional options or flags that are not supported by the script. do your thing, queen ✨

🧚 What JaCoCo needs to be told 🧚

A JaCoCo .exec file holds execution data but not the names of the classes it refers to or their source. so like. it's giving mysterious. thus, at least one class location has to be named, with --classpath: JaCoCo reads the coverage counts out of the class files, and cannot write a report without them. and at least one source directory has to be named as well, with --source-directory, because a JaCoCo report names no search path of its own and xml2lcov has to find the sources to translate them. --plugin-directory is a shorthand for both when your code is laid out in the usual Eclipse or Maven way 🌈

With none of --classpath, --source-directory and --plugin-directory given, the current directory is searched as --plugin-directory . would search it. that finds the source and class directories of a project laid out either of those ways β€” src/main/java and target/classes for Maven, src and bin for Eclipse β€” and of a directory holding several such projects, in which case each of them contributes the directories it has. jacoco2lcov says so when it does this, and stops if it finds nothing: a layout it does not recognize, or classes somewhere else your build put them, still has to be named. it is a convenience for the usual case, not a search: nothing is looked for outside the conventional places, and nothing is guessed from file extensions πŸ™ˆ

πŸ’€ Coverage types πŸ’€

JaCoCo data always contains branch and function coverage β€” so jacoco2lcov enables both of them by default. slay. use command line and/or config file options to change this behaviour, if desired πŸ’…

There is no MC/DC or condition coverage to write: JaCoCo does not collect it. not me finding out the hard way 😭

πŸŽ€ Source versions πŸŽ€

A JaCoCo report does not say which version of the source it describes, so there is no version in the data to carry through β€” unlike a lcov --capture, which records the version of each file it finds. --version-script therefore means "compute the version", and jacoco2lcov turns compute_file_version on for you when you name one: the callback is applied to each file as the translated data is read back in, and the VER: records it returns are written to the output. say --rc compute_file_version=0 if you want the callback used for nothing but comparisons πŸ‘‘

Without a version script there is no version to record, and a report generated from the result has nothing to check the source it reads against β€” so genhtml(1) will stop with a version error if it is asked to compute versions itself. lowkey tragic but that's the vibe check πŸ’€

πŸ¦‹ Consistency πŸ¦‹

JaCoCo counts instructions and branches rather than executions, so the execution counts in the translated data are derived, and LCOV may consider the result internally inconsistent β€” most often because JaCoCo reports a line as covered whose branches it never saw evaluated. see the JaCoCo conversion notes section of xml2lcov(1) for why the derived data appears as it does. if you need to work around the inconsistent error which is reported, either exclude the offending code or add --ignore-errors inconsistent to your command line 🫢

The same inconsistent error is generated when a function is marked "not executed" but contains a line which is covered β€” for example, function 'com.example.Widget.dead()V' is not hit but line 8 is. a JaCoCo method contains a 'begin' line but no information about where it ends β€” so the range of lines contained within the function is derived from the line data and source text. this can erroneously claim a line belonging to another method 😭 the message can be suppressed via --ignore-errors inconsistent. see the JaCoCo conversion notes section of xml2lcov(1).

🌸 Merging 🌸

If you have execution data from more than one test run, hand all of the .exec files to a single jacoco2lcov command rather than translating each of them and merging the results with lcov -a: JaCoCo can combine per-branch data exactly and the translated data cannot. fr fr, trust. see Merging JaCoCo data in xml2lcov(1) πŸ’œ


✨ OPTIONS ✨

In addition to the common options supported by the other tools in the LCOV suite (e.g., --exclude, --include, --filter, --substitute, --omit-lines, --erase-functions, --ignore-errors, --comment, --version-script, etc.), which are applied to the translated data, the tool options are the ones below πŸ‘‡

Each of them is marked optional or required, and the default of each is given. nothing but the .exec files is required unconditionally: the rest of what jacoco2lcov has to know it can get from the environment or from the layout of the directory it is run in. so flexible, we love her 🌈

  • execfile β€” one or more JaCoCo .exec execution data files, or directories which are searched for .exec files. every argument which is not an option is taken to name execution data, whatever it is called: .exec is a convention and nothing here depends on it. Required πŸ‘‘
  • -o, --output file β€” Optional. specify the output LCOV .info file. default: jacoco2lcov.info in the current directory πŸŽ€
  • -t, --test-name, --testname name β€” Optional. specify the test name for the TN: entry in the LCOV .info file. default: none β€” the TN: entry is empty πŸ™ˆ
  • -d, --root-directory directory β€” Optional. the run directory and root of relative paths to source, class execution data files, and the output file. default: the directory jacoco2lcov was run in πŸ¦‹
  • -c, --classpath, --classfiles path β€” a directory or .jar file containing the class files whose coverage JaCoCo recorded. JaCoCo reads the coverage counts out of the class files, so it cannot write a report without them. Required, unless -p names them or the default search below finds them. may be specified multiple times. default: none πŸ’…
  • -s, --source-directory, --source-dir directory β€” a root directory of your Java sources β€” that is, one of the directories you would pass to javac, such that the name of a package, used as a directory path, names the directory holding that package's sources. Required, unless -p names them or the default search below finds them. may be specified multiple times. default: none 🌸
  • -p, --plugin-directory, --plugin-dir directory β€” Optional. the root of an Eclipse/Maven plugin, or the parent directory of several of them, to be searched for source and class directories in the usual places (src, src/java, src/main/java, src/test/java and bin, classes, target/classes). this is a shorthand for the -s and -c options which such a directory implies. may be specified multiple times. default: with none of -s, -c and -p given, the current directory is searched as -p . would search it β€” see What JaCoCo needs to be told above 🧚
  • --jar jacococli.jar β€” Optional if the environment names the jar, required if it does not. path to the JaCoCo command line jar. default: the jar named by the JACOCOCLI_JAR environment variable, else the one found under the directory named by JACOCO_HOME πŸ“
  • --java executable β€” Optional. the java executable used to run the JaCoCo command line jar. default: $JAVA_HOME/bin/java if that is an executable, else java, found on your PATH ⭐
  • --xml file β€” Optional. write the intermediate JaCoCo XML report to the named file and keep it. default: a temporary file, removed when jacoco2lcov exits πŸ’œ
  • --xml2lcov path β€” Optional. the xml2lcov executable to use. default: the one installed next to jacoco2lcov. on Windows, a wrapper which Windows can run β€” an xml2lcov.bat, say β€” is preferred to the extensionless script beside it πŸͺŸ
  • -v, --verbose β€” Optional. print each command before it is run. default: off β€” only warnings, errors and notices are printed πŸ‘€
  • -k, --keep-going β€” Optional. ignore errors and continue processing. default: off β€” stop at the first error πŸ’€
  • -h, --help β€” print usage information and exit 🫢

🌈 Common options 🌈

Every other option jacoco2lcov accepts is one the rest of the suite accepts, and means here what it means there β€” it is applied to the translated data:

$ jacoco2lcov -o mydata.info -s src -c bin --exclude='*/test/*' \
      --filter branch mytest.exec

See lcov(1) and lcovrc(5) for details of these options and of the configuration settings which also reach them πŸ’–

✨ EXAMPLES ✨

Okay bestie, this is the part where it all comes together πŸ’– real commands, real vibes, copy them and go.

First up: run your tests with the JaCoCo agent attached, so you actually collect coverage:

# run your tests with the JaCoCo agent attached, to collect coverage
$ java -javaagent:jacocoagent.jar=destfile=test1.exec -cp bin MyTest1
$ java -javaagent:jacocoagent.jar=destfile=test2.exec -cp bin MyTest2

Then translate all of that execution data in one single step, iconic behavior honestly:

# translate all of the execution data in one step
$ jacoco2lcov -o mydata.info -s src -c bin test1.exec test2.exec

Same thing, but run from the root of a conventionally laid out project β€” and the way that you don't name any directory at all, the ones the layout implies just get used πŸŽ€

# the same, run from the root of a conventionally laid out project:  with
# no directory named, the ones the layout implies are used
$ jacoco2lcov -o mydata.info test1.exec test2.exec

Same again, but for a directory of Eclipse/Maven plugins β€” this one keeps the intermediate XML report and drops the test sources from the result. Two birds, no cap πŸ¦‹

# the same, for a directory of Eclipse/Maven plugins, keeping the
# intermediate XML report and dropping the test sources from the result
$ jacoco2lcov -o mydata.info -p plugins --xml jacoco.xml \
    --exclude '*/src/test/java/*' test1.exec test2.exec

Now this one's a whole vibe: a build that wrote one .exec file per test below a results directory, translated from the directory that the rest of your coverage data is relative to. Naming that directory is literally what makes the file names in the result line up with it πŸ‘‘

# a build which wrote one .exec file per test below a results directory,
# translated from the directory the rest of your coverage data is
# relative to:  naming that directory is what makes the file names in the
# result line up with it
$ jacoco2lcov -d /work/myproject -o mydata.info -p plugins results

And finally… generate an HTML coverage report πŸ’… Just a heads up though: JaCoCo reports lines as covered whose branches it never saw evaluated, which genhtml considers inconsistent β€” see 'Consistency' above. Hence the extra flag, iykyk:

# and generate an HTML coverage report.  JaCoCo reports lines as covered
# whose branches it never saw evaluated, which genhtml considers
# inconsistent - see 'Consistency' above
$ genhtml -o html_report mydata.info --branch-coverage \
    --ignore-errors inconsistent

🌸 ENVIRONMENT 🌸

The environment variables, aka where it looks when you didn't tell it where to look. Order matters, bestie 🫢

  • JACOCOCLI_JAR β€” the JaCoCo command line jar to run, if --jar does not name one.
  • JACOCO_HOME β€” the root of a JaCoCo installation. It gets searched for lib/jacococli.jar and then jacococli.jar, if neither --jar nor JACOCOCLI_JAR names a jar.
  • JAVA_HOME β€” the root of the Java installation whose bin/java is used to run the JaCoCo command line jar, if --java does not name one.

πŸŽ€ AUTHOR πŸŽ€

Henry Cox <<henry.cox@mediatek.com>> β€” shoutout to the icon who made this ✨


🌈 SEE ALSO 🌈

Go read these too, they're all part of the family:

More lore, if you're obsessed like me:


Copyright 2024-2026, LCOV Project


That's the whole page bestie, you ate it up πŸ’…βœ¨ This is JACOCO2LCOV(1) version 2.6, dated 2026-10-03 β€” go forth and get those coverage numbers, ily 🫢

πŸ“¦ where this page comes from