CMake produces object files with .obj extension instead of .o [duplicate] - c++

I'm struggling to get coverage information for gcov. No errors during compilation and linking, but when I run the executable, no coverage data is produced.
I'm using CMake with a separate build directory, passing flags to the compiler and linker in this way:
add_definitions(--coverage)
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
Does the executable expect the source code to be in a specific location?
What do I have to add to my CMakeLists.txt to get things going?
Kind regards,
Bjoern

CMake seems to put the code coverage (*.gcda, *.gcdo) files with the object files of your project. If your executable was named "tester" then they would appear in the following path
${CMAKE_BINARY_DIR}/CMakeFiles/tester.dir/
CMake seems to name the source files in a way that isn't very compatible with gcov though. For example if I had a source file called "mytestprog.cpp" it would be build
mytestprog.cpp.o
mytestprog.cpp.gcda
mytestprog.cpp.gcdno
where as gcov seems to expect
mytestprog.gcda
mytestprog.gcdno
I'm not really sure how to fix it. I've tried using LCov instead and that "appeared" to work but I'm not really sure if it did.

Delcypher pointed out the problem.
Solution 1: you can ask cmake to name object files as main.o instead of main.cpp.o etc. using the undocumented CMAKE_CXX_OUTPUT_EXTENSION_REPLACE switch:
cmake -DCMAKE_CXX_OUTPUT_EXTENSION_REPLACE=ON ...
Solution 2: if you do not need the .gcov files you can call lcov from the build directory:
lcov --capture --directory . --output-file coverage.info
genhtml coverage.info --output-directory out
You will find the coverage information in the out directory in html form.

Not sure where you got --coverage from, but these are the arguments I use on Linux to get coverage information using gcc and gcov:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
Here's what gcc --help --verbose has to say about those options:
-ftest-coverage Create
data files needed by "gcov"
-fprofile-arcs Insert
arc-based program profiling code

You don't need to pass --coverage to the linker. --coverage will pass -fprofile-arcs -ftest-coverage to the compiler and -lgcov to the linker.
Are you sure that it isn't creating any gcdo or gcda files? Where are you looking for these files? It should put the gcov file for each object file into the same directory as the object file. Do a find for .gcda files at the top of your build directory. If nothing shows up, gcov might not be getting linked in. Run the following command to see if it is:
nm name_of_binary | grep "gcov"
If it is getting linked in, then gcov might not have permission to write files to where you are running the executable. If it has permission, then I am stumped.

Related

cant create coverage informations with lcov WARNING: no .gcda files found in ./coverage

