1.9. External source annotations
In case modifying the sources is not possible or desirable, it is possible to generate annotations in separate files, which can be passed to gnatcov instrument or gnatcov coverage to modify the behavior of the instrumenter or of the coverage analysis.
Annotations loaded from an external file can be used along in-source annotations, however in case of conflicts, the annotations defined in the sources will always be prioritized.
External annotations are stored in TOML files, which can be manipulated through three gnatcov commands, gnatcov add-annotation, gnatcov delete-annotation and gnatcov show-annotations, to respectively add a new annotations, delete an existing annotation from the files, or show the annotations that are stored in the files.
Once generated, annotation files should be passed to the gnatcov instrument or gnatcov coverage
commands with the --external-annotations
switch for them to be
taken into account by gnatcov.
1.9.1. Generating external annotations
The gnatcov add-annotation command can be used to create an annotation, tied to a specific source location.
The help section for the gnatcov add-annotation command can be displayed by running
gnatcov add-annotation --help
. Its synopsis is:
gnatcov add-annotation --kind=KIND [--external-annotations=FILENAME] --output=OUTPUT_FILENAME [OPTIONS] FILENAME
Some notable command line options are:
--output
Name of the file to the newly created annotation will be written. If there already is a file, it will be overwritten.
--external-annotations
, possibly repeated and accepting @listfile argumentsLoads pre-existing annotations from FILENAME. They are used to check that the new annotation does not conflict with any pre-existing one. The loaded annotations are all written to the output file specified through
--output
.FILENAME
, positionalFilename to which the new annotation should apply. There are special considerations to keep in mind when specifying the name of the file to be annotated, see File relocation considerations
--annotation-id=IDENTIFIER
, optionalUnique identifier for the new annotation. If not specified, gnatcov will generate one based on the kind of annotation and the designated location.
This identifier must be unique across all external annotation files passed to any gnatcov invocation, and is used in diagnostics, or in the other annotation manipulation commands, gnatcov delete-annotation and gnatcov show-annotations to uniquely designate an annotation.
--force
, optionalForce overwriting of a pre-existing annotation for the same location, or with the same identifier. If not specified, gnatcov will emit an error and abort the annotation generation. The output file will not be modified.
The required command line switches depend on the value of the
--kind
, conveying the kind annotation to be generated, which
correspond to the annotations kinds supported in
pragma Annotate (Xcov, KIND, ..)
. The required switches are detailed in the
help text for the gnatcov add-annotation command, and are detailed bellow. A switch in
brackets signifies that the switch is optional, otherwise the switch is required
and gnatcov add-annotation will emit an error if not found on the command line.
--kind=Exempt_On
Generate an annotation symbolizing the beginning of an exempted region.
--location=LINE:COL
Source location for the beginning of the exempted region.
--justification=MESSAGE
Justification message to be displayed in the coverage reports for the exempted region.
--kind=Exempt_Off
Generate an annotation symbolizing the end of an exempted region.
--location=LINE:COL
Source location for the end of the exempted region.
--kind=Exempt_Region
Generate an annotation symbolizing an entire exempted region.
--start-location=LINE:COL
Source location for the beginning of the exempted region.
--end-location=LINE:COL
Source location for the end of the exempted region.
--justification=MESSAGE
Justification message to be displayed in the coverage reports for the exempted region.
--kind=Cov_Off
Generate an annotation symbolizing the beginning of a disabled coverage region.
--location=LINE:COL
Source location for the beginning of the disabled coverage region.
--justification=MESSAGE
Justification message for the disabled coverage region, to be displayed in the coverage reports.
--kind=Cov_On
Generate an annotation symbolizing the end of a disabled coverage region.
--location=LINE:COL
Location for the end of the disabled coverage region.
--kind=Dump_Buffers
Generate an annotation instructing gnatcov to insert a buffer dump procedure call at the specified location. This is only taken into account when the selected dump trigger is
manual
, see Output strategies for main units for more information concerning the dump triggers.--location=LINE:COL
Source location at which the buffer dump procedure call should be inserted.
[--dump-filename-prefix=TEXT]
Optional trace filename prefix to be passed to the buffer dump procedure call. This will be textually passed as argument to the buffer dump, and must be an expression evaluating to a null-terminated
char *
. As such, if the prefix to be used is a literal string, the argument passed to--dump-filename-prefix
must contain quotes (e.g.--dump-filename-prefix='"my_trace"'
).[--annotate-after]
If specified, instruct gnatcov to insert the buffer dump procedure after the statement designated by the annotation. See Semantics of buffer manipulation annotations for more details on the meaning of this option.
--kind=Reset_Buffers
Generate an annotation instructing gnatcov to insert a coverage buffer reset procedure call at the specified location. This is only taken into account when the selected dump trigger is
manual
, see Output strategies for main units for more information concerning the dump triggers.--location=LINE:COL
Location at which the buffer reset procedure call should be inserted.
[--annotate-after]
If specified, instruct gnatcov to insert the buffer reset procedure after the statement designated by the annotation. See Semantics of buffer manipulation annotations for more details on the meaning of this option.
1.9.1.1. Semantics of buffer manipulation annotations
Due to the differences in instrumentation technology used by gnatcov for C/C++ and Ada, the external annotations concerning buffer dump/reset have different semantics that need to be taken into account when first annotation sources.
For C and C++ sources, gnatcov will insert the buffer dump/reset call at the exact location designated by the annotation, without validating if the resulting code is legal. It is thus recommended to choose a location corresponding to a whitespace character, immediately before or after a statement.
For instance, starting from the following source file:
1int main(){
2 // Execute the core program
3 do_stuff();
4
5 // Cleanup temp files
6 cleanup();
7}
Creating an annotation as follows:
gnatcov add-annotation --kind=Dump_Buffers -o annotations.toml --location=6:3 main.c
would result in the following invalid code to be generated:
1int main(){
2 //Execute the core program
3 do_stuff();
4
5 // Cleanup temp files
6 cgnatcov_dump_buffers();leanup();
7}
Instead, it is better to target any whitespace character before the statement,
as in --location=6:2
.
For Ada sources, gnatcov will locate the inner-most statement list that encloses
the designated location, and insert the procedure call immediately before
this statement by default. The --annotate-after
switch can be used to
instruct gnatcov to instead insert the procedure call after the designated
statement. This in particular is necessary to add a buffer dump annotation after
the last statement of a list.
If gnatcov cannot locate a statement list enclosing the designated location, a warning will be emitted and the annotations will be ignored.
For instance, starting from the following source file:
1procedure Main is
2begin
3 -- Run the actual program
4
5 Do_Processing;
6
7 -- Cleanup temp files
8
9 Do_Cleanup;
10end Main;
Generating an annotation with:
gnatcov add-annotation --kind=Dump_Buffers -o annotations.toml --location=9:15 main.adb
results in the following source, despite the source location pointing at the end of the Do_Cleanup procedure call:
1procedure Main is
2begin
3 -- Run the actual program
4
5 Do_Processing;
6
7 -- Cleanup temp files
8
9 GNATCov_RTS_Dump_Buffers; Do_Cleanup;
10end Main;
To ensure the buffer dump procedure is inserted after the Do_Cleanup call, it is
necessary to pass the --annotate-after
command line switch.
1.9.1.2. File relocation considerations
The external file annotation mechanism stores the filename passed to the gnatcov add-annotation command in the generated annotation file. When the annotations are loaded by a gnatcov instrument or gnatcov coverage command invocation, to determine if an annotation is relevant for any of the processed files, gnatcov checks whether the full filename of the file being processed ends with the annotation target filename. It is thus important to only store in the annotation the part of the filename that will not change between the different gnatcov command invocations.
This means that relative paths components (e.g. ./
or ../
), and absolute
paths are likely to not be properly recognized.
The gnatcov add-annotation command accepts a --source-root=PREFIX
option that will strip
PREFIX
from the target filename when generating the annotations. As such, it
is possible to generate an annotation for a file located in a parent directory,
while ensuring the generated annotation will correctly be taken into account in
subsequent gnatcov invocations with the following command line:
gnatcov add-annotation [OPTIONS] --source-root="../" ../src/file.adb
gnatcov can also automatically deduce the appropriate prefix to be stripped from
the filename if a project file is passed to gnatcov add-annotation with the -P
option.
Note that this only works if the file is unique in the project tree, or if the
file is located in a sub-directory of its project root directory.
1.9.2. Deleting a pre-existing annotation
The gnatcov delete-annotation command can be used to remove a pre-existing annotation from an external annotation file.
The help section for the gnatcov add-annotation command can be displayed by running
gnatcov delete-annotation --help
. Its synopsis is:
gnatcov delete-annotation --external-annotations=FILENAME --output=OUTPUT_FILENAME --annotation-id=IDENTIFIER
The semantics of each command line switch is:
--annotation-id=IDENTIFIER
:Unique IDENTIFIER of the annotation to be deleted.``
--external-annotations=FILENAME
, possibly repeated and accepting @listfile arguments:External annotation files from which the annotation will be loaded. If multiple files are passed to gnatcov, the annotations will be consolidated together and all written to the output file.
--output=OUTPUT_FILENAME
:Name of the file where the annotations will be written back after deletion of the designated annotation. This will overwrite any pre-existing file with the same OUTPUT_FILENAME.
1.9.3. Displaying the annotations contained in annotation files
The command gnatcov show-annotations can be used to display the annotations contained in annotation files in a more user-friendly manner.
The help section for the gnatcov add-annotation command can be displayed by running
gnatcov show-annotations --help
. Its synopsis is:
gnatcov show-annotations --external-annotations=FILENAME [--kind=KIND] [-P PROJECT] [FILENAMES]
The semantics of the command line switches are as follow:
--external-annotations=FILENAME
, possibly repeated and accepting @listfile arguments:External annotation files from which annotations will be loaded
--kind=KIND
, optional:Only display the annotations of kind KIND.
-P PROJECT
, optional:Show all annotations applicable to all source files of the project tree rooted at PROJECT.
FILENAMES
, positional:Only show the annotations applicable to the listed files.
Either the -P
command line option or positional filenames must be specified.
The output format is as follows:
BASENAME_1:
- START_LOCATION - END_LOCATION; id: IDENTIFIER; kind: KIND; [EXTRA_FIELDS]
- ...
BASENAME_2:
- ...
BASENAME_i
corresponds to the basename of each file for which there is an
annotation. The each annotation is displayed on each line, starting by the
location range for the annotation. If the annotation only concerns a single
location, the END_LOCATION
field will be identical to the
START_LOCATION
. The unique identifier of the annotation is then displayed in
place of IDENTIFIER
, and the annotation kind is displayed in place of
KIND
. The EXTRA_FIELDS
concerns options specific to each annotation
kind, and are displayed as a semi-column separated list. See Generating external annotations for
more details on the extra fields that each annotation kind supports.
1.9.4. Annotation stability through file modifications
The external annotations generated by the gnatcov add-annotation command embed varying levels of information so that the source location designated on the command line option can be remapped when possible, or invalidated otherwise.
This depends mainly on the language of the file to be annotated:
For Ada sources, the annotation is tied to the inner-most enclosing named construct, such as a subprogram or a package. If the file is modified outside of that construct the annotation will be remapped properly. If the enclosing construct is modified, the annotation will be invalidated.
For C sources, the annotations are currently not stable through modifications. Any modification to the annotated source file will invalidate the annotations.
If an annotation is invalidated gnatcov will emit a warning stating that the annotation was ignored, along with its unique identifier.
The output of the gnatcov show-annotations command will also display stale annotations, the format for those annotations will be:
- STALE ANNOTATION; id: IDENTIFIER; kind: KIND; [EXTRA_FIELDS]; diagnostic: DIAGNOSTIC
where DIAGNOSTIC
will contain a short explanation of why the entry is stale.
To fix this, simply replace the entry with an invocation of gnatcov add-annotation, specifying the annotation identifier to be replaced, and forcing the replacement:
gnatcov add-annotation --annotation-id=IDENTIFIER --force [OPTIONS]