Merge C/C++ Code Coverage Results from Build Variants
R2026bIn many projects, the same source code is compiled with different preprocessor macros to produce different build variants. For instance, a source file might use #if preprocessor directives to select between different code paths depending on the active variant. Each variant activates different branches in the code, so measuring code coverage for one variant alone does not reflect the actual test coverage of the entire source file.
To compute code coverage for a source file that supports multiple variants, you can collect code coverage results for each variant separately and then use the polyspace-code-profiler -merge -operation aggregate-variants command to combine the results into a single overview that accounts for all code paths across all variants.
Example Files
To follow this example, copy the folder <polyspaceroot>\polyspace\examples\doc_pstest\coverage_variants to a writable location. Here, <polyspaceroot> is the Polyspace® installation folder, for example, C:\Program Files\Polyspace\R2026b.
The folder contains these files:
source.c— Source file containing functions to test. The file uses#ifpreprocessor directives to select between two variant-specific code paths (Variant A and Variant B).The source file contains this pattern to define the variants:
#if VARIANT_A /* Variant A: trim high values, nudge low values. */ if (out > 50) { out = out - 5; } else { out = out + 1; } #elif VARIANT_B /* Variant B: bias away from zero. */ if (out >= 0) { out = out + 3; } else { out = out - 3; } #endifsut.h— Header file declaring the functions insource.c.variantA/test.c— xUnit test file for Variant A. When building the test, set the macroVARIANT_Ato 1.variantB/test.c— xUnit test file for Variant B. When building the test, set the macroVARIANT_Bto 1.
The tutorial uses <PSTEST_SOURCE>, <PSTEST_INCLUDE>, and <PSTEST_LIB> as shorthands for files and folders available with a Polyspace
Test™ installation. For the full paths to these files and folders, see Set Up C/C++ Testing and Code Profiling Using Self-Managed Builds.
Collect Coverage for Each Variant
To collect coverage for each variant, instrument, compile, and run the tests for each variant separately. In this example, the GCC compiler (gcc command) is used as the toolchain.
Variant A
Instrument the source file for Variant A and compile it:
polyspace-code-profiler -instrument -instrum-dir instrums_variantA -- gcc -DVARIANT_A=1 -c source.c -I . -o source_variantA.oCompile the test file and the file
pstest.ccontaining Polyspace Test xUnit API definitions (listed as<PSTEST_SOURCE>below):gcc -DVARIANT_A=1 -c variantA/test.c -I . -I <PSTEST_INCLUDE> -o test_variantA.ogcc -c -D PSTEST_RUNTIME_AS_STATIC_LIBRARY=1 <PSTEST_SOURCE> -I <PSTEST_INCLUDE> -o pstest.oLink the object files with the Polyspace Test precompiled library to create the test executable:
gcc source_variantA.o test_variantA.o pstest.o <PSTEST_LIB> -o variantARun the test executable and collect coverage data. In Windows®, enter:
In Linux®, enter:polyspace-code-profiler -run -instrum-dir instrums_variantA -results-dir results_variantA -- variantA.exepolyspace-code-profiler -run -instrum-dir instrums_variantA -results-dir results_variantA -- ./variantA.out
Variant B
Repeat the same steps for Variant B, using -DVARIANT_B=1 instead of -DVARIANT_A=1:
Instrument and compile the source file:
polyspace-code-profiler -instrument -instrum-dir instrums_variantB -- gcc -DVARIANT_B=1 -c source.c -I . -o source_variantB.oCompile the test file:
You have already compiled the filegcc -DVARIANT_B=1 -c variantB/test.c -I . -I <PSTEST_INCLUDE> -o test_variantB.opstest.ccontaining Polyspace Test xUnit API definitions and do not need to compile this file again.Link the test executable:
gcc source_variantB.o test_variantB.o pstest.o <PSTEST_LIB> -o variantBRun the test executable and collect coverage data. In Windows, enter:
In Linux, enter:polyspace-code-profiler -run -instrum-dir instrums_variantB -results-dir results_variantB -- variantB.exepolyspace-code-profiler -run -instrum-dir instrums_variantB -results-dir results_variantB -- ./variantB.out
At this point, you have separate coverage results for each variant in results_variantA and results_variantB. Open each coverage result in the Polyspace Platform user interface and note the percentage coverage.
Aggregate Coverage Results from All Variants
Use the -merge command with the aggregate-variants operation to combine coverage results from the two variants into a single
result:
polyspace-code-profiler -merge -operation aggregate-variants -results-dir mergedResult -results-name merged_variants results_variantA results_variantBThis command:
Reads the
.psproffiles from the two input foldersresults_variantAandresults_variantB.Aggregates the code coverage data from both variants, combining the coverage of variant-specific code paths.
Saves the aggregated result as
merged_variants.psprofin the foldermergedResult.
Open the merged result, merged_variants.psprof, in the Polyspace Platform user interface. You see greater code coverage compared to either of the individual results.
To generate an HTML report from the aggregated results, enter:
polyspace-code-profiler -report -html -report-dir reports mergedResultOpen the HTML report to review the aggregated code coverage across all variants. The aggregated view shows coverage for code paths that are active in Variant A, code paths that are active in Variant B, and the shared code paths that are common to both variants.