Multi-platform application
Principle
Coco has strict checks to detect that the coverage data is coherent with the source code. It is, for example, not possible to import an execution report (.csexe
file) of an earlier project version or to import the coverage information of an old version into a newer instrumentation database (.csmes
file). This prevents some usage errors and the generation of incoherent test metrics.
Coherence analysis includes verifying that every instrumented source file in the project is not modified. This is done during the build and when coverage data are imported or merged. If the C preprocessor produces different files across the build – which can occur when some files are built in debug mode and others in release mode – Coco detects it, adds a suffix like #1
or #2
to the file name, and requires that both versions are tested to achieve full coverage.
It is possible to compile a program on several platforms and then merge the coverage data. This requires that the source code is identical for each build. If that is not the case, Coco refuses to merge.
We use a small example to illustrate how this works. The project consists of only one source file, project.cpp
, and we build it on Microsoft® Windows and Linux™.
On Linux, we compile the project with the command:
$ csg++ /home/me/project.cpp -o project-unix
The project-unix.csmes
file is generated and the tests can be executed and imported as usual into it.
On Windows, we compile the project with the command:
C:\code> cscl C:\Home\me\project.cpp /Feproject-windows.exe
The project-windows.exe.csmes
file is generated.
Merging the coverage information is possible with cmmerge:
$ cmmerge -o project.csmes project-unix.csmes project-windows.exe.csmes
Unfortunately, this operation is not enough because the file project.csmes
will then contain two project.cpp
files:
/home/me/project.cpp
C:\Home\me\project.cpp
It is necessary to tell Coco that both files are the same. To do that, we use cmedit to change two absolute file names to an identical one:
$ cmedit project.csmes --rename="/home/me/,/PRJ/" --rename="C:\Home\me\,/PRJ/" --verbose
These two rules rename the base directories /home/me/
and C:\Home\me\
to /PRJ/
to a single source file: /PRJ/project.cpp
. The coverage information from both platforms can now be merged.
Restrictions
Code generators
In some build processes, code generators are used, like flex
/bison
or, for Qt products, Meta-Object Compiler (moc). Then the code generators need to produce identical source code on each platform to make the editing work.
If this is not the case, cmedit will refuse the renaming operation because it assumes that the project is not produced from the same source code. The solution is then to skip explicitly the files that are automatically generated.
Let's consider the case of moc
. qmake
generates files with the name moc_*.cpp
. The trick could consist of using the switch --force
which skips the renaming operation for files with conflicts:
$ cmedit project.csmes --force --rename="/home/me/,/PRJ/" --rename="C:\Home\me\,/PRJ/" --verbose
As result, all source files are merged together in a directory PRJ
except the moc files on which a conflict is detected. These moc files need then to be covered separately on each platforms.
Platform dependent macros
In general, C macros expand to platform dependent code and should therefore be avoided. If macro expansions are different between the platforms, Coco will create duplicates by appending a #1
or #2
to the source files. Both versions of the sources need then to be covered.
There are some common pitfalls that you need to know to avoid conflicts:
- The
__FILE__
macro can generate unwanted differences because it may contain the absolute source file name. To solve this issue, since this macro is often used in asserts, the easiest solution is simply to work with the release build. Another solution is to ensure that the source file names passed to the compiler are not absolute file names. In this case, on most platforms__FILE__
is not expended to be the source's absolute path. - The
NULL
macro may also be different on each platform. Sometimes it is expanded as(void*)0
and sometimes as__null
. The proper solution is to avoid the comparison withNULL
and to use the C++ extensionstd::nullptr
.
Coco v7.3.0 ©2024 The Qt Company Ltd.
Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property
of their respective owners.