I have been trying to get code coverage working for Qt but im struggling with generating any coverage information
Project
example.pro (contains include for googletest.pri)
gtest_dependency (contains googletest.pri
headerfiles for gtest
testsuite.h
sourcefiles for gtest
test.cpp
testsuite.cpp
main.cpp
All files above are pretty much empty just the code to run the test and one test case.
I included the linker flags in the example.pro
QMAKE_CXXFLAGS += -O0 -g --coverage
QMAKE_LFLAGS += -O0 -g --coverage
The problem is when I build the project it creates all the .gcna .gcno files, but when i execute lcov it says
WARNING: no .gcda files found in ./coverage -skipping!
Finished .info-file creation
Reading tracefile ./coverage/coverage.info
lcov: ERROR: no valid records found in tracefile ./coverage/coverage.info
Reading data file ./coverage/coverage-filtered.info
genhtml: ERROR: cannot read file ./coverage/coverage-filtered.info
Qt Version 5.14.2
Compiler mingw730_64
lcov version 1.14
gcov version 7.5.0
Ok i managed to fix it
If you run into the same problem as me check if you have googletest installed on /usr/include, since I use lcov and so on over the linux bash it couldnt find anything since everything was installed over /mnt/ and it couldnt find gtest since it searches in /usr.
Same goes for qt it couldnt find the files even if included with -L and -I.
I had to install both on /usr/

CMake Gcov c++ creating wrong .gcno files

I have a CMakeLists.txt file in which I added:
set(CMAKE_CXX_FLAGS "-fprofile-arcs -ftest-coverage -pthread -std=c++11 -O0 ${CMAKE_CXX_FLAGS}")
It is generating the report files in:
project_root/build/CMakeFiles/project.dir/
BUT the files it generates have extentions .cpp.gcno, .cpp.gcda and .cpp.o.
Also, they are not in the same folder as the src files, which are at:
project_root/src/
When I move the report files to the src/ folder and execute
$ gcov main.cpp
main.gcno:cannot open notes file
But I get that error message. So I change the .cpp.gcno, .cpp.cdna and cpp.o to .gcno, .gcda and .o and finally I get the following:
gcov main.cpp
Lines executed:86.67% of 15
Creating 'main.cpp.gcov'
I have over 50 files and can't do this manually for each one.
I need to be able to run gcov once for all files and generate report for all files. I don't care where the files are generated.
It is generating the report files in: project_root/build/CMakeFiles/project.dir/
This is directory where all additional files are built for 'project' executable.
BUT the files it generates have extentions '.cpp.gcno', '.cpp.gcda' and '.cpp.o'
This is because CMake creates .cpp.o object file from .cpp source (you may see that running make VERBOSE=1. In accordance to -fprofile-arcs option's description, data file has suffix .cpp.gcno.
Also, they are not in the same folder as the src files
Data files are created in the same directory with object file.
Actually, created files are still work, if you call
gcov main.cpp.gcno
from the directory with .gcno files.
Apparently the standard CMake behavior to add an extension to give .cpp.o can be changed to replace an extension to give .o by using:
set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE ON)

How to find the coverage of a library opened using dlopen()?

I have a C++ library (.so) which is opened using dlopen() by another application. But I need to find the code coverage of this library while run within the application using gcov. Is it possible? If yes, how can it be done?
If not, how can the issue be resolved?
Firstly have your compiled your C++ library with the --coverage flag? I've never actually used a '.so' library with gcov before, so I'm not sure it would work anyway.
Secondly could you arrange a test version of your application to not use dlopen(), but instead be linked to a static library(.a) version of your library and still make the usual calls?
Yes. Coverage of shared library loaded by dlopen can be generated.
1) compile shared library with flags -fprofile-arcs -ftest-coverage
2) compile program that using dlopen with flags -fprofile-arc -ftest-coverage
3) lcov to generate .info file
lcov --capture --rc lcov_branch_coverage=1 --directory path/to/.gcda --output-file coverage.info
4) generate html
genhtml coverage.info --branch-coverage --output-directory out

gcov with CMake using a separate build directory

I'm struggling to get coverage information for gcov. No errors during compilation and linking, but when I run the executable, no coverage data is produced.
I'm using CMake with a separate build directory, passing flags to the compiler and linker in this way:
add_definitions(--coverage)
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
Does the executable expect the source code to be in a specific location?
What do I have to add to my CMakeLists.txt to get things going?
Kind regards,
Bjoern
CMake seems to put the code coverage (*.gcda, *.gcdo) files with the object files of your project. If your executable was named "tester" then they would appear in the following path
${CMAKE_BINARY_DIR}/CMakeFiles/tester.dir/
CMake seems to name the source files in a way that isn't very compatible with gcov though. For example if I had a source file called "mytestprog.cpp" it would be build
mytestprog.cpp.o
mytestprog.cpp.gcda
mytestprog.cpp.gcdno
where as gcov seems to expect
mytestprog.gcda
mytestprog.gcdno
I'm not really sure how to fix it. I've tried using LCov instead and that "appeared" to work but I'm not really sure if it did.
Delcypher pointed out the problem.
Solution 1: you can ask cmake to name object files as main.o instead of main.cpp.o etc. using the undocumented CMAKE_CXX_OUTPUT_EXTENSION_REPLACE switch:
cmake -DCMAKE_CXX_OUTPUT_EXTENSION_REPLACE=ON ...
Solution 2: if you do not need the .gcov files you can call lcov from the build directory:
lcov --capture --directory . --output-file coverage.info
genhtml coverage.info --output-directory out
You will find the coverage information in the out directory in html form.
Not sure where you got --coverage from, but these are the arguments I use on Linux to get coverage information using gcc and gcov:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
Here's what gcc --help --verbose has to say about those options:
-ftest-coverage Create
data files needed by "gcov"
-fprofile-arcs Insert
arc-based program profiling code
You don't need to pass --coverage to the linker. --coverage will pass -fprofile-arcs -ftest-coverage to the compiler and -lgcov to the linker.
Are you sure that it isn't creating any gcdo or gcda files? Where are you looking for these files? It should put the gcov file for each object file into the same directory as the object file. Do a find for .gcda files at the top of your build directory. If nothing shows up, gcov might not be getting linked in. Run the following command to see if it is:
nm name_of_binary | grep "gcov"
If it is getting linked in, then gcov might not have permission to write files to where you are running the executable. If it has permission, then I am stumped.

