Skip to content

Commit

Permalink
Add clang frontend arguments to the xcodebuild module
Browse files Browse the repository at this point in the history
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
  • Loading branch information
martinoluca committed Jun 22, 2015
1 parent fc1b26e commit 9912514
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 82 deletions.
82 changes: 10 additions & 72 deletions infer/lib/capture/make.py
Original file line number Diff line number Diff line change
@@ -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]
Expand All @@ -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:
Expand All @@ -85,45 +43,25 @@ def create_results_dir(self):

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:
Expand Down
76 changes: 76 additions & 0 deletions infer/lib/capture/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,79 @@ def _func(group_name=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
22 changes: 12 additions & 10 deletions infer/lib/capture/xcodebuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,29 @@
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:
def __init__(self, args, cmd):
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)]
Expand All @@ -52,11 +57,8 @@ def capture(self):
# 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:
Expand Down

0 comments on commit 9912514

Please sign in to comment.