diff --git a/infer/lib/capture/make.py b/infer/lib/capture/make.py index 7116b439a..0564caf15 100644 --- a/infer/lib/capture/make.py +++ b/infer/lib/capture/make.py @@ -1,8 +1,9 @@ -import argparse import os import subprocess import traceback +import util + MODULE_NAME = 'make/cc/clang/gcc' MODULE_DESCRIPTION = '''Run analysis of code built with commands like: make [target] @@ -24,51 +25,8 @@ def mkdir_if_not_exists(path): if not os.path.exists(path): os.mkdir(path) - -def create_argparser(group_name=MODULE_NAME): - """This defines the set of arguments that get added by this module to the - set of global args defined in the infer top-level module - Do not use this function directly, it should be invoked by the infer - top-level module""" - parser = argparse.ArgumentParser(add_help=False) - group = parser.add_argument_group( - "{grp} module".format(grp=MODULE_NAME), - description=MODULE_DESCRIPTION, - ) - group.add_argument( - '-hd', '--headers', - action='store_true', - help='Analyze code in header files', - ) - group.add_argument( - '--models_mode', - action='store_true', - dest='models_mode', - help='Mode for computing the models', - ) - group.add_argument( - '--no_failures_allowed', - action='store_true', - dest='no_failures_allowed', - help='Fail if at least one of the translations fails', - ) - group.add_argument( - '-tm', '--testing_mode', - dest='testing_mode', - action='store_true', - help='Testing mode for the translation: Do not translate libraries' - ' (including enums)') - group.add_argument( - '-fs', '--frontend-stats', - dest='frontend_stats', - action='store_true', - help='Output statistics about the capture phase to *.o.astlog') - group.add_argument( - '-fd', '--frontend-debug', - dest='frontend_debug', - action='store_true', - help='Output debugging information to *.o.astlog during capture') - return parser +create_argparser = \ + util.clang_frontend_argparser(MODULE_DESCRIPTION, MODULE_NAME) class MakeCapture: @@ -85,45 +43,25 @@ class MakeCapture: def get_envvars(self): env_vars = dict(os.environ) - env_vars['INFER_RESULTS_DIR'] = self.args.infer_out wrappers_path = os.path.join( - os.path.dirname(os.path.realpath(__file__)), '..', 'wrappers') + os.path.dirname( + os.path.realpath(__file__)), os.path.pardir, 'wrappers') env_vars['INFER_OLD_PATH'] = env_vars['PATH'] env_vars['PATH'] = '{wrappers}{sep}{path}'.format( wrappers=wrappers_path, sep=os.pathsep, path=env_vars['PATH'], ) + + frontend_env_vars = util.get_clang_frontend_envvars(self.args) + env_vars.update(frontend_env_vars) return env_vars def capture(self): self.create_results_dir() - env_vars = self.get_envvars() - frontend_args = [] - - if self.args.headers: - frontend_args.append('-headers') - if self.args.models_mode: - frontend_args.append('-models_mode') - if self.args.project_root: - frontend_args += ['-project_root', self.args.project_root] - if self.args.testing_mode: - frontend_args.append('-testing_mode') - if self.args.frontend_debug: - frontend_args += ['-debug'] - env_vars['FCP_DEBUG_MODE'] = '1' - if self.args.frontend_stats: - frontend_args += ['-stats'] - env_vars['FCP_DEBUG_MODE'] = '1' - if self.args.no_failures_allowed: - env_vars['FCP_REPORT_FRONTEND_FAILURE'] = '1' - - # export an env variable with all the arguments to pass to InferClang - env_vars['FCP_INFER_FRONTEND_ARGS'] = ' '.join(frontend_args) - try: - subprocess.check_call(self.cmd, env=env_vars) + subprocess.check_call(self.cmd, env=self.get_envvars()) return os.EX_OK except subprocess.CalledProcessError as exc: if self.args.debug: diff --git a/infer/lib/capture/util.py b/infer/lib/capture/util.py index c0812f97b..b9b4520e8 100644 --- a/infer/lib/capture/util.py +++ b/infer/lib/capture/util.py @@ -47,3 +47,79 @@ def base_argparser(description, module_name): ) return parser return _func + + +def clang_frontend_argparser(description, module_name): + def _func(group_name=module_name): + """This creates an argparser for all the modules that require + clang for their capture phase, thus InferClang and clang wrappers""" + parser = argparse.ArgumentParser(add_help=False) + group = parser.add_argument_group( + "{grp} module".format(grp=group_name), + description=description, + ) + group.add_argument( + '-hd', '--headers', + action='store_true', + help='Analyze code in header files', + ) + group.add_argument( + '--models_mode', + action='store_true', + dest='models_mode', + help='Mode for computing the models', + ) + group.add_argument( + '--no_failures_allowed', + action='store_true', + dest='no_failures_allowed', + help='Fail if at least one of the translations fails', + ) + group.add_argument( + '-tm', '--testing_mode', + dest='testing_mode', + action='store_true', + help='Testing mode for the translation: Do not translate libraries' + ' (including enums)') + group.add_argument( + '-fs', '--frontend-stats', + dest='frontend_stats', + action='store_true', + help='Output statistics about the capture phase to *.o.astlog') + group.add_argument( + '-fd', '--frontend-debug', + dest='frontend_debug', + action='store_true', + help='Output debugging information to *.o.astlog during capture') + return parser + return _func + + +def get_clang_frontend_envvars(args): + """Return the environment variables that configure the clang wrapper, e.g. + to emit debug information if needed, and the invocation of the Infer + frontend for Clang, InferClang, e.g. to analyze headers, emit stats, etc""" + env_vars = {} + frontend_args = [] + + env_vars['INFER_RESULTS_DIR'] = args.infer_out + if args.headers: + frontend_args.append('-headers') + if args.models_mode: + frontend_args.append('-models_mode') + if args.project_root: + frontend_args += ['-project_root', args.project_root] + if args.testing_mode: + frontend_args.append('-testing_mode') + if args.frontend_debug: + frontend_args += ['-debug'] + env_vars['FCP_DEBUG_MODE'] = '1' + if args.frontend_stats: + frontend_args += ['-stats'] + env_vars['FCP_DEBUG_MODE'] = '1' + if args.no_failures_allowed: + env_vars['FCP_REPORT_FRONTEND_FAILURE'] = '1' + + # export an env variable with all the arguments to pass to InferClang + env_vars['FCP_INFER_FRONTEND_ARGS'] = ' '.join(frontend_args) + return env_vars diff --git a/infer/lib/capture/xcodebuild.py b/infer/lib/capture/xcodebuild.py index ce951cdd3..9dfdd7b63 100644 --- a/infer/lib/capture/xcodebuild.py +++ b/infer/lib/capture/xcodebuild.py @@ -25,9 +25,8 @@ CLANGPLUSPLUS_WRAPPER = os.path.join( def gen_instance(*args): return XcodebuildCapture(*args) -# This creates an empty argparser for the module, which provides only -# description/usage information and no arguments. -create_argparser = util.base_argparser(MODULE_DESCRIPTION, MODULE_NAME) +create_argparser = \ + util.clang_frontend_argparser(MODULE_DESCRIPTION, MODULE_NAME) class XcodebuildCapture: @@ -35,14 +34,20 @@ class XcodebuildCapture: self.args = args self.cmd = cmd - def capture(self): + def get_envvars(self): env_vars = dict(os.environ) - # get the path to 'true' using xcrun - true_path = subprocess.check_output(['xcrun', '--find', 'true']).strip() apple_clang_path = \ subprocess.check_output(['xcrun', '--find', 'clang']).strip() + env_vars['FCP_APPLE_CLANG'] = apple_clang_path + + frontend_env_vars = \ + util.get_clang_frontend_envvars(self.args) + env_vars.update(frontend_env_vars) + return env_vars + + def capture(self): # these settings will instruct xcodebuild on which clang to use self.cmd += ['CC={wrapper}'.format(wrapper=CLANG_WRAPPER)] self.cmd += ['CPLUSPLUS={wrapper}'.format(wrapper=CLANGPLUSPLUS_WRAPPER)] @@ -52,11 +57,8 @@ class XcodebuildCapture: # the open-source one self.cmd += ['GCC_PRECOMPILE_PREFIX_HEADER=NO'] - env_vars['INFER_RESULTS_DIR'] = self.args.infer_out - env_vars['FCP_APPLE_CLANG'] = apple_clang_path - try: - subprocess.check_call(self.cmd, env=env_vars) + subprocess.check_call(self.cmd, env=self.get_envvars()) return os.EX_OK except subprocess.CalledProcessError as exc: if self.args.debug: