__all: build
-main-targets := build install uninstall clean distclean MAP
+main-targets := build install uninstall clean distclean MAP cppcheck cppcheck-html
.PHONY: $(main-targets)
ifneq ($(XEN_TARGET_ARCH),x86_32)
$(main-targets): %: _% ;
$(Q)$(MAKE) $(clean)=tools/kconfig
find . \( -name "*.o" -o -name ".*.d" -o -name ".*.d2" \
-o -name ".*.o.tmp" -o -name "*~" -o -name "core" \
- -o -name '*.lex.c' -o -name '*.tab.[ch]' \
+ -o -name '*.lex.c' -o -name '*.tab.[ch]' -o -name '*.c.cppcheck' \
-o -name "*.gcno" -o -name ".*.cmd" -o -name "lib.a" \) -exec rm -f {} \;
rm -f include/asm $(TARGET) $(TARGET).gz $(TARGET).efi $(TARGET).efi.map $(TARGET)-syms $(TARGET)-syms.map
rm -f asm-offsets.s arch/*/include/asm/asm-offsets.h
rm -f .banner .allconfig.tmp include/xen/compile.h
+ rm -f xen-cppcheck.xml
.PHONY: _distclean
_distclean: clean
rm -f tags TAGS cscope.files cscope.in.out cscope.out cscope.po.out GTAGS GPATH GRTAGS GSYMS .config source
+ rm -rf $(CPPCHECK_HTMLREPORT_OUTDIR)
$(TARGET).gz: $(TARGET)
gzip -n -f -9 < $< > $@.new
done; \
done | cloc --list-file=-
+# What cppcheck command to use.
+# To get proper results, it is recommended to build cppcheck manually from the
+# latest source and use CPPCHECK to give the full path to the built version.
+CPPCHECK ?= cppcheck
+
+# What cppcheck-htmlreport to use.
+# If you give the full path to a self compiled cppcheck, this should be set
+# to the full path to cppcheck-html in the htmlreport directory of cppcheck.
+# On recent distribution, this is available in the standard path.
+CPPCHECK_HTMLREPORT ?= cppcheck-htmlreport
+
+# By default we generate the report in cppcheck-htmlreport directory in the
+# build directory. This can be changed by giving a directory in this variable.
+CPPCHECK_HTMLREPORT_OUTDIR ?= cppcheck-htmlreport
+
+# Compile flags to pass to cppcheck:
+# - include directories and defines Xen Makefile is passing (from CFLAGS)
+# - include config.h as this is passed directly to the compiler.
+# - define CPPCHECK as we use to disable or enable some specific part of the
+# code to solve some cppcheck issues.
+# - explicitely enable some cppcheck checks as we do not want to use "all"
+# which includes unusedFunction which gives wrong positives as we check file
+# per file.
+#
+# Compiler defines are in compiler-def.h which is included in config.h
+#
+CPPCHECKFLAGS := -DCPPCHECK --max-ctu-depth=10 \
+ --enable=style,information,missingInclude \
+ --include=$(srctree)/include/xen/config.h \
+ -I $(srctree)/xsm/flask/include \
+ -I $(srctree)/include/xen/libfdt \
+ $(filter -D% -I%,$(CFLAGS))
+
+# We need to find all C files (as we are not checking assembly files) so
+# we find all generated .o files which have a .c corresponding file.
+CPPCHECKFILES := $(wildcard $(patsubst $(objtree)/%.o,$(srctree)/%.c, \
+ $(filter-out $(objtree)/tools/%, \
+ $(shell find $(objtree) -name "*.o"))))
+
+quiet_cmd_cppcheck_xml = CPPCHECK $(patsubst $(srctree)/%,%,$<)
+cmd_cppcheck_xml = $(CPPCHECK) -v -q --xml $(CPPCHECKFLAGS) \
+ --output-file=$@ $<
+
+quiet_cmd_merge_cppcheck_reports = CPPCHECK-MERGE $@
+cmd_merge_cppcheck_reports = $(srctree)/tools/merge_cppcheck_reports.py $^ $@
+
+quiet_cmd_cppcheck_html = CPPCHECK-HTML $<
+cmd_cppcheck_html = $(CPPCHECK_HTMLREPORT) --file=$< --source-dir=$(srctree) \
+ --report-dir=$(CPPCHECK_HTMLREPORT_OUTDIR) --title=Xen
+
+PHONY += _cppcheck _cppcheck-html cppcheck-version
+
+_cppcheck-html: xen-cppcheck.xml
+ $(call if_changed,cppcheck_html)
+
+_cppcheck: xen-cppcheck.xml
+
+xen-cppcheck.xml: $(patsubst $(srctree)/%.c,$(objtree)/%.c.cppcheck,$(CPPCHECKFILES))
+ifeq ($(CPPCHECKFILES),)
+ $(error Please build Xen before running cppcheck)
+endif
+ $(call if_changed,merge_cppcheck_reports)
+
+$(objtree)/%.c.cppcheck: $(srctree)/%.c $(objtree)/include/generated/autoconf.h $(objtree)/include/generated/compiler-def.h | cppcheck-version
+ $(call if_changed,cppcheck_xml)
+
+cppcheck-version:
+ifeq ($(shell which $(CPPCHECK)),)
+ $(error Cannot find cppcheck executable: $(CPPCHECK))
+endif
+ifeq ($(shell $(CPPCHECK) --version | awk '{print ($$2 < 2.7)}'),1)
+ $(error Please upgrade your cppcheck to version 2.7 or greater)
+endif
+
+# Put this in generated headers this way it is cleaned by include/Makefile
+$(objtree)/include/generated/compiler-def.h:
+ $(Q)$(CC) -dM -E -o $@ - < /dev/null
+
endif #config-build
endif # need-sub-make
--- /dev/null
+#!/usr/bin/env python
+
+"""
+This script acts as a tool to merge XML files created by cppcheck.
+Usage:
+ merge_cppcheck_reports.py [FILES] [OUTPUT]
+
+ FILES - list of XML files with extension .cppcheck
+ OUTPUT - file to store results (with .xml extension).
+ If not specified, the script will print results to stdout.
+"""
+
+import sys
+from xml.etree import ElementTree
+
+def elements_equal(el1, el2):
+ if type(el1) != type(el2): return False
+
+ if el1.find('location') is None: return False
+ if el2.find('location') is None: return False
+
+ el1_location = str(el1.find('location').attrib)
+ el2_location = str(el2.find('location').attrib)
+
+ if el1_location != el2_location: return False
+
+ return True
+
+def contain_element(new, lst):
+ for elem in lst:
+ if elements_equal(new, elem):
+ return True
+ return False
+
+def merge(files):
+ try:
+ result_xml_root = ElementTree.parse(files[0]).getroot()
+ except:
+ print("Xml parsing error in %s\n" % (files[0]))
+ print("Please upgrade your cppcheck to version 2.7 or greater")
+ sys.exit(1)
+ insert_point = result_xml_root.findall("errors")[0]
+ curr = 1
+ total = len(files)
+ numelem = len(insert_point)
+ for xml_file in files[1:]:
+ try:
+ xml_root = ElementTree.parse(xml_file).getroot()
+ except:
+ print("Xml parsing error in %s\n" % (xml_file))
+ print("Please upgrade your cppcheck to version 2.7 or greater")
+ sys.exit(1)
+ curr_elem_list = list(insert_point)
+ new_elem_list = list(xml_root.findall("errors")[0])
+ for xml_error_elem in new_elem_list:
+ if not contain_element(xml_error_elem, curr_elem_list):
+ insert_point.insert(1,xml_error_elem)
+ numelem = numelem + 1
+ curr = curr + 1
+ sys.stdout.write('\r')
+ sys.stdout.write(" %d / %d" % (curr,total))
+ sys.stdout.flush()
+
+ sys.stdout.write('\r\n')
+ print("Done: %d elements" % (numelem))
+ return result_xml_root
+
+def run():
+ files = []
+ output = None
+ for i in sys.argv[1:]:
+ output = i if '.xml' in i else None
+ files.append(i) if '.cppcheck' in i else None
+
+ result = merge(files)
+
+ if result is None:
+ return
+
+ if output is not None:
+ ElementTree.ElementTree(result).write(output)
+ else:
+ print(ElementTree.tostring(result).decode('utf-8'))
+
+if __name__ == '__main__':
+ run()