clang++ always generates empty profraw coverage reports - c++

I'm trying to integrate coverage in C++ with clang 6 for the first time and have been following this guide.
I successfully compiled the binary, generated a .profraw file and generated a .profdata file as described in steps 1, 2 and 3a. But when I try to create a line-oriented coverage report as described in 3b, I receive the following message:
error: build/debug/dane: Failed to load coverage: No coverage data found
Upon checking the .profraw file, I found it was empty. I tried changing my code a bit and running again but the generated .profraw was always empty.
My main.cpp file:
#include <iostream>
int main(int argc, char **argv) {
std::cout << "Hello, World!" << std::endl;
return 0;
}
My SConstruct file:
env = Environment(CXX='clang++', CXXFLAGS=['-Wall', '-g', '-O0'], LINKFLAGS=['-fprofile-instr-generate', '-fcoverage-mapping'])
env.Program(target='build/debug/dane', source=['src/main.cpp'])
Command line output:
➤ scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
clang++ -o src/main.o -c -Wall -g -O0 src/main.cpp
clang++ -o build/debug/dane -fprofile-instr-generate -fcoverage-mapping src/main.o
scons: done building targets.
➤ build/debug/dane
Hello, World!
➤ llvm-profdata merge -sparse default.profraw -o default.profdata
➤ llvm-cov show build/debug/dane -instr-profile=default.profdata
error: build/debug/dane: Failed to load coverage: No coverage data found
I expected the default.profraw file to hold meaningful coverage results, and have no clue why it's empty.

Finally solved it.
At first I gave the -fprofile-instr-generate -fcoverage-mapping flags as CXXFLAGS, but it didn't work, and so I understood that these were linker flags and moved them to the LINKFLAGS (which resulted in this frustrated post).
Apparently, these flags need to appear both as compilation and linker flags in order for the whole thing to work.
I also tried checking if you can distribute the flags between the compiler and the linker but that didn't succeed.

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/

Cross compilation using clang for target aarch64-cros-linux-gnu

Maybe I've got a silly question, but I stuck with that issue. I'm trying to do cross compilation using clang-5.0 of simple test program for target aarch64-cros-linux-gnu:
int main(int argc, const char **argv)
{
return 0x2;
}
So, when I'm running clang with the next command:
/home/alex/Dev/CustomToolchains/Google/clang-5.0/aarch64/usr/bin/clang --sysroot=/home/alex/Dev/CustomToolchains/Google/clang-5.0/aarch64/usr/aarch64-cros-linux-gnu -Qunused-arguments -grecord-gcc-switches -fPIE -D_FORTIFY_SOURCE=2 -fstack-protector-strong -pie -fno-omit-frame-pointer main.cxx -o main3 -B/home/alex/Dev/CustomToolchains/Google/clang-5.0/aarch64/bin -target aarch64-cros-linux-gnu
I'm getting an error:
ld.bfd: no input files
clang: error: linker command failed with exit code 1 (use -v to see invocation)
But when I'm removing --sysroot and -target parameters everything is ok. I have checked --sysroot path and it's exists but I'm not sure if it correct. clang docs says that this folder must contain bin, lib, include directories, but in the sysroot directory there are only next folders:
lib lib64 NOTICE-eglibc NOTICE-gdb sbin sys-include usr var
So, how I can specify correct toolchain path to the clang for my target triple aarch64-cros-linux-gnu? or where I can get that toolchain?
Big thanks for answers.
PS. I'm a newbie with all linux/clang/cros compilation -related staff, so I'm sorry for mistakes in my question.

Compiling an external library on Linux

Good Day Everyone,
N.B - This problem has been solved - I have provided my own solution in the answer section however the solution provided by Jonathan is much shorter. Nevertheless, this was the following question I originally posted:
I am basically trying to compile a serial library (for UART communication) on Linux however I am not really sure how to correctly compile (I have mentioned what I have done so far below), any suggestions would be highly valuable. I am using the serialib library - which is composed of 2 main files (serialib.h and serialib.cpp) , you may directly view the source code of these files here (scroll all the way to the bottom and view the files in new tabs): http://serialib.free.fr/html/classserialib.html
I transferred these files (serialib.h and serialib.cpp) to my BeagleBone Black micro-controller which is running Debian (Wheezy) , g++/gcc (Debian 4.6.3-14) 4.6.3. I wrote my own program (uart.cpp is my file name) to access the functions provided by this library, this is what I wrote:
#include <iostream>
#include "serialib.h"
#ifdef __linux__
#define DEVICE_PORT "/dev/ttyO1"
#endif
int main()
{
serialib LS;
return 0;
}
So as you can see I am trying to access the 'seriallib' class. serialib.h, serialib.cpp and uart.cpp are all in the home directory. I also manually added the iostream library in serialib.cpp as I did not see it being declared in the original source code.
Now I am really unsure of how to compile such external libraries but so far I tried the following steps:
g++ -c -Wall -Werror -fPIC serialib.c to convert to PIC which gives the following error:
distcc[3142] (dcc_parse_hosts) Warning: /home/debian/.distcc/zeroconf/hosts contained no hosts; can't distribute work
distcc[3142] (dcc_zeroconf_add_hosts) CRITICAL! failed to parse host file.
distcc[3142] (dcc_build_somewhere) Warning: failed to distribute, running locally instead
g++ serialib.cpp -L /home/debian/serialib.h which gives the following error:
/usr/lib/gcc/arm-linux-gnueabihf/4.6/../../../arm-linux-gnueabihf/crt1.o: In function _start':
(.text+0x30): undefined reference tomain'
collect2: ld returned 1 exit status
distcc[3210] ERROR: compile serialib.cpp on localhost failed
As of now I am still finding out how to compile this and if I manage to work this out then I'll post my solution here too. Once again any suggestion will be highly valuable. Thank you all :) .
g++ -c -Wall -Werror -fPIC serialib.c to convert to PIC which gives the following error:
The "error" is not an error, it's a warning, telling you that your distcc setup is broken, but that it compiled locally.
That command doesn't "convert to PIC", it compiles the file serialib.c and produces a compiled object file, serialib.o
g++ serialib.cpp -L /home/debian/serialib.h
This is just nonsense. It tries to build a program from serialib.cpp and use the directory /home/debian/serialib.h (which isn't a directory!) to find libraries.
You don't need to "compile a library" you can just compile both the source files and link them together into a program. Either:
g++ -c serialib.cpp
g++ -c uart.cpp
g++ serialib.o uart.o -o uart
Or all in one command:
g++ serialib.cpp uart.cpp -o uart
You should read An Introduction to GCC to understand the commands, not just enter bogus commands without understanding them.
I have found a solution to this problem, hope this helps for all the future readers with similar problems. I have my own source code uart.cpp (Given in the question) which I want to compile, the external library is serialib that contains two main files (serialib.h and serialib.cpp), you will want to replace the following commands with respect to the files you have
Step 1: Compiling with position independent code
g++ -c -Wall -Werror -fpic serialib.cpp
Step 2: Creating a shared library
g++ -shared -o libserialib.so serialib.o , here the library is libserialib.so.
Step 3: Linking your source code with library
g++ -L /home/debian -lserialib uart.cpp -o uart
g++ -L /home/debian -Wall -o test uart.cpp -lserialib
You may save the library at a different path and you may have a different name of course. Suppose you have a library called libabc.so at the directory /home/user/myDir then the commands will be like:
g++ -L /home/user/myDir -labc your_code.cpp -o your_code
g++ -L /home/user/myDir -Wall -o test your_code.cpp -labc
test is out own program, lserialib is actually looking for libserialib.so and not serialib.o as gcc/g++ assumes all libraries start with lib and end with .so or .a and you can see the same goes for labc as it will look for libabc.so thus it is important to make sure your library name begins with lib and ends with .so or .a
Step 4: Making library available at run time
Here we provide the path where the library is actually stored, I saved it in the directory /home/debian which is why my command looks like:
export LD_LIBRARY_PATH=/home/debian:$LD_LIBRARY_PATH
if your library is saved at /path/to/file then the command will look like:
export LD_LIBRARY_PATH=/path/to/file:$LD_LIBRARY_PATH
This is to help the loader find the shared library and to view this path: echo $LD_LIBRARY_PATH and to unset this: unset LD_LIBRARY_PATH
To execute the program type either ./test or ./uart and in case of any modification to the main source code (uart.cpp in this case) , simply repeat step 3. I found the following link very useful: http://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html . Thank you to all of you who took time to read this question and especially those who gave me suggestions. If anyone has more or better solutions, feel free to post them here to assist future readers :).

Scons: how to check file before compilation with commands which doesn't product any output file?

I work with project in which every object files is being built 3 times:
With newest g++ with lots of flags in order to find every possible errors and warnings
With clang in order to do as above and check style.
With g++ compatible with 3rdpart libraries (no newer version, but entire product is based of the libraries)
It works that way: if any object file should be recompiled: the steps 1, if success then 2, if success then 3 is being done. It is done with makefile, but I'm planning to use scons to do its. The problem is that in current solution object file from 1 and 2 is being saved into /dev/null.
I've tried something line this:
3 files in the same directory: hello.cc, Sconstruct, Sconscript
SConstruct
#!python
warningFlags = ' -Wall -Wextra -Werror' # and many more
env = Environment(CXX = 'g++-4.8', parse_flags = warningFlags, CPPPATH = '.')
builtObjects = env.SConscript('SConscript', variant_dir='built', duplicate=0, exports='env')
env.Program(target = 'hello', source = builtObjects)
SConscript
#!python
Import('env')
builtObjects = env.Object(source = 'hello.cc')
checkWithClang = env.Command('/dev/null', builtObjects, 'clang -o $TARGET -Wall -Werror')
env.Depends(checkWithClang, builtObjects)
Return('builtObjects')
The output from scons is:
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
scons: building associated VariantDir targets: built
g++-4.8 -o built/hello.o -c -Wall -Wextra -Werror -Ibuilt -I. hello.cc
g++-4.8 -o hello built/hello.o
scons: done building targets.
EDIT:
Is it possible to somehow check in scons:
if object file should be rebuilt?
Pseudo code:
src = 'hello.cc'
if shouldObjectFileBeRebuilt(src):
checkWithClang = env.Command('/dev/null', builtObjects, 'clang -o $TARGET -Wall -Werror')
builtObjects = env.Object(source = src)
env.Depends(checkWithClang, builtObjects)
try
src = "hello.cc"
builtObjects = env.Object(source = src)
checkWithClang = env.Command('/dev/null', src, 'clang -o $TARGET -Wall -Werror')
env.Depends(builtObjects, checkWithClang)
buildobjects represent '.o' files, so you should put '.c' files to clang
you want buildObjects to be built after clang objects - change the order
Still - building into /dev/null will probably break dependency tree, you might consider something like:
checkWithClang = env.Object(source = src, CC="clang", OBJPREFIX="clang-")
this will build all .c files with clang and store extra .o files, allowing scons to rebuild only what is necessarry

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