1*a9ac8606Spatrick# -*- coding: utf-8 -*- 2*a9ac8606Spatrick# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 3*a9ac8606Spatrick# See https://llvm.org/LICENSE.txt for license information. 4*a9ac8606Spatrick# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 5*a9ac8606Spatrick""" This module parses and validates arguments for command-line interfaces. 6*a9ac8606Spatrick 7*a9ac8606SpatrickIt uses argparse module to create the command line parser. (This library is 8*a9ac8606Spatrickin the standard python library since 3.2 and backported to 2.7, but not 9*a9ac8606Spatrickearlier.) 10*a9ac8606Spatrick 11*a9ac8606SpatrickIt also implements basic validation methods, related to the command. 12*a9ac8606SpatrickValidations are mostly calling specific help methods, or mangling values. 13*a9ac8606Spatrick""" 14*a9ac8606Spatrickfrom __future__ import absolute_import, division, print_function 15*a9ac8606Spatrick 16*a9ac8606Spatrickimport os 17*a9ac8606Spatrickimport sys 18*a9ac8606Spatrickimport argparse 19*a9ac8606Spatrickimport logging 20*a9ac8606Spatrickimport tempfile 21*a9ac8606Spatrickfrom libscanbuild import reconfigure_logging, CtuConfig 22*a9ac8606Spatrickfrom libscanbuild.clang import get_checkers, is_ctu_capable 23*a9ac8606Spatrick 24*a9ac8606Spatrick__all__ = ['parse_args_for_intercept_build', 'parse_args_for_analyze_build', 25*a9ac8606Spatrick 'parse_args_for_scan_build'] 26*a9ac8606Spatrick 27*a9ac8606Spatrick 28*a9ac8606Spatrickdef parse_args_for_intercept_build(): 29*a9ac8606Spatrick """ Parse and validate command-line arguments for intercept-build. """ 30*a9ac8606Spatrick 31*a9ac8606Spatrick parser = create_intercept_parser() 32*a9ac8606Spatrick args = parser.parse_args() 33*a9ac8606Spatrick 34*a9ac8606Spatrick reconfigure_logging(args.verbose) 35*a9ac8606Spatrick logging.debug('Raw arguments %s', sys.argv) 36*a9ac8606Spatrick 37*a9ac8606Spatrick # short validation logic 38*a9ac8606Spatrick if not args.build: 39*a9ac8606Spatrick parser.error(message='missing build command') 40*a9ac8606Spatrick 41*a9ac8606Spatrick logging.debug('Parsed arguments: %s', args) 42*a9ac8606Spatrick return args 43*a9ac8606Spatrick 44*a9ac8606Spatrick 45*a9ac8606Spatrickdef parse_args_for_analyze_build(): 46*a9ac8606Spatrick """ Parse and validate command-line arguments for analyze-build. """ 47*a9ac8606Spatrick 48*a9ac8606Spatrick from_build_command = False 49*a9ac8606Spatrick parser = create_analyze_parser(from_build_command) 50*a9ac8606Spatrick args = parser.parse_args() 51*a9ac8606Spatrick 52*a9ac8606Spatrick reconfigure_logging(args.verbose) 53*a9ac8606Spatrick logging.debug('Raw arguments %s', sys.argv) 54*a9ac8606Spatrick 55*a9ac8606Spatrick normalize_args_for_analyze(args, from_build_command) 56*a9ac8606Spatrick validate_args_for_analyze(parser, args, from_build_command) 57*a9ac8606Spatrick logging.debug('Parsed arguments: %s', args) 58*a9ac8606Spatrick return args 59*a9ac8606Spatrick 60*a9ac8606Spatrick 61*a9ac8606Spatrickdef parse_args_for_scan_build(): 62*a9ac8606Spatrick """ Parse and validate command-line arguments for scan-build. """ 63*a9ac8606Spatrick 64*a9ac8606Spatrick from_build_command = True 65*a9ac8606Spatrick parser = create_analyze_parser(from_build_command) 66*a9ac8606Spatrick args = parser.parse_args() 67*a9ac8606Spatrick 68*a9ac8606Spatrick reconfigure_logging(args.verbose) 69*a9ac8606Spatrick logging.debug('Raw arguments %s', sys.argv) 70*a9ac8606Spatrick 71*a9ac8606Spatrick normalize_args_for_analyze(args, from_build_command) 72*a9ac8606Spatrick validate_args_for_analyze(parser, args, from_build_command) 73*a9ac8606Spatrick logging.debug('Parsed arguments: %s', args) 74*a9ac8606Spatrick return args 75*a9ac8606Spatrick 76*a9ac8606Spatrick 77*a9ac8606Spatrickdef normalize_args_for_analyze(args, from_build_command): 78*a9ac8606Spatrick """ Normalize parsed arguments for analyze-build and scan-build. 79*a9ac8606Spatrick 80*a9ac8606Spatrick :param args: Parsed argument object. (Will be mutated.) 81*a9ac8606Spatrick :param from_build_command: Boolean value tells is the command suppose 82*a9ac8606Spatrick to run the analyzer against a build command or a compilation db. """ 83*a9ac8606Spatrick 84*a9ac8606Spatrick # make plugins always a list. (it might be None when not specified.) 85*a9ac8606Spatrick if args.plugins is None: 86*a9ac8606Spatrick args.plugins = [] 87*a9ac8606Spatrick 88*a9ac8606Spatrick # make exclude directory list unique and absolute. 89*a9ac8606Spatrick uniq_excludes = set(os.path.abspath(entry) for entry in args.excludes) 90*a9ac8606Spatrick args.excludes = list(uniq_excludes) 91*a9ac8606Spatrick 92*a9ac8606Spatrick # because shared codes for all tools, some common used methods are 93*a9ac8606Spatrick # expecting some argument to be present. so, instead of query the args 94*a9ac8606Spatrick # object about the presence of the flag, we fake it here. to make those 95*a9ac8606Spatrick # methods more readable. (it's an arguable choice, took it only for those 96*a9ac8606Spatrick # which have good default value.) 97*a9ac8606Spatrick if from_build_command: 98*a9ac8606Spatrick # add cdb parameter invisibly to make report module working. 99*a9ac8606Spatrick args.cdb = 'compile_commands.json' 100*a9ac8606Spatrick 101*a9ac8606Spatrick # Make ctu_dir an abspath as it is needed inside clang 102*a9ac8606Spatrick if not from_build_command and hasattr(args, 'ctu_phases') \ 103*a9ac8606Spatrick and hasattr(args.ctu_phases, 'dir'): 104*a9ac8606Spatrick args.ctu_dir = os.path.abspath(args.ctu_dir) 105*a9ac8606Spatrick 106*a9ac8606Spatrick 107*a9ac8606Spatrickdef validate_args_for_analyze(parser, args, from_build_command): 108*a9ac8606Spatrick """ Command line parsing is done by the argparse module, but semantic 109*a9ac8606Spatrick validation still needs to be done. This method is doing it for 110*a9ac8606Spatrick analyze-build and scan-build commands. 111*a9ac8606Spatrick 112*a9ac8606Spatrick :param parser: The command line parser object. 113*a9ac8606Spatrick :param args: Parsed argument object. 114*a9ac8606Spatrick :param from_build_command: Boolean value tells is the command suppose 115*a9ac8606Spatrick to run the analyzer against a build command or a compilation db. 116*a9ac8606Spatrick :return: No return value, but this call might throw when validation 117*a9ac8606Spatrick fails. """ 118*a9ac8606Spatrick 119*a9ac8606Spatrick if args.help_checkers_verbose: 120*a9ac8606Spatrick print_checkers(get_checkers(args.clang, args.plugins)) 121*a9ac8606Spatrick parser.exit(status=0) 122*a9ac8606Spatrick elif args.help_checkers: 123*a9ac8606Spatrick print_active_checkers(get_checkers(args.clang, args.plugins)) 124*a9ac8606Spatrick parser.exit(status=0) 125*a9ac8606Spatrick elif from_build_command and not args.build: 126*a9ac8606Spatrick parser.error(message='missing build command') 127*a9ac8606Spatrick elif not from_build_command and not os.path.exists(args.cdb): 128*a9ac8606Spatrick parser.error(message='compilation database is missing') 129*a9ac8606Spatrick 130*a9ac8606Spatrick # If the user wants CTU mode 131*a9ac8606Spatrick if not from_build_command and hasattr(args, 'ctu_phases') \ 132*a9ac8606Spatrick and hasattr(args.ctu_phases, 'dir'): 133*a9ac8606Spatrick # If CTU analyze_only, the input directory should exist 134*a9ac8606Spatrick if args.ctu_phases.analyze and not args.ctu_phases.collect \ 135*a9ac8606Spatrick and not os.path.exists(args.ctu_dir): 136*a9ac8606Spatrick parser.error(message='missing CTU directory') 137*a9ac8606Spatrick # Check CTU capability via checking clang-extdef-mapping 138*a9ac8606Spatrick if not is_ctu_capable(args.extdef_map_cmd): 139*a9ac8606Spatrick parser.error(message="""This version of clang does not support CTU 140*a9ac8606Spatrick functionality or clang-extdef-mapping command not found.""") 141*a9ac8606Spatrick 142*a9ac8606Spatrick 143*a9ac8606Spatrickdef create_intercept_parser(): 144*a9ac8606Spatrick """ Creates a parser for command-line arguments to 'intercept'. """ 145*a9ac8606Spatrick 146*a9ac8606Spatrick parser = create_default_parser() 147*a9ac8606Spatrick parser_add_cdb(parser) 148*a9ac8606Spatrick 149*a9ac8606Spatrick parser_add_prefer_wrapper(parser) 150*a9ac8606Spatrick parser_add_compilers(parser) 151*a9ac8606Spatrick 152*a9ac8606Spatrick advanced = parser.add_argument_group('advanced options') 153*a9ac8606Spatrick group = advanced.add_mutually_exclusive_group() 154*a9ac8606Spatrick group.add_argument( 155*a9ac8606Spatrick '--append', 156*a9ac8606Spatrick action='store_true', 157*a9ac8606Spatrick help="""Extend existing compilation database with new entries. 158*a9ac8606Spatrick Duplicate entries are detected and not present in the final output. 159*a9ac8606Spatrick The output is not continuously updated, it's done when the build 160*a9ac8606Spatrick command finished. """) 161*a9ac8606Spatrick 162*a9ac8606Spatrick parser.add_argument( 163*a9ac8606Spatrick dest='build', nargs=argparse.REMAINDER, help="""Command to run.""") 164*a9ac8606Spatrick return parser 165*a9ac8606Spatrick 166*a9ac8606Spatrick 167*a9ac8606Spatrickdef create_analyze_parser(from_build_command): 168*a9ac8606Spatrick """ Creates a parser for command-line arguments to 'analyze'. """ 169*a9ac8606Spatrick 170*a9ac8606Spatrick parser = create_default_parser() 171*a9ac8606Spatrick 172*a9ac8606Spatrick if from_build_command: 173*a9ac8606Spatrick parser_add_prefer_wrapper(parser) 174*a9ac8606Spatrick parser_add_compilers(parser) 175*a9ac8606Spatrick 176*a9ac8606Spatrick parser.add_argument( 177*a9ac8606Spatrick '--intercept-first', 178*a9ac8606Spatrick action='store_true', 179*a9ac8606Spatrick help="""Run the build commands first, intercept compiler 180*a9ac8606Spatrick calls and then run the static analyzer afterwards. 181*a9ac8606Spatrick Generally speaking it has better coverage on build commands. 182*a9ac8606Spatrick With '--override-compiler' it use compiler wrapper, but does 183*a9ac8606Spatrick not run the analyzer till the build is finished.""") 184*a9ac8606Spatrick else: 185*a9ac8606Spatrick parser_add_cdb(parser) 186*a9ac8606Spatrick 187*a9ac8606Spatrick parser.add_argument( 188*a9ac8606Spatrick '--status-bugs', 189*a9ac8606Spatrick action='store_true', 190*a9ac8606Spatrick help="""The exit status of '%(prog)s' is the same as the executed 191*a9ac8606Spatrick build command. This option ignores the build exit status and sets to 192*a9ac8606Spatrick be non zero if it found potential bugs or zero otherwise.""") 193*a9ac8606Spatrick parser.add_argument( 194*a9ac8606Spatrick '--exclude', 195*a9ac8606Spatrick metavar='<directory>', 196*a9ac8606Spatrick dest='excludes', 197*a9ac8606Spatrick action='append', 198*a9ac8606Spatrick default=[], 199*a9ac8606Spatrick help="""Do not run static analyzer against files found in this 200*a9ac8606Spatrick directory. (You can specify this option multiple times.) 201*a9ac8606Spatrick Could be useful when project contains 3rd party libraries.""") 202*a9ac8606Spatrick 203*a9ac8606Spatrick output = parser.add_argument_group('output control options') 204*a9ac8606Spatrick output.add_argument( 205*a9ac8606Spatrick '--output', 206*a9ac8606Spatrick '-o', 207*a9ac8606Spatrick metavar='<path>', 208*a9ac8606Spatrick default=tempfile.gettempdir(), 209*a9ac8606Spatrick help="""Specifies the output directory for analyzer reports. 210*a9ac8606Spatrick Subdirectory will be created if default directory is targeted.""") 211*a9ac8606Spatrick output.add_argument( 212*a9ac8606Spatrick '--keep-empty', 213*a9ac8606Spatrick action='store_true', 214*a9ac8606Spatrick help="""Don't remove the build results directory even if no issues 215*a9ac8606Spatrick were reported.""") 216*a9ac8606Spatrick output.add_argument( 217*a9ac8606Spatrick '--html-title', 218*a9ac8606Spatrick metavar='<title>', 219*a9ac8606Spatrick help="""Specify the title used on generated HTML pages. 220*a9ac8606Spatrick If not specified, a default title will be used.""") 221*a9ac8606Spatrick format_group = output.add_mutually_exclusive_group() 222*a9ac8606Spatrick format_group.add_argument( 223*a9ac8606Spatrick '--plist', 224*a9ac8606Spatrick '-plist', 225*a9ac8606Spatrick dest='output_format', 226*a9ac8606Spatrick const='plist', 227*a9ac8606Spatrick default='html', 228*a9ac8606Spatrick action='store_const', 229*a9ac8606Spatrick help="""Cause the results as a set of .plist files.""") 230*a9ac8606Spatrick format_group.add_argument( 231*a9ac8606Spatrick '--plist-html', 232*a9ac8606Spatrick '-plist-html', 233*a9ac8606Spatrick dest='output_format', 234*a9ac8606Spatrick const='plist-html', 235*a9ac8606Spatrick default='html', 236*a9ac8606Spatrick action='store_const', 237*a9ac8606Spatrick help="""Cause the results as a set of .html and .plist files.""") 238*a9ac8606Spatrick format_group.add_argument( 239*a9ac8606Spatrick '--plist-multi-file', 240*a9ac8606Spatrick '-plist-multi-file', 241*a9ac8606Spatrick dest='output_format', 242*a9ac8606Spatrick const='plist-multi-file', 243*a9ac8606Spatrick default='html', 244*a9ac8606Spatrick action='store_const', 245*a9ac8606Spatrick help="""Cause the results as a set of .plist files with extra 246*a9ac8606Spatrick information on related files.""") 247*a9ac8606Spatrick format_group.add_argument( 248*a9ac8606Spatrick '--sarif', 249*a9ac8606Spatrick '-sarif', 250*a9ac8606Spatrick dest='output_format', 251*a9ac8606Spatrick const='sarif', 252*a9ac8606Spatrick default='html', 253*a9ac8606Spatrick action='store_const', 254*a9ac8606Spatrick help="""Cause the results as a result.sarif file.""") 255*a9ac8606Spatrick format_group.add_argument( 256*a9ac8606Spatrick '--sarif-html', 257*a9ac8606Spatrick '-sarif-html', 258*a9ac8606Spatrick dest='output_format', 259*a9ac8606Spatrick const='sarif-html', 260*a9ac8606Spatrick default='html', 261*a9ac8606Spatrick action='store_const', 262*a9ac8606Spatrick help="""Cause the results as a result.sarif file and .html files.""") 263*a9ac8606Spatrick 264*a9ac8606Spatrick advanced = parser.add_argument_group('advanced options') 265*a9ac8606Spatrick advanced.add_argument( 266*a9ac8606Spatrick '--use-analyzer', 267*a9ac8606Spatrick metavar='<path>', 268*a9ac8606Spatrick dest='clang', 269*a9ac8606Spatrick default='clang', 270*a9ac8606Spatrick help="""'%(prog)s' uses the 'clang' executable relative to itself for 271*a9ac8606Spatrick static analysis. One can override this behavior with this option by 272*a9ac8606Spatrick using the 'clang' packaged with Xcode (on OS X) or from the PATH.""") 273*a9ac8606Spatrick advanced.add_argument( 274*a9ac8606Spatrick '--no-failure-reports', 275*a9ac8606Spatrick '-no-failure-reports', 276*a9ac8606Spatrick dest='output_failures', 277*a9ac8606Spatrick action='store_false', 278*a9ac8606Spatrick help="""Do not create a 'failures' subdirectory that includes analyzer 279*a9ac8606Spatrick crash reports and preprocessed source files.""") 280*a9ac8606Spatrick parser.add_argument( 281*a9ac8606Spatrick '--analyze-headers', 282*a9ac8606Spatrick action='store_true', 283*a9ac8606Spatrick help="""Also analyze functions in #included files. By default, such 284*a9ac8606Spatrick functions are skipped unless they are called by functions within the 285*a9ac8606Spatrick main source file.""") 286*a9ac8606Spatrick advanced.add_argument( 287*a9ac8606Spatrick '--stats', 288*a9ac8606Spatrick '-stats', 289*a9ac8606Spatrick action='store_true', 290*a9ac8606Spatrick help="""Generates visitation statistics for the project.""") 291*a9ac8606Spatrick advanced.add_argument( 292*a9ac8606Spatrick '--internal-stats', 293*a9ac8606Spatrick action='store_true', 294*a9ac8606Spatrick help="""Generate internal analyzer statistics.""") 295*a9ac8606Spatrick advanced.add_argument( 296*a9ac8606Spatrick '--maxloop', 297*a9ac8606Spatrick '-maxloop', 298*a9ac8606Spatrick metavar='<loop count>', 299*a9ac8606Spatrick type=int, 300*a9ac8606Spatrick help="""Specify the number of times a block can be visited before 301*a9ac8606Spatrick giving up. Increase for more comprehensive coverage at a cost of 302*a9ac8606Spatrick speed.""") 303*a9ac8606Spatrick advanced.add_argument( 304*a9ac8606Spatrick '--store', 305*a9ac8606Spatrick '-store', 306*a9ac8606Spatrick metavar='<model>', 307*a9ac8606Spatrick dest='store_model', 308*a9ac8606Spatrick choices=['region', 'basic'], 309*a9ac8606Spatrick help="""Specify the store model used by the analyzer. 'region' 310*a9ac8606Spatrick specifies a field- sensitive store model. 'basic' which is far less 311*a9ac8606Spatrick precise but can more quickly analyze code. 'basic' was the default 312*a9ac8606Spatrick store model for checker-0.221 and earlier.""") 313*a9ac8606Spatrick advanced.add_argument( 314*a9ac8606Spatrick '--constraints', 315*a9ac8606Spatrick '-constraints', 316*a9ac8606Spatrick metavar='<model>', 317*a9ac8606Spatrick dest='constraints_model', 318*a9ac8606Spatrick choices=['range', 'basic'], 319*a9ac8606Spatrick help="""Specify the constraint engine used by the analyzer. Specifying 320*a9ac8606Spatrick 'basic' uses a simpler, less powerful constraint model used by 321*a9ac8606Spatrick checker-0.160 and earlier.""") 322*a9ac8606Spatrick advanced.add_argument( 323*a9ac8606Spatrick '--analyzer-config', 324*a9ac8606Spatrick '-analyzer-config', 325*a9ac8606Spatrick metavar='<options>', 326*a9ac8606Spatrick help="""Provide options to pass through to the analyzer's 327*a9ac8606Spatrick -analyzer-config flag. Several options are separated with comma: 328*a9ac8606Spatrick 'key1=val1,key2=val2' 329*a9ac8606Spatrick 330*a9ac8606Spatrick Available options: 331*a9ac8606Spatrick stable-report-filename=true or false (default) 332*a9ac8606Spatrick 333*a9ac8606Spatrick Switch the page naming to: 334*a9ac8606Spatrick report-<filename>-<function/method name>-<id>.html 335*a9ac8606Spatrick instead of report-XXXXXX.html""") 336*a9ac8606Spatrick advanced.add_argument( 337*a9ac8606Spatrick '--force-analyze-debug-code', 338*a9ac8606Spatrick dest='force_debug', 339*a9ac8606Spatrick action='store_true', 340*a9ac8606Spatrick help="""Tells analyzer to enable assertions in code even if they were 341*a9ac8606Spatrick disabled during compilation, enabling more precise results.""") 342*a9ac8606Spatrick 343*a9ac8606Spatrick plugins = parser.add_argument_group('checker options') 344*a9ac8606Spatrick plugins.add_argument( 345*a9ac8606Spatrick '--load-plugin', 346*a9ac8606Spatrick '-load-plugin', 347*a9ac8606Spatrick metavar='<plugin library>', 348*a9ac8606Spatrick dest='plugins', 349*a9ac8606Spatrick action='append', 350*a9ac8606Spatrick help="""Loading external checkers using the clang plugin interface.""") 351*a9ac8606Spatrick plugins.add_argument( 352*a9ac8606Spatrick '--enable-checker', 353*a9ac8606Spatrick '-enable-checker', 354*a9ac8606Spatrick metavar='<checker name>', 355*a9ac8606Spatrick action=AppendCommaSeparated, 356*a9ac8606Spatrick help="""Enable specific checker.""") 357*a9ac8606Spatrick plugins.add_argument( 358*a9ac8606Spatrick '--disable-checker', 359*a9ac8606Spatrick '-disable-checker', 360*a9ac8606Spatrick metavar='<checker name>', 361*a9ac8606Spatrick action=AppendCommaSeparated, 362*a9ac8606Spatrick help="""Disable specific checker.""") 363*a9ac8606Spatrick plugins.add_argument( 364*a9ac8606Spatrick '--help-checkers', 365*a9ac8606Spatrick action='store_true', 366*a9ac8606Spatrick help="""A default group of checkers is run unless explicitly disabled. 367*a9ac8606Spatrick Exactly which checkers constitute the default group is a function of 368*a9ac8606Spatrick the operating system in use. These can be printed with this flag.""") 369*a9ac8606Spatrick plugins.add_argument( 370*a9ac8606Spatrick '--help-checkers-verbose', 371*a9ac8606Spatrick action='store_true', 372*a9ac8606Spatrick help="""Print all available checkers and mark the enabled ones.""") 373*a9ac8606Spatrick 374*a9ac8606Spatrick if from_build_command: 375*a9ac8606Spatrick parser.add_argument( 376*a9ac8606Spatrick dest='build', nargs=argparse.REMAINDER, help="""Command to run.""") 377*a9ac8606Spatrick else: 378*a9ac8606Spatrick ctu = parser.add_argument_group('cross translation unit analysis') 379*a9ac8606Spatrick ctu_mutex_group = ctu.add_mutually_exclusive_group() 380*a9ac8606Spatrick ctu_mutex_group.add_argument( 381*a9ac8606Spatrick '--ctu', 382*a9ac8606Spatrick action='store_const', 383*a9ac8606Spatrick const=CtuConfig(collect=True, analyze=True, 384*a9ac8606Spatrick dir='', extdef_map_cmd=''), 385*a9ac8606Spatrick dest='ctu_phases', 386*a9ac8606Spatrick help="""Perform cross translation unit (ctu) analysis (both collect 387*a9ac8606Spatrick and analyze phases) using default <ctu-dir> for temporary output. 388*a9ac8606Spatrick At the end of the analysis, the temporary directory is removed.""") 389*a9ac8606Spatrick ctu.add_argument( 390*a9ac8606Spatrick '--ctu-dir', 391*a9ac8606Spatrick metavar='<ctu-dir>', 392*a9ac8606Spatrick dest='ctu_dir', 393*a9ac8606Spatrick default='ctu-dir', 394*a9ac8606Spatrick help="""Defines the temporary directory used between ctu 395*a9ac8606Spatrick phases.""") 396*a9ac8606Spatrick ctu_mutex_group.add_argument( 397*a9ac8606Spatrick '--ctu-collect-only', 398*a9ac8606Spatrick action='store_const', 399*a9ac8606Spatrick const=CtuConfig(collect=True, analyze=False, 400*a9ac8606Spatrick dir='', extdef_map_cmd=''), 401*a9ac8606Spatrick dest='ctu_phases', 402*a9ac8606Spatrick help="""Perform only the collect phase of ctu. 403*a9ac8606Spatrick Keep <ctu-dir> for further use.""") 404*a9ac8606Spatrick ctu_mutex_group.add_argument( 405*a9ac8606Spatrick '--ctu-analyze-only', 406*a9ac8606Spatrick action='store_const', 407*a9ac8606Spatrick const=CtuConfig(collect=False, analyze=True, 408*a9ac8606Spatrick dir='', extdef_map_cmd=''), 409*a9ac8606Spatrick dest='ctu_phases', 410*a9ac8606Spatrick help="""Perform only the analyze phase of ctu. <ctu-dir> should be 411*a9ac8606Spatrick present and will not be removed after analysis.""") 412*a9ac8606Spatrick ctu.add_argument( 413*a9ac8606Spatrick '--use-extdef-map-cmd', 414*a9ac8606Spatrick metavar='<path>', 415*a9ac8606Spatrick dest='extdef_map_cmd', 416*a9ac8606Spatrick default='clang-extdef-mapping', 417*a9ac8606Spatrick help="""'%(prog)s' uses the 'clang-extdef-mapping' executable 418*a9ac8606Spatrick relative to itself for generating external definition maps for 419*a9ac8606Spatrick static analysis. One can override this behavior with this option 420*a9ac8606Spatrick by using the 'clang-extdef-mapping' packaged with Xcode (on OS X) 421*a9ac8606Spatrick or from the PATH.""") 422*a9ac8606Spatrick return parser 423*a9ac8606Spatrick 424*a9ac8606Spatrick 425*a9ac8606Spatrickdef create_default_parser(): 426*a9ac8606Spatrick """ Creates command line parser for all build wrapper commands. """ 427*a9ac8606Spatrick 428*a9ac8606Spatrick parser = argparse.ArgumentParser( 429*a9ac8606Spatrick formatter_class=argparse.ArgumentDefaultsHelpFormatter) 430*a9ac8606Spatrick 431*a9ac8606Spatrick parser.add_argument( 432*a9ac8606Spatrick '--verbose', 433*a9ac8606Spatrick '-v', 434*a9ac8606Spatrick action='count', 435*a9ac8606Spatrick default=0, 436*a9ac8606Spatrick help="""Enable verbose output from '%(prog)s'. A second, third and 437*a9ac8606Spatrick fourth flags increases verbosity.""") 438*a9ac8606Spatrick return parser 439*a9ac8606Spatrick 440*a9ac8606Spatrick 441*a9ac8606Spatrickdef parser_add_cdb(parser): 442*a9ac8606Spatrick parser.add_argument( 443*a9ac8606Spatrick '--cdb', 444*a9ac8606Spatrick metavar='<file>', 445*a9ac8606Spatrick default="compile_commands.json", 446*a9ac8606Spatrick help="""The JSON compilation database.""") 447*a9ac8606Spatrick 448*a9ac8606Spatrick 449*a9ac8606Spatrickdef parser_add_prefer_wrapper(parser): 450*a9ac8606Spatrick parser.add_argument( 451*a9ac8606Spatrick '--override-compiler', 452*a9ac8606Spatrick action='store_true', 453*a9ac8606Spatrick help="""Always resort to the compiler wrapper even when better 454*a9ac8606Spatrick intercept methods are available.""") 455*a9ac8606Spatrick 456*a9ac8606Spatrick 457*a9ac8606Spatrickdef parser_add_compilers(parser): 458*a9ac8606Spatrick parser.add_argument( 459*a9ac8606Spatrick '--use-cc', 460*a9ac8606Spatrick metavar='<path>', 461*a9ac8606Spatrick dest='cc', 462*a9ac8606Spatrick default=os.getenv('CC', 'cc'), 463*a9ac8606Spatrick help="""When '%(prog)s' analyzes a project by interposing a compiler 464*a9ac8606Spatrick wrapper, which executes a real compiler for compilation and do other 465*a9ac8606Spatrick tasks (record the compiler invocation). Because of this interposing, 466*a9ac8606Spatrick '%(prog)s' does not know what compiler your project normally uses. 467*a9ac8606Spatrick Instead, it simply overrides the CC environment variable, and guesses 468*a9ac8606Spatrick your default compiler. 469*a9ac8606Spatrick 470*a9ac8606Spatrick If you need '%(prog)s' to use a specific compiler for *compilation* 471*a9ac8606Spatrick then you can use this option to specify a path to that compiler.""") 472*a9ac8606Spatrick parser.add_argument( 473*a9ac8606Spatrick '--use-c++', 474*a9ac8606Spatrick metavar='<path>', 475*a9ac8606Spatrick dest='cxx', 476*a9ac8606Spatrick default=os.getenv('CXX', 'c++'), 477*a9ac8606Spatrick help="""This is the same as "--use-cc" but for C++ code.""") 478*a9ac8606Spatrick 479*a9ac8606Spatrick 480*a9ac8606Spatrickclass AppendCommaSeparated(argparse.Action): 481*a9ac8606Spatrick """ argparse Action class to support multiple comma separated lists. """ 482*a9ac8606Spatrick 483*a9ac8606Spatrick def __call__(self, __parser, namespace, values, __option_string): 484*a9ac8606Spatrick # getattr(obj, attr, default) does not really returns default but none 485*a9ac8606Spatrick if getattr(namespace, self.dest, None) is None: 486*a9ac8606Spatrick setattr(namespace, self.dest, []) 487*a9ac8606Spatrick # once it's fixed we can use as expected 488*a9ac8606Spatrick actual = getattr(namespace, self.dest) 489*a9ac8606Spatrick actual.extend(values.split(',')) 490*a9ac8606Spatrick setattr(namespace, self.dest, actual) 491*a9ac8606Spatrick 492*a9ac8606Spatrick 493*a9ac8606Spatrickdef print_active_checkers(checkers): 494*a9ac8606Spatrick """ Print active checkers to stdout. """ 495*a9ac8606Spatrick 496*a9ac8606Spatrick for name in sorted(name for name, (_, active) in checkers.items() 497*a9ac8606Spatrick if active): 498*a9ac8606Spatrick print(name) 499*a9ac8606Spatrick 500*a9ac8606Spatrick 501*a9ac8606Spatrickdef print_checkers(checkers): 502*a9ac8606Spatrick """ Print verbose checker help to stdout. """ 503*a9ac8606Spatrick 504*a9ac8606Spatrick print('') 505*a9ac8606Spatrick print('available checkers:') 506*a9ac8606Spatrick print('') 507*a9ac8606Spatrick for name in sorted(checkers.keys()): 508*a9ac8606Spatrick description, active = checkers[name] 509*a9ac8606Spatrick prefix = '+' if active else ' ' 510*a9ac8606Spatrick if len(name) > 30: 511*a9ac8606Spatrick print(' {0} {1}'.format(prefix, name)) 512*a9ac8606Spatrick print(' ' * 35 + description) 513*a9ac8606Spatrick else: 514*a9ac8606Spatrick print(' {0} {1: <30} {2}'.format(prefix, name, description)) 515*a9ac8606Spatrick print('') 516*a9ac8606Spatrick print('NOTE: "+" indicates that an analysis is enabled by default.') 517*a9ac8606Spatrick print('') 518