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 os
import subprocess import subprocess
import traceback import traceback
import util
MODULE_NAME = 'make/cc/clang/gcc' MODULE_NAME = 'make/cc/clang/gcc'
MODULE_DESCRIPTION = '''Run analysis of code built with commands like: MODULE_DESCRIPTION = '''Run analysis of code built with commands like:
make [target] make [target]
@ -24,51 +25,8 @@ def mkdir_if_not_exists(path):
if not os.path.exists(path): if not os.path.exists(path):
os.mkdir(path) os.mkdir(path)
create_argparser = \
def create_argparser(group_name=MODULE_NAME): util.clang_frontend_argparser(MODULE_DESCRIPTION, 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
class MakeCapture: class MakeCapture:
@ -85,45 +43,25 @@ class MakeCapture:
def get_envvars(self): def get_envvars(self):
env_vars = dict(os.environ) env_vars = dict(os.environ)
env_vars['INFER_RESULTS_DIR'] = self.args.infer_out
wrappers_path = os.path.join( 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['INFER_OLD_PATH'] = env_vars['PATH']
env_vars['PATH'] = '{wrappers}{sep}{path}'.format( env_vars['PATH'] = '{wrappers}{sep}{path}'.format(
wrappers=wrappers_path, wrappers=wrappers_path,
sep=os.pathsep, sep=os.pathsep,
path=env_vars['PATH'], path=env_vars['PATH'],
) )
frontend_env_vars = util.get_clang_frontend_envvars(self.args)
env_vars.update(frontend_env_vars)
return env_vars return env_vars
def capture(self): def capture(self):
self.create_results_dir() 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: try:
subprocess.check_call(self.cmd, env=env_vars) subprocess.check_call(self.cmd, env=self.get_envvars())
return os.EX_OK return os.EX_OK
except subprocess.CalledProcessError as exc: except subprocess.CalledProcessError as exc:
if self.args.debug: if self.args.debug:

@ -47,3 +47,79 @@ def base_argparser(description, module_name):
) )
return parser return parser
return _func 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): def gen_instance(*args):
return XcodebuildCapture(*args) return XcodebuildCapture(*args)
# This creates an empty argparser for the module, which provides only create_argparser = \
# description/usage information and no arguments. util.clang_frontend_argparser(MODULE_DESCRIPTION, MODULE_NAME)
create_argparser = util.base_argparser(MODULE_DESCRIPTION, MODULE_NAME)
class XcodebuildCapture: class XcodebuildCapture:
@ -35,14 +34,20 @@ class XcodebuildCapture:
self.args = args self.args = args
self.cmd = cmd self.cmd = cmd
def capture(self): def get_envvars(self):
env_vars = dict(os.environ) env_vars = dict(os.environ)
# get the path to 'true' using xcrun
true_path = subprocess.check_output(['xcrun', '--find', 'true']).strip()
apple_clang_path = \ apple_clang_path = \
subprocess.check_output(['xcrun', '--find', 'clang']).strip() 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 # these settings will instruct xcodebuild on which clang to use
self.cmd += ['CC={wrapper}'.format(wrapper=CLANG_WRAPPER)] self.cmd += ['CC={wrapper}'.format(wrapper=CLANG_WRAPPER)]
self.cmd += ['CPLUSPLUS={wrapper}'.format(wrapper=CLANGPLUSPLUS_WRAPPER)] self.cmd += ['CPLUSPLUS={wrapper}'.format(wrapper=CLANGPLUSPLUS_WRAPPER)]
@ -52,11 +57,8 @@ class XcodebuildCapture:
# the open-source one # the open-source one
self.cmd += ['GCC_PRECOMPILE_PREFIX_HEADER=NO'] 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: try:
subprocess.check_call(self.cmd, env=env_vars) subprocess.check_call(self.cmd, env=self.get_envvars())
return os.EX_OK return os.EX_OK
except subprocess.CalledProcessError as exc: except subprocess.CalledProcessError as exc:
if self.args.debug: if self.args.debug:

Loading…
Cancel
Save