Add clang frontend arguments to the xcodebuild module

Summary:
@public
This will enable support for the same set of arguments already supported by the `make` module, e.g. `--frontend-stats`, `--frontend-debug`

Test Plan:
Tested on an Xcode project with the `-fs` argument, and checked that `.astlog` files have been generated on the same location of the .o files
  infer -fs -- xcodebuild -workspace Project.xcworkspace -scheme Project -sdk iphonesimulator
master
martinoluca 10 years ago
parent fc1b26e9cf
commit 99125144d7

@ -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:

@ -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

@ -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:

Loading…
Cancel
Save