1.7.3. Consolidating Coverage for Different Project Build Configurations
Some projects need to provide alternative implementations depending on the context. For instance, when using a GPR file, an external variable may configure a target-specific implementation of an API at build-time (you can learn more about external variables in the GPR Tools User’s Guide, section 2.9.6.3 The function External).
Here is a simple example: the Logging package a means to emit errors or
warnings. A single source file (logging.ads) defines the API to emit these
messages, but two source files (logging__text_io.adb and
logging__gnat_io.adb) implement this API: one relies on the Ada.Text_IO
runtime unit, and the other on the GNAT.IO unit.
-- example.gpr
project Example is
type Logging_Backend_Type is ("text_io", "gnat_io");
Logging_Backend : Logging_Backend_Type := external ("LOGGING_BACKEND");
for Main use ("main.adb");
for Object_Dir use "obj-" & Logging_Backend;
package Naming is
for Body ("logging") use "logging__" & Logging_Backend & ".adb";
end Naming;
end Example;
-- logging.ads
package Logging is
procedure Warn (Message : String);
procedure Error (Message : String);
end Logging;
-- logging__gnat_io.adb
with GNAT.IO; use GNAT.IO;
package body Logging is
procedure Write (Prefix, Message : String) is
begin
Put (Prefix);
Put (Message);
New_Line;
end Write;
procedure Warn (Message : String) is
begin
Write ("warning: ", Message);
end Warn;
procedure Error (Message : String) is
begin
Write ("error: ", Message);
end Error;
end Logging;
-- logging__text_io.adb
with Ada.Text_IO; use Ada.Text_IO;
package body Logging is
procedure Write (Prefix, Message : String) is
begin
Put (Prefix);
Put_Line (Message);
end Write;
procedure Warn (Message : String) is
begin
Write ("warning: ", Message);
end Warn;
procedure Error (Message : String) is
begin
Write ("error: ", Message);
end Error;
end Logging;
with Logging;
-- main.adb
with Logging;
procedure Main is
begin
Logging.Warn ("message");
end Main;
gnatcov allows to compute code coverage for both implementations. They must be instrumented separately so that all source files have a chance of being instrumented:
gnatcov instrument -Pexample --level=stmt -XLOGGING_BACKEND=text_io
gnatcov instrument -Pexample --level=stmt -XLOGGING_BACKEND=gnat_io
Building and running the programs in order to generated source traces is next:
gprbuild -Pexample -XLOGGING_BACKEND=text_io \
--src-subdirs=gnatcov-instr --implicit-with=gnatcov_rts
gprbuild -Pexample -XLOGGING_BACKEND=gnat_io \
--src-subdirs=gnatcov-instr --implicit-with=gnatcov_rts
GNATCOV_TRACE_FILE=main_text_io.srctrace obj-text_io/main
GNATCOV_TRACE_FILE=main_gnat_io.srctrace obj-gnat_io/main
As described in Specifying Units Of Interest, coverage obligations for all the source files
that need to appear in the coverage report must be conveyed to gnatcov
coverage eventually. Since a given set of GPR file loading options (-P,
-X) deals with one implementation at a time, special care must be taken
when generating the coverage report. The two methods of consolidation can be
used
here:
Manually pass the relevant SID files (
--sidswitch) to use all source traces at once (i.e. Consolidation from trace files).Keep using project loading options to load source traces separately and produce checkpoint files (i.e. Consolidation from coverage checkpoints).
In the following sections, we will use the above example to demonstrate consolidation for two variant programs running on the same host, but you can expect the same kind of coverage consolidation even if traces are obtained from execution on different targets. For instance, for a project that targets a bareboard ARM system, with a variant running on a native host for testing purposes:
# Instrument and run the program to run on the ARM system
gnatcov instrument --level=stmt \
-P example.gpr --target=arm-eabi --RTS=light-stm32f4
gprbuild --src-subdirs=gnatcov-instr --implicit-with=gnatcov_rts \
-P example.gpr --target=arm-eabi --RTS=light-stm32f4
# [execute on target and produce onboard.srctrace]
# Instrument and run the program to run on the host system
gnatcov instrument --level=stmt \
-P example.gpr
gprbuild --src-subdirs=gnatcov-instr --implicit-with=gnatcov_rts \
-P example.gpr
GNATCOV_TRACE_FILE=native.srctrace obj/example
# It is then possible to produce a coverage report using either of the two
# methods presented below from onboard.srctrace and native.srctrace.
1.7.3.1. Use SID files to use all source traces at once
In order to make gnatcov coverage aware of all source files referenced in source traces, pass all the relevant SID files (Providing coverage obligation files (--sid)):
gnatcov coverage \
--sid obj-text_io/logging__text_io.sid \
--sid obj-gnat_io/logging__gnat_io.sid \
main*.srctrace \
--level=stmt --annotate=xcov --output-dir=xcov
This yields the expected coverage report, displaying the coverage for the two
alternative implementations of Logging:
cat xcov/logging.ads.xcov
[...]/logging.ads:
no code
no code
Coverage level: stmt
1 .: package Logging is
2 .: procedure Warn (Message : String);
3 .: procedure Error (Message : String);
4 .: end Logging;
cat xcov/logging__text_io.adb.xcov
[...]/logging__text_io.adb:
75% of 4 lines covered
75% statement coverage (3 out of 4)
Coverage level: stmt
1 .: with Ada.Text_IO; use Ada.Text_IO;
2 .: package body Logging is
3 .:
4 .: procedure Write (Prefix, Message : String) is
5 .: begin
6 +: Put (Prefix);
7 +: Put_Line (Message);
8 .: end Write;
9 .:
10 .: procedure Warn (Message : String) is
11 .: begin
12 +: Write ("warning: ", Message);
13 .: end Warn;
14 .:
15 .: procedure Error (Message : String) is
16 .: begin
17 -: Write ("error: ", Message);
18 .: end Error;
19 .: end Logging;
cat xcov/logging__gnat_io.adb.xcov
[...]/logging__gnat_io.adb:
80% of 5 lines covered
80% statement coverage (4 out of 5)
Coverage level: stmt
1 .: with GNAT.IO; use GNAT.IO;
2 .: package body Logging is
3 .:
4 .: procedure Write (Prefix, Message : String) is
5 .: begin
6 +: Put (Prefix);
7 +: Put (Message);
8 +: New_Line;
9 .: end Write;
10 .:
11 .: procedure Warn (Message : String) is
12 .: begin
13 +: Write ("warning: ", Message);
14 .: end Warn;
15 .:
16 .: procedure Error (Message : String) is
17 .: begin
18 -: Write ("error: ", Message);
19 .: end Error;
20 .: end Logging;
1.7.3.2. Use project loading options to load source traces separately
gnatcov coverage must load each source trace with the corresponding set of project
loading options (-P, -X): each time, we create a checkpoint to carry
the corresponding coverage information:
gnatcov coverage -Pexample -XLOGGING_BACKEND=text_io \
main_text_io.srctrace \
--level=stmt --save-checkpoint=text_io.ckpt
gnatcov coverage -Pexample -XLOGGING_BACKEND=gnat_io \
main_gnat_io.srctrace \
--level=stmt --save-checkpoint=gnat_io.ckpt
Now that each source trace was loaded into a checkpoint, it is possible to generate the coverage report from the checkpoints:
gnatcov coverage \
--checkpoint=text_io.ckpt \
--checkpoint=gnat_io.ckpt \
--level=stmt --annotate=xcov --output-dir=xcov
The same as the first method, this yields the expected coverage report,
displaying coverage for the two alternative implementations of Logging: see
the coverage report in the previous section.