Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TOOLS: add support for GCOV code coverage tool #10635

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
/Tools/autotest/jsb_sim/rascal_test.xml
/Tools/autotest/jsbsim_fgout_0.xml
/Tools/autotest/jsbsim_start_0.xml
/Tools/autotest/rover-ch7_mission.txt
/tmp/*
*.bin
*.d
Expand Down Expand Up @@ -109,4 +110,6 @@ parameters.edn
.idea/*
# CMake
cmake-build-*/
/reports/
/GCOV_*.log

2 changes: 1 addition & 1 deletion Tools/scripts/install-prereqs-ubuntu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ PX4_PKGS="python-argparse openocd flex bison libncurses5-dev \
zip genromfs python-empy cmake cmake-data"
ARM_LINUX_PKGS="g++-arm-linux-gnueabihf pkg-config-arm-linux-gnueabihf"
# python-wxgtk packages are added to SITL_PKGS below
SITL_PKGS="libtool libxml2-dev libxslt1-dev python-dev python-pip python-setuptools python-matplotlib python-serial python-scipy python-opencv python-numpy python-pyparsing xterm"
SITL_PKGS="libtool libxml2-dev libxslt1-dev python-dev python-pip python-setuptools python-matplotlib python-serial python-scipy python-opencv python-numpy python-pyparsing xterm lcov gcovr"
ASSUME_YES=false
QUIET=false

Expand Down
134 changes: 134 additions & 0 deletions wscript
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from __future__ import print_function

import os.path
import os
import sys
import subprocess
sys.path.insert(0, 'Tools/ardupilotwaf/')

import ardupilotwaf
Expand Down Expand Up @@ -193,6 +195,112 @@ configuration in order to save typing.
default=False,
help='Force a static build')

g.add_option("--enable-gcov",
help=("Enable gcov code coverage analysis."
" WARNING: this option only has effect "
"with the configure command. "
"You should also add --lcov-report to your build command."),
action="store_true", default=False,
dest="enable_gcov")

g.add_option("--lcov-report",
help=("Generates a lcov code coverage report "
"(use this option at build time, not in configure)"),
action="store_true", default=False,
dest="lcov_report")



# EXECUTE enough code via the autotest tool to see coverage results afterwards, but don't build/rebuild anything
# our aim here is to try to execute as many code path/s as we have available to us, and we'll afterward report
# on the percentage of code executed and not executed etc.
def run_coverage_tests(bld):

FNULL = open(os.devnull, 'w')

#tests = ['fly.ArduPlane']
#tests = ['fly.ArduCopter','fly.ArduPlane']
tests = ['fly.ArduCopter','fly.ArduPlane', 'fly.QuadPlane', 'drive.APMrover2', 'dive.ArduSub']

for test in tests:
print("LCOV/GCOV -> "+test+" started.... this will take quite some time...")
testcmd = '( ./Tools/autotest/autotest.py --debug --no-configure '+test+' ) '
print("Coverage Tests Executing:"+testcmd+" > ./GCOV_"+test+".log")
FLOG = open("./GCOV_"+test+".log", 'w')
if subprocess.Popen(testcmd, shell=True , stdout=FLOG, stderr=FNULL).wait():
print("LCOV/GCOV -> "+test+" see ./GCOV_"+test+".log for log of activity)")
raise SystemExit(1)
print("LCOV/GCOV -> "+test+" succeeded")
FLOG.close()

#TODO add any other execution path/s we can to maximise the actually used code, can we run other tests or things?
# eg run.unit_tests, run.examples , test.AntennaTracker or other things?


def lcov_report(bld):
"""
Generates the coverage report
:param bld: temporal options context
:type bld: wscript.tmp
"""
env = bld.env
REPORTS = "reports"

if not env.GCOV_ENABLED:
raise WafError("project not configured for code coverage;"
" reconfigure with --enable-gcov")

