1#!/usr/bin/env python3
2
3import sys, re, os
4
5module_dir = os.path.dirname(os.path.realpath(__file__))
6xen_dir = os.path.realpath(module_dir + "/../..")
7repo_dir = os.path.realpath(xen_dir + "/..")
8tools_dir = os.path.realpath(xen_dir + "/tools")
9
10step_get_make_vars = False
11step_parse_tags = True
12step_cppcheck_deps = False
13step_build_xen = True
14step_cppcheck_report = False
15step_clean_analysis = True
16step_distclean_analysis = False
17
18target_build = False
19target_clean = False
20target_distclean = False
21
22analysis_tool = ""
23cppcheck_binpath = "cppcheck"
24cppcheck_html = False
25cppcheck_htmlreport_binpath = "cppcheck-htmlreport"
26cppcheck_misra = False
27cppcheck_skip_rules = ""
28make_forward_args = ""
29outdir = xen_dir
30
31
32def help():
33    msg="""
34Usage: {} [OPTION] ... [-- [make arguments]]
35
36This script runs the analysis on the Xen codebase.
37
38The phases for the analysis are <tags>, <build>, <clean>, <cppcheck report>
39
40Depending on the options below, only some phases will run:
41
42<no options>: tags, build, [cppcheck report], clean
43--build-only: build, [cppcheck report]
44--clean-only: clean
45--distclean:  clean, [destroy cppcheck report]
46--no-build:   tags, clean
47--no-clean:   tags, build
48
49--no-build/--no-clean can be passed together to avoid both clean and build
50phases.
51Tags and build phases need to specify --run-coverity, --run-eclair or
52--run-cppcheck.
53Cppcheck report creation phase runs only when --run-cppcheck is passed to the
54script.
55
56Options:
57  --build-only            Run only the commands to build Xen with the optional
58                          make arguments passed to the script
59  --clean-only            Run only the commands to clean the analysis artifacts
60  --cppcheck-bin=         Path to the cppcheck binary (Default: {})
61  --cppcheck-html         Produce an additional HTML output report for Cppcheck
62  --cppcheck-html-bin=    Path to the cppcheck-html binary (Default: {})
63  --cppcheck-misra        Activate the Cppcheck MISRA analysis
64  --cppcheck-skip-rules=  List of MISRA rules to be skipped, comma separated.
65                          (e.g. --cppcheck-skip-rules=1.1,20.7,8.4)
66  --distclean             Clean analysis artifacts and reports
67  -h, --help              Print this help
68  --no-build              Skip the build Xen phase
69  --no-clean              Don\'t clean the analysis artifacts on exit
70  --run-coverity          Run the analysis for the Coverity tool
71  --run-cppcheck          Run the Cppcheck analysis tool on Xen
72  --run-eclair            Run the analysis for the Eclair tool
73"""
74    print(msg.format(sys.argv[0], cppcheck_binpath,
75                     cppcheck_htmlreport_binpath))
76
77
78def parse_commandline(argv):
79    global analysis_tool
80    global cppcheck_binpath
81    global cppcheck_html
82    global cppcheck_htmlreport_binpath
83    global cppcheck_misra
84    global cppcheck_skip_rules
85    global make_forward_args
86    global outdir
87    global step_get_make_vars
88    global step_parse_tags
89    global step_cppcheck_deps
90    global step_build_xen
91    global step_cppcheck_report
92    global step_clean_analysis
93    global step_distclean_analysis
94    global target_build
95    global target_clean
96    global target_distclean
97    forward_to_make = False
98    for option in argv:
99        args_with_content_regex = re.match(r'^(--[a-z]+[a-z-]*)=(.*)$', option)
100
101        if forward_to_make:
102            # Intercept outdir
103            outdir_regex = re.match("^O=(.*)$", option)
104            if outdir_regex:
105                outdir = outdir_regex.group(1)
106            # Forward any make arguments
107            make_forward_args = make_forward_args + " " + option
108        elif option == "--build-only":
109            target_build = True
110        elif option == "--clean-only":
111            target_clean = True
112        elif args_with_content_regex and \
113             args_with_content_regex.group(1) == "--cppcheck-bin":
114            cppcheck_binpath = args_with_content_regex.group(2)
115        elif option == "--cppcheck-html":
116            cppcheck_html = True
117        elif args_with_content_regex and \
118             args_with_content_regex.group(1) == "--cppcheck-html-bin":
119            cppcheck_htmlreport_binpath = args_with_content_regex.group(2)
120        elif option == "--cppcheck-misra":
121            cppcheck_misra = True
122        elif args_with_content_regex and \
123             args_with_content_regex.group(1) == "--cppcheck-skip-rules":
124            cppcheck_skip_rules = args_with_content_regex.group(2)
125        elif option == "--distclean":
126            target_distclean = True
127        elif (option == "--help") or (option == "-h"):
128            help()
129            sys.exit(0)
130        elif option == "--no-build":
131            step_build_xen = False
132        elif option == "--no-clean":
133            step_clean_analysis = False
134        elif (option == "--run-coverity") or (option == "--run-eclair"):
135            analysis_tool = option[6:]
136        elif (option == "--run-cppcheck"):
137            analysis_tool = "cppcheck"
138            step_get_make_vars = True
139            step_cppcheck_deps = True
140            step_cppcheck_report = True
141        elif option == "--":
142            forward_to_make = True
143        else:
144            print("Invalid option: {}".format(option))
145            help()
146            sys.exit(1)
147
148    if target_build and (target_clean or target_distclean):
149        print("--build-only is not compatible with --clean-only/--distclean "
150              "argument.")
151        sys.exit(1)
152
153    if target_distclean:
154        # Implicit activation of clean target
155        target_clean = True
156
157        step_distclean_analysis = True
158
159    if target_clean:
160        step_get_make_vars = False
161        step_parse_tags = False
162        step_cppcheck_deps = False
163        step_build_xen = False
164        step_cppcheck_report = False
165        step_clean_analysis = True
166        return
167
168    if analysis_tool == "":
169        print("Please specify one analysis tool.")
170        help()
171        sys.exit(1)
172
173    if target_build:
174        step_parse_tags = False
175        step_build_xen = True
176        step_clean_analysis = False
177