gcov on larger projects (static libraries, ...)

I'm working on larger project which has the following directory layout:
Source
MyA
aa.cpp
ab.cpp
ac.cpp
MyB
ba.cpp
bb.cpp
bc.cpp
MyTest
testaa.cpp
testab.cpp
testac.cpp
testba.cpp
testbb.cpp
testbc.cpp
main.cpp
Build
MyA
aa.o
ab.o
ac.o
libMyA.a (static library)
MyB
ba.o
bb.o
bc.o
libMyB.a (static library)
MyTest
testaa.o
testab.o
testac.o
testba.o
testbb.o
testbc.o
MyTest (executable)
After compiling with -fprofile-arcs -ftest-coverage I execute the MyTest application inside the Build/MyTest directory. As expected there are *.gcno and *.gcda files inside the Build directory. After running gcov inside the MyTest directory different *.gcov files are produced but unfortunately not for everything inside MyA and MyB, although every function is called inside this two libraries. Tried different options but somehow I'm unable to create useful (means correct) *.gcov files with this layout.
If I copy every cpp inside one directory and repeat the steps everything works as expected and the coverage analysis is perfect.
You must specify source files as absolute paths to g++/gcc. Don't use relative paths with ".." or like "foo/bar.cpp", else you'll get errors like "geninfo: WARNING: no data found for XXXX".
Don't include any header files on the command line to g++/gcc. Else you'll get "stamp mismatch with graph file" errors.
So, following should work when having multiple directories:
g++ --coverage -DDEBUG -g3 heyo.cpp /app/helper/blah.cpp /app/libfoo/foo.cpp -o program
./program
lcov --directory . --capture --output-file app.info
genhtml --output-directory cov_htmp app.info
Or, if you're in a Makefile that uses relative paths already, it's convenient to use:
g++ --coverage -DDEBUG -g3 $(abspath heyo.cpp helper/blah.cpp ../foo/bar/baz.cpp) -o program
To be able to keep your directory structure, you need to run gcov once inside each source file folder, but use the -o option to tell gcov where the data files are.
I think it should be like this:
gcov -o ../../Build/MyA *.cpp
I have a project with a similar source file structure, but I let the compiler dump object files etc into the source folders. I then run gcov multiple times from the root folder, once for each source file, but I specify the relative path of the source file and use the -o option to specify the relative folder like this:
gcov -o Source/MyA Source/MyA/aa.cpp
If you performed your product or application testing thoroughly and manually and spent lot of effort on it. If your objective is to get code coverage report using lcov and gcov but by mistake deleted gcno files. You can regenerate gcno files by recompiling the code but it will be generated with new timestamp and gcov reports error saying "stamp mismatch with graph file" and no code coverage report will be generated. This will result in all your testing effort getting wasted.
There is a shortcut to still generate the code coverage report. This is just a workaround and should not be relied upon all the time. Its recommended to preserve *.gcno files till your testing completes.
Note down your gcc version(gcc -v) and download its source code from one of the mirror sites
Eg - ftp://gd.tuwien.ac.at/gnu/sourceware/gcc/releases/gcc-4.4.6/gcc-4.4.6.tar.bz2
After extracting downloaded file, gcc the folder structure will be as follows
gcc-4.4.6
gcc-4.4.6/gcc
If you directly go inside gcc-4.4.6/gcc and try to do ./configure and compile(make) from there then you will encounter below problem
build/genmodes -h > tmp-modes.h
/bin/sh: build/genmodes: No such file or directory
Solution is do ./configure and make from gcc-4.4.6 and no errors will be shown related to genmodes. This will compile all modules including gcc. You may have to install mpfr and gmp modules which are needed by gcc if any error shown by ./configure
goto gcc-4.4.6/gcc/gcov.c and comment below lines and then recompile with above command
/* if (tag != bbg_stamp)
{
fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name);
goto cleanup;
}*/
Example path of new gcov binary after compilation is gcc-4.4.6/host-x86_64-unknown-linux-gnu/gcc/gcov
Place this binary in /usr/bin and regenerate code coverage report with command as shown in below example
lcov --capture --directory ./ --output-file coverage.info ; genhtml coverage.info --output-directory /var/www/html/coverage
Now you should not get "stamp mismatch with graph file" error and you will get code coverage report properly