17330f729Sjoerg# -*- coding: utf-8 -*- 27330f729Sjoerg# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 37330f729Sjoerg# See https://llvm.org/LICENSE.txt for license information. 47330f729Sjoerg# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 57330f729Sjoerg""" This module parses and validates arguments for command-line interfaces. 67330f729Sjoerg 77330f729SjoergIt uses argparse module to create the command line parser. (This library is 87330f729Sjoergin the standard python library since 3.2 and backported to 2.7, but not 97330f729Sjoergearlier.) 107330f729Sjoerg 117330f729SjoergIt also implements basic validation methods, related to the command. 127330f729SjoergValidations are mostly calling specific help methods, or mangling values. 137330f729Sjoerg""" 147330f729Sjoergfrom __future__ import absolute_import, division, print_function 157330f729Sjoerg 167330f729Sjoergimport os 177330f729Sjoergimport sys 187330f729Sjoergimport argparse 197330f729Sjoergimport logging 207330f729Sjoergimport tempfile 217330f729Sjoergfrom libscanbuild import reconfigure_logging, CtuConfig 227330f729Sjoergfrom libscanbuild.clang import get_checkers, is_ctu_capable 237330f729Sjoerg 247330f729Sjoerg__all__ = ['parse_args_for_intercept_build', 'parse_args_for_analyze_build', 257330f729Sjoerg 'parse_args_for_scan_build'] 267330f729Sjoerg 277330f729Sjoerg 287330f729Sjoergdef parse_args_for_intercept_build(): 297330f729Sjoerg """ Parse and validate command-line arguments for intercept-build. """ 307330f729Sjoerg 317330f729Sjoerg parser = create_intercept_parser() 327330f729Sjoerg args = parser.parse_args() 337330f729Sjoerg 347330f729Sjoerg reconfigure_logging(args.verbose) 357330f729Sjoerg logging.debug('Raw arguments %s', sys.argv) 367330f729Sjoerg 377330f729Sjoerg # short validation logic 387330f729Sjoerg if not args.build: 397330f729Sjoerg parser.error(message='missing build command') 407330f729Sjoerg 417330f729Sjoerg logging.debug('Parsed arguments: %s', args) 427330f729Sjoerg return args 437330f729Sjoerg 447330f729Sjoerg 457330f729Sjoergdef parse_args_for_analyze_build(): 467330f729Sjoerg """ Parse and validate command-line arguments for analyze-build. """ 477330f729Sjoerg 487330f729Sjoerg from_build_command = False 497330f729Sjoerg parser = create_analyze_parser(from_build_command) 507330f729Sjoerg args = parser.parse_args() 517330f729Sjoerg 527330f729Sjoerg reconfigure_logging(args.verbose) 537330f729Sjoerg logging.debug('Raw arguments %s', sys.argv) 547330f729Sjoerg 557330f729Sjoerg normalize_args_for_analyze(args, from_build_command) 567330f729Sjoerg validate_args_for_analyze(parser, args, from_build_command) 577330f729Sjoerg logging.debug('Parsed arguments: %s', args) 587330f729Sjoerg return args 597330f729Sjoerg 607330f729Sjoerg 617330f729Sjoergdef parse_args_for_scan_build(): 627330f729Sjoerg """ Parse and validate command-line arguments for scan-build. """ 637330f729Sjoerg 647330f729Sjoerg from_build_command = True 657330f729Sjoerg parser = create_analyze_parser(from_build_command) 667330f729Sjoerg args = parser.parse_args() 677330f729Sjoerg 687330f729Sjoerg reconfigure_logging(args.verbose) 697330f729Sjoerg logging.debug('Raw arguments %s', sys.argv) 707330f729Sjoerg 717330f729Sjoerg normalize_args_for_analyze(args, from_build_command) 727330f729Sjoerg validate_args_for_analyze(parser, args, from_build_command) 737330f729Sjoerg logging.debug('Parsed arguments: %s', args) 747330f729Sjoerg return args 757330f729Sjoerg 767330f729Sjoerg 777330f729Sjoergdef normalize_args_for_analyze(args, from_build_command): 787330f729Sjoerg """ Normalize parsed arguments for analyze-build and scan-build. 797330f729Sjoerg 807330f729Sjoerg :param args: Parsed argument object. (Will be mutated.) 817330f729Sjoerg :param from_build_command: Boolean value tells is the command suppose 827330f729Sjoerg to run the analyzer against a build command or a compilation db. """ 837330f729Sjoerg 847330f729Sjoerg # make plugins always a list. (it might be None when not specified.) 857330f729Sjoerg if args.plugins is None: 867330f729Sjoerg args.plugins = [] 877330f729Sjoerg 887330f729Sjoerg # make exclude directory list unique and absolute. 897330f729Sjoerg uniq_excludes = set(os.path.abspath(entry) for entry in args.excludes) 907330f729Sjoerg args.excludes = list(uniq_excludes) 917330f729Sjoerg 927330f729Sjoerg # because shared codes for all tools, some common used methods are 937330f729Sjoerg # expecting some argument to be present. so, instead of query the args 947330f729Sjoerg # object about the presence of the flag, we fake it here. to make those 957330f729Sjoerg # methods more readable. (it's an arguable choice, took it only for those 967330f729Sjoerg # which have good default value.) 977330f729Sjoerg if from_build_command: 987330f729Sjoerg # add cdb parameter invisibly to make report module working. 997330f729Sjoerg args.cdb = 'compile_commands.json' 1007330f729Sjoerg 1017330f729Sjoerg # Make ctu_dir an abspath as it is needed inside clang 1027330f729Sjoerg if not from_build_command and hasattr(args, 'ctu_phases') \ 1037330f729Sjoerg and hasattr(args.ctu_phases, 'dir'): 1047330f729Sjoerg args.ctu_dir = os.path.abspath(args.ctu_dir) 1057330f729Sjoerg 1067330f729Sjoerg 1077330f729Sjoergdef validate_args_for_analyze(parser, args, from_build_command): 1087330f729Sjoerg """ Command line parsing is done by the argparse module, but semantic 1097330f729Sjoerg validation still needs to be done. This method is doing it for 1107330f729Sjoerg analyze-build and scan-build commands. 1117330f729Sjoerg 1127330f729Sjoerg :param parser: The command line parser object. 1137330f729Sjoerg :param args: Parsed argument object. 1147330f729Sjoerg :param from_build_command: Boolean value tells is the command suppose 1157330f729Sjoerg to run the analyzer against a build command or a compilation db. 1167330f729Sjoerg :return: No return value, but this call might throw when validation 1177330f729Sjoerg fails. """ 1187330f729Sjoerg 1197330f729Sjoerg if args.help_checkers_verbose: 1207330f729Sjoerg print_checkers(get_checkers(args.clang, args.plugins)) 1217330f729Sjoerg parser.exit(status=0) 1227330f729Sjoerg elif args.help_checkers: 1237330f729Sjoerg print_active_checkers(get_checkers(args.clang, args.plugins)) 1247330f729Sjoerg parser.exit(status=0) 1257330f729Sjoerg elif from_build_command and not args.build: 1267330f729Sjoerg parser.error(message='missing build command') 1277330f729Sjoerg elif not from_build_command and not os.path.exists(args.cdb): 1287330f729Sjoerg parser.error(message='compilation database is missing') 1297330f729Sjoerg 1307330f729Sjoerg # If the user wants CTU mode 1317330f729Sjoerg if not from_build_command and hasattr(args, 'ctu_phases') \ 1327330f729Sjoerg and hasattr(args.ctu_phases, 'dir'): 1337330f729Sjoerg # If CTU analyze_only, the input directory should exist 1347330f729Sjoerg if args.ctu_phases.analyze and not args.ctu_phases.collect \ 1357330f729Sjoerg and not os.path.exists(args.ctu_dir): 1367330f729Sjoerg parser.error(message='missing CTU directory') 1377330f729Sjoerg # Check CTU capability via checking clang-extdef-mapping 1387330f729Sjoerg if not is_ctu_capable(args.extdef_map_cmd): 1397330f729Sjoerg parser.error(message="""This version of clang does not support CTU 1407330f729Sjoerg functionality or clang-extdef-mapping command not found.""") 1417330f729Sjoerg 1427330f729Sjoerg 1437330f729Sjoergdef create_intercept_parser(): 1447330f729Sjoerg """ Creates a parser for command-line arguments to 'intercept'. """ 1457330f729Sjoerg 1467330f729Sjoerg parser = create_default_parser() 1477330f729Sjoerg parser_add_cdb(parser) 1487330f729Sjoerg 1497330f729Sjoerg parser_add_prefer_wrapper(parser) 1507330f729Sjoerg parser_add_compilers(parser) 1517330f729Sjoerg 1527330f729Sjoerg advanced = parser.add_argument_group('advanced options') 1537330f729Sjoerg group = advanced.add_mutually_exclusive_group() 1547330f729Sjoerg group.add_argument( 1557330f729Sjoerg '--append', 1567330f729Sjoerg action='store_true', 1577330f729Sjoerg help="""Extend existing compilation database with new entries. 1587330f729Sjoerg Duplicate entries are detected and not present in the final output. 1597330f729Sjoerg The output is not continuously updated, it's done when the build 1607330f729Sjoerg command finished. """) 1617330f729Sjoerg 1627330f729Sjoerg parser.add_argument( 1637330f729Sjoerg dest='build', nargs=argparse.REMAINDER, help="""Command to run.""") 1647330f729Sjoerg return parser 1657330f729Sjoerg 1667330f729Sjoerg 1677330f729Sjoergdef create_analyze_parser(from_build_command): 1687330f729Sjoerg """ Creates a parser for command-line arguments to 'analyze'. """ 1697330f729Sjoerg 1707330f729Sjoerg parser = create_default_parser() 1717330f729Sjoerg 1727330f729Sjoerg if from_build_command: 1737330f729Sjoerg parser_add_prefer_wrapper(parser) 1747330f729Sjoerg parser_add_compilers(parser) 1757330f729Sjoerg 1767330f729Sjoerg parser.add_argument( 1777330f729Sjoerg '--intercept-first', 1787330f729Sjoerg action='store_true', 1797330f729Sjoerg help="""Run the build commands first, intercept compiler 1807330f729Sjoerg calls and then run the static analyzer afterwards. 1817330f729Sjoerg Generally speaking it has better coverage on build commands. 1827330f729Sjoerg With '--override-compiler' it use compiler wrapper, but does 1837330f729Sjoerg not run the analyzer till the build is finished.""") 1847330f729Sjoerg else: 1857330f729Sjoerg parser_add_cdb(parser) 1867330f729Sjoerg 1877330f729Sjoerg parser.add_argument( 1887330f729Sjoerg '--status-bugs', 1897330f729Sjoerg action='store_true', 1907330f729Sjoerg help="""The exit status of '%(prog)s' is the same as the executed 1917330f729Sjoerg build command. This option ignores the build exit status and sets to 1927330f729Sjoerg be non zero if it found potential bugs or zero otherwise.""") 1937330f729Sjoerg parser.add_argument( 1947330f729Sjoerg '--exclude', 1957330f729Sjoerg metavar='<directory>', 1967330f729Sjoerg dest='excludes', 1977330f729Sjoerg action='append', 1987330f729Sjoerg default=[], 1997330f729Sjoerg help="""Do not run static analyzer against files found in this 2007330f729Sjoerg directory. (You can specify this option multiple times.) 2017330f729Sjoerg Could be useful when project contains 3rd party libraries.""") 2027330f729Sjoerg 2037330f729Sjoerg output = parser.add_argument_group('output control options') 2047330f729Sjoerg output.add_argument( 2057330f729Sjoerg '--output', 2067330f729Sjoerg '-o', 2077330f729Sjoerg metavar='<path>', 2087330f729Sjoerg default=tempfile.gettempdir(), 2097330f729Sjoerg help="""Specifies the output directory for analyzer reports. 2107330f729Sjoerg Subdirectory will be created if default directory is targeted.""") 2117330f729Sjoerg output.add_argument( 2127330f729Sjoerg '--keep-empty', 2137330f729Sjoerg action='store_true', 2147330f729Sjoerg help="""Don't remove the build results directory even if no issues 2157330f729Sjoerg were reported.""") 2167330f729Sjoerg output.add_argument( 2177330f729Sjoerg '--html-title', 2187330f729Sjoerg metavar='<title>', 2197330f729Sjoerg help="""Specify the title used on generated HTML pages. 2207330f729Sjoerg If not specified, a default title will be used.""") 2217330f729Sjoerg format_group = output.add_mutually_exclusive_group() 2227330f729Sjoerg format_group.add_argument( 2237330f729Sjoerg '--plist', 2247330f729Sjoerg '-plist', 2257330f729Sjoerg dest='output_format', 2267330f729Sjoerg const='plist', 2277330f729Sjoerg default='html', 2287330f729Sjoerg action='store_const', 2297330f729Sjoerg help="""Cause the results as a set of .plist files.""") 2307330f729Sjoerg format_group.add_argument( 2317330f729Sjoerg '--plist-html', 2327330f729Sjoerg '-plist-html', 2337330f729Sjoerg dest='output_format', 2347330f729Sjoerg const='plist-html', 2357330f729Sjoerg default='html', 2367330f729Sjoerg action='store_const', 2377330f729Sjoerg help="""Cause the results as a set of .html and .plist files.""") 2387330f729Sjoerg format_group.add_argument( 2397330f729Sjoerg '--plist-multi-file', 2407330f729Sjoerg '-plist-multi-file', 2417330f729Sjoerg dest='output_format', 2427330f729Sjoerg const='plist-multi-file', 2437330f729Sjoerg default='html', 2447330f729Sjoerg action='store_const', 2457330f729Sjoerg help="""Cause the results as a set of .plist files with extra 2467330f729Sjoerg information on related files.""") 247*e038c9c4Sjoerg format_group.add_argument( 248*e038c9c4Sjoerg '--sarif', 249*e038c9c4Sjoerg '-sarif', 250*e038c9c4Sjoerg dest='output_format', 251*e038c9c4Sjoerg const='sarif', 252*e038c9c4Sjoerg default='html', 253*e038c9c4Sjoerg action='store_const', 254*e038c9c4Sjoerg help="""Cause the results as a result.sarif file.""") 255*e038c9c4Sjoerg format_group.add_argument( 256*e038c9c4Sjoerg '--sarif-html', 257*e038c9c4Sjoerg '-sarif-html', 258*e038c9c4Sjoerg dest='output_format', 259*e038c9c4Sjoerg const='sarif-html', 260*e038c9c4Sjoerg default='html', 261*e038c9c4Sjoerg action='store_const', 262*e038c9c4Sjoerg help="""Cause the results as a result.sarif file and .html files.""") 2637330f729Sjoerg 2647330f729Sjoerg advanced = parser.add_argument_group('advanced options') 2657330f729Sjoerg advanced.add_argument( 2667330f729Sjoerg '--use-analyzer', 2677330f729Sjoerg metavar='<path>', 2687330f729Sjoerg dest='clang', 2697330f729Sjoerg default='clang', 2707330f729Sjoerg help="""'%(prog)s' uses the 'clang' executable relative to itself for 2717330f729Sjoerg static analysis. One can override this behavior with this option by 2727330f729Sjoerg using the 'clang' packaged with Xcode (on OS X) or from the PATH.""") 2737330f729Sjoerg advanced.add_argument( 2747330f729Sjoerg '--no-failure-reports', 2757330f729Sjoerg '-no-failure-reports', 2767330f729Sjoerg dest='output_failures', 2777330f729Sjoerg action='store_false', 2787330f729Sjoerg help="""Do not create a 'failures' subdirectory that includes analyzer 2797330f729Sjoerg crash reports and preprocessed source files.""") 2807330f729Sjoerg parser.add_argument( 2817330f729Sjoerg '--analyze-headers', 2827330f729Sjoerg action='store_true', 2837330f729Sjoerg help="""Also analyze functions in #included files. By default, such 2847330f729Sjoerg functions are skipped unless they are called by functions within the 2857330f729Sjoerg main source file.""") 2867330f729Sjoerg advanced.add_argument( 2877330f729Sjoerg '--stats', 2887330f729Sjoerg '-stats', 2897330f729Sjoerg action='store_true', 2907330f729Sjoerg help="""Generates visitation statistics for the project.""") 2917330f729Sjoerg advanced.add_argument( 2927330f729Sjoerg '--internal-stats', 2937330f729Sjoerg action='store_true', 2947330f729Sjoerg help="""Generate internal analyzer statistics.""") 2957330f729Sjoerg advanced.add_argument( 2967330f729Sjoerg '--maxloop', 2977330f729Sjoerg '-maxloop', 2987330f729Sjoerg metavar='<loop count>', 2997330f729Sjoerg type=int, 3007330f729Sjoerg help="""Specify the number of times a block can be visited before 3017330f729Sjoerg giving up. Increase for more comprehensive coverage at a cost of 3027330f729Sjoerg speed.""") 3037330f729Sjoerg advanced.add_argument( 3047330f729Sjoerg '--store', 3057330f729Sjoerg '-store', 3067330f729Sjoerg metavar='<model>', 3077330f729Sjoerg dest='store_model', 3087330f729Sjoerg choices=['region', 'basic'], 3097330f729Sjoerg help="""Specify the store model used by the analyzer. 'region' 3107330f729Sjoerg specifies a field- sensitive store model. 'basic' which is far less 3117330f729Sjoerg precise but can more quickly analyze code. 'basic' was the default 3127330f729Sjoerg store model for checker-0.221 and earlier.""") 3137330f729Sjoerg advanced.add_argument( 3147330f729Sjoerg '--constraints', 3157330f729Sjoerg '-constraints', 3167330f729Sjoerg metavar='<model>', 3177330f729Sjoerg dest='constraints_model', 3187330f729Sjoerg choices=['range', 'basic'], 3197330f729Sjoerg help="""Specify the constraint engine used by the analyzer. Specifying 3207330f729Sjoerg 'basic' uses a simpler, less powerful constraint model used by 3217330f729Sjoerg checker-0.160 and earlier.""") 3227330f729Sjoerg advanced.add_argument( 3237330f729Sjoerg '--analyzer-config', 3247330f729Sjoerg '-analyzer-config', 3257330f729Sjoerg metavar='<options>', 3267330f729Sjoerg help="""Provide options to pass through to the analyzer's 3277330f729Sjoerg -analyzer-config flag. Several options are separated with comma: 3287330f729Sjoerg 'key1=val1,key2=val2' 3297330f729Sjoerg 3307330f729Sjoerg Available options: 3317330f729Sjoerg stable-report-filename=true or false (default) 3327330f729Sjoerg 3337330f729Sjoerg Switch the page naming to: 3347330f729Sjoerg report-<filename>-<function/method name>-<id>.html 3357330f729Sjoerg instead of report-XXXXXX.html""") 3367330f729Sjoerg advanced.add_argument( 3377330f729Sjoerg '--force-analyze-debug-code', 3387330f729Sjoerg dest='force_debug', 3397330f729Sjoerg action='store_true', 3407330f729Sjoerg help="""Tells analyzer to enable assertions in code even if they were 3417330f729Sjoerg disabled during compilation, enabling more precise results.""") 3427330f729Sjoerg 3437330f729Sjoerg plugins = parser.add_argument_group('checker options') 3447330f729Sjoerg plugins.add_argument( 3457330f729Sjoerg '--load-plugin', 3467330f729Sjoerg '-load-plugin', 3477330f729Sjoerg metavar='<plugin library>', 3487330f729Sjoerg dest='plugins', 3497330f729Sjoerg action='append', 3507330f729Sjoerg help="""Loading external checkers using the clang plugin interface.""") 3517330f729Sjoerg plugins.add_argument( 3527330f729Sjoerg '--enable-checker', 3537330f729Sjoerg '-enable-checker', 3547330f729Sjoerg metavar='<checker name>', 3557330f729Sjoerg action=AppendCommaSeparated, 3567330f729Sjoerg help="""Enable specific checker.""") 3577330f729Sjoerg plugins.add_argument( 3587330f729Sjoerg '--disable-checker', 3597330f729Sjoerg '-disable-checker', 3607330f729Sjoerg metavar='<checker name>', 3617330f729Sjoerg action=AppendCommaSeparated, 3627330f729Sjoerg help="""Disable specific checker.""") 3637330f729Sjoerg plugins.add_argument( 3647330f729Sjoerg '--help-checkers', 3657330f729Sjoerg action='store_true', 3667330f729Sjoerg help="""A default group of checkers is run unless explicitly disabled. 3677330f729Sjoerg Exactly which checkers constitute the default group is a function of 3687330f729Sjoerg the operating system in use. These can be printed with this flag.""") 3697330f729Sjoerg plugins.add_argument( 3707330f729Sjoerg '--help-checkers-verbose', 3717330f729Sjoerg action='store_true', 3727330f729Sjoerg help="""Print all available checkers and mark the enabled ones.""") 3737330f729Sjoerg 3747330f729Sjoerg if from_build_command: 3757330f729Sjoerg parser.add_argument( 3767330f729Sjoerg dest='build', nargs=argparse.REMAINDER, help="""Command to run.""") 3777330f729Sjoerg else: 3787330f729Sjoerg ctu = parser.add_argument_group('cross translation unit analysis') 3797330f729Sjoerg ctu_mutex_group = ctu.add_mutually_exclusive_group() 3807330f729Sjoerg ctu_mutex_group.add_argument( 3817330f729Sjoerg '--ctu', 3827330f729Sjoerg action='store_const', 3837330f729Sjoerg const=CtuConfig(collect=True, analyze=True, 3847330f729Sjoerg dir='', extdef_map_cmd=''), 3857330f729Sjoerg dest='ctu_phases', 3867330f729Sjoerg help="""Perform cross translation unit (ctu) analysis (both collect 3877330f729Sjoerg and analyze phases) using default <ctu-dir> for temporary output. 3887330f729Sjoerg At the end of the analysis, the temporary directory is removed.""") 3897330f729Sjoerg ctu.add_argument( 3907330f729Sjoerg '--ctu-dir', 3917330f729Sjoerg metavar='<ctu-dir>', 3927330f729Sjoerg dest='ctu_dir', 3937330f729Sjoerg default='ctu-dir', 3947330f729Sjoerg help="""Defines the temporary directory used between ctu 3957330f729Sjoerg phases.""") 3967330f729Sjoerg ctu_mutex_group.add_argument( 3977330f729Sjoerg '--ctu-collect-only', 3987330f729Sjoerg action='store_const', 3997330f729Sjoerg const=CtuConfig(collect=True, analyze=False, 4007330f729Sjoerg dir='', extdef_map_cmd=''), 4017330f729Sjoerg dest='ctu_phases', 4027330f729Sjoerg help="""Perform only the collect phase of ctu. 4037330f729Sjoerg Keep <ctu-dir> for further use.""") 4047330f729Sjoerg ctu_mutex_group.add_argument( 4057330f729Sjoerg '--ctu-analyze-only', 4067330f729Sjoerg action='store_const', 4077330f729Sjoerg const=CtuConfig(collect=False, analyze=True, 4087330f729Sjoerg dir='', extdef_map_cmd=''), 4097330f729Sjoerg dest='ctu_phases', 4107330f729Sjoerg help="""Perform only the analyze phase of ctu. <ctu-dir> should be 4117330f729Sjoerg present and will not be removed after analysis.""") 4127330f729Sjoerg ctu.add_argument( 4137330f729Sjoerg '--use-extdef-map-cmd', 4147330f729Sjoerg metavar='<path>', 4157330f729Sjoerg dest='extdef_map_cmd', 4167330f729Sjoerg default='clang-extdef-mapping', 4177330f729Sjoerg help="""'%(prog)s' uses the 'clang-extdef-mapping' executable 4187330f729Sjoerg relative to itself for generating external definition maps for 4197330f729Sjoerg static analysis. One can override this behavior with this option 4207330f729Sjoerg by using the 'clang-extdef-mapping' packaged with Xcode (on OS X) 4217330f729Sjoerg or from the PATH.""") 4227330f729Sjoerg return parser 4237330f729Sjoerg 4247330f729Sjoerg 4257330f729Sjoergdef create_default_parser(): 4267330f729Sjoerg """ Creates command line parser for all build wrapper commands. """ 4277330f729Sjoerg 4287330f729Sjoerg parser = argparse.ArgumentParser( 4297330f729Sjoerg formatter_class=argparse.ArgumentDefaultsHelpFormatter) 4307330f729Sjoerg 4317330f729Sjoerg parser.add_argument( 4327330f729Sjoerg '--verbose', 4337330f729Sjoerg '-v', 4347330f729Sjoerg action='count', 4357330f729Sjoerg default=0, 4367330f729Sjoerg help="""Enable verbose output from '%(prog)s'. A second, third and 4377330f729Sjoerg fourth flags increases verbosity.""") 4387330f729Sjoerg return parser 4397330f729Sjoerg 4407330f729Sjoerg 4417330f729Sjoergdef parser_add_cdb(parser): 4427330f729Sjoerg parser.add_argument( 4437330f729Sjoerg '--cdb', 4447330f729Sjoerg metavar='<file>', 4457330f729Sjoerg default="compile_commands.json", 4467330f729Sjoerg help="""The JSON compilation database.""") 4477330f729Sjoerg 4487330f729Sjoerg 4497330f729Sjoergdef parser_add_prefer_wrapper(parser): 4507330f729Sjoerg parser.add_argument( 4517330f729Sjoerg '--override-compiler', 4527330f729Sjoerg action='store_true', 4537330f729Sjoerg help="""Always resort to the compiler wrapper even when better 4547330f729Sjoerg intercept methods are available.""") 4557330f729Sjoerg 4567330f729Sjoerg 4577330f729Sjoergdef parser_add_compilers(parser): 4587330f729Sjoerg parser.add_argument( 4597330f729Sjoerg '--use-cc', 4607330f729Sjoerg metavar='<path>', 4617330f729Sjoerg dest='cc', 4627330f729Sjoerg default=os.getenv('CC', 'cc'), 4637330f729Sjoerg help="""When '%(prog)s' analyzes a project by interposing a compiler 4647330f729Sjoerg wrapper, which executes a real compiler for compilation and do other 4657330f729Sjoerg tasks (record the compiler invocation). Because of this interposing, 4667330f729Sjoerg '%(prog)s' does not know what compiler your project normally uses. 4677330f729Sjoerg Instead, it simply overrides the CC environment variable, and guesses 4687330f729Sjoerg your default compiler. 4697330f729Sjoerg 4707330f729Sjoerg If you need '%(prog)s' to use a specific compiler for *compilation* 4717330f729Sjoerg then you can use this option to specify a path to that compiler.""") 4727330f729Sjoerg parser.add_argument( 4737330f729Sjoerg '--use-c++', 4747330f729Sjoerg metavar='<path>', 4757330f729Sjoerg dest='cxx', 4767330f729Sjoerg default=os.getenv('CXX', 'c++'), 4777330f729Sjoerg help="""This is the same as "--use-cc" but for C++ code.""") 4787330f729Sjoerg 4797330f729Sjoerg 4807330f729Sjoergclass AppendCommaSeparated(argparse.Action): 4817330f729Sjoerg """ argparse Action class to support multiple comma separated lists. """ 4827330f729Sjoerg 4837330f729Sjoerg def __call__(self, __parser, namespace, values, __option_string): 4847330f729Sjoerg # getattr(obj, attr, default) does not really returns default but none 4857330f729Sjoerg if getattr(namespace, self.dest, None) is None: 4867330f729Sjoerg setattr(namespace, self.dest, []) 4877330f729Sjoerg # once it's fixed we can use as expected 4887330f729Sjoerg actual = getattr(namespace, self.dest) 4897330f729Sjoerg actual.extend(values.split(',')) 4907330f729Sjoerg setattr(namespace, self.dest, actual) 4917330f729Sjoerg 4927330f729Sjoerg 4937330f729Sjoergdef print_active_checkers(checkers): 4947330f729Sjoerg """ Print active checkers to stdout. """ 4957330f729Sjoerg 4967330f729Sjoerg for name in sorted(name for name, (_, active) in checkers.items() 4977330f729Sjoerg if active): 4987330f729Sjoerg print(name) 4997330f729Sjoerg 5007330f729Sjoerg 5017330f729Sjoergdef print_checkers(checkers): 5027330f729Sjoerg """ Print verbose checker help to stdout. """ 5037330f729Sjoerg 5047330f729Sjoerg print('') 5057330f729Sjoerg print('available checkers:') 5067330f729Sjoerg print('') 5077330f729Sjoerg for name in sorted(checkers.keys()): 5087330f729Sjoerg description, active = checkers[name] 5097330f729Sjoerg prefix = '+' if active else ' ' 5107330f729Sjoerg if len(name) > 30: 5117330f729Sjoerg print(' {0} {1}'.format(prefix, name)) 5127330f729Sjoerg print(' ' * 35 + description) 5137330f729Sjoerg else: 5147330f729Sjoerg print(' {0} {1: <30} {2}'.format(prefix, name, description)) 5157330f729Sjoerg print('') 5167330f729Sjoerg print('NOTE: "+" indicates that an analysis is enabled by default.') 5177330f729Sjoerg print('') 518