run_coverage_tests(bld)
lcov_report_dir = os.path.join(REPORTS, "lcov-report")
try:
if not os.path.exists(REPORTS):
os.mkdir(REPORTS)

create_dir_command = "rm -rf " + lcov_report_dir
create_dir_command += " && mkdir " + lcov_report_dir

print (create_dir_command );
if subprocess.Popen(create_dir_command, shell=True).wait():
raise SystemExit(1)

info_file = os.path.join(lcov_report_dir, "lcov.info")

FLOG = open("GCOV_lcov.log", 'w')
FNULL = open(os.devnull, 'w')

lcov_command =\
"lcov --no-external --capture --directory . -o " + info_file
lcov_command +=\
" && lcov --remove " + info_file + " \".waf*\" -o " + info_file

print("LCOV/GCOV executing lcov -> ")
print ("\t"+lcov_command + " > ./GCOV_lcov.log")
if subprocess.Popen(lcov_command, shell=True, stdout=FLOG, stderr=FNULL).wait():
raise SystemExit(1)
FLOG.close()


FLOG = open("GCOV_genhtml.log", 'w')
genhtml_command = "genhtml " + info_file
genhtml_command += " -o " + lcov_report_dir
print("LCOV/GCOV building html report -> ")
print ("\t"+genhtml_command + " > ./GCOV_genhtml.log")
if subprocess.Popen(genhtml_command, shell=True, stdout=FLOG, stderr=FNULL).wait():
raise SystemExit(1)
FLOG.close()

except:
print (\
"LCOV/GCOV -> Problems running coverage. Try manually" );

finally:
print (\
"LCOV/GCOV -> Coverage successful. Open " + lcov_report_dir +\
"/index.html" );




def _collect_autoconfig_files(cfg):
for m in sys.modules.values():
paths = []
Expand All @@ -212,10 +320,17 @@ def _collect_autoconfig_files(cfg):
cfg.files.append(p)

def configure(cfg):
# we need to enable debug mode when building for gconv, and force it to sitl
if cfg.options.enable_gcov:
cfg.options.debug = True
cfg.options.board = 'sitl'

if cfg.options.board is None:
cfg.options.board = 'sitl'

cfg.env.BOARD = cfg.options.board

cfg.env.DEBUG = cfg.options.debug
cfg.env.AUTOCONFIG = cfg.options.autoconfig

_set_build_context_variant(cfg.env.BOARD)
Expand All @@ -234,6 +349,21 @@ def configure(cfg):

cfg.msg('Autoconfiguration', 'enabled' if cfg.options.autoconfig else 'disabled')

#Sets the lcov flag if is configurated
if cfg.options.enable_gcov:
cfg.start_msg("GCOV code coverage analysis")
cfg.env.GCOV_ENABLED = True
cfg.env.append_value('CCFLAGS', '-fprofile-arcs')
cfg.env.append_value('CCFLAGS', '-ftest-coverage')
cfg.env.append_value('CXXFLAGS', '-fprofile-arcs')
cfg.env.append_value('CXXFLAGS', '-ftest-coverage')
cfg.env.append_value('LINKFLAGS', '-lgcov')
cfg.env.append_value('LINKFLAGS', '-coverage')
cfg.end_msg('yes' , color='RED')
else:
cfg.start_msg("GCOV code coverage analysis")
cfg.end_msg('no' , color='GREEN')

if cfg.options.static:
cfg.msg('Using static linking', 'yes', color='YELLOW')
cfg.env.STATIC_LINKING = True
Expand Down Expand Up @@ -472,6 +602,10 @@ def _build_post_funs(bld):
if bld.env.SUBMODULE_UPDATE:
bld.git_submodule_post_fun()

if bld.env.GCOV_ENABLED:
#print(bld.env);
bld.add_post_fun(lcov_report)

def _load_pre_build(bld):
'''allow for a pre_build() function in build modules'''
brd = bld.get_board()
Expand Down