summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2014-08-12 13:48:45 +0100
committerTorne (Richard Coles) <torne@google.com>2014-08-12 13:48:45 +0100
commitb1e05afbf9d31ac43e23478ba5709fd9165cb845 (patch)
tree51f0264163b56a64fea9a5c36d806b1591ddfcfb
parent9c42a79388ce87185ad04cb02047c1e56ac5e066 (diff)
parent184447a86e6c01ecb2a0b9bed8d08290d252c989 (diff)
downloadgyp-b1e05afbf9d31ac43e23478ba5709fd9165cb845.tar.gz
Merge from Chromium at DEPS revision 288042
This commit was generated by merge_to_master.py. Change-Id: I579101318ff77c5e0666a08e4acd86ffb7277d4c
-rw-r--r--pylib/gyp/generator/analyzer.py266
-rw-r--r--pylib/gyp/generator/ninja.py20
-rw-r--r--pylib/gyp/generator/xcode.py23
-rw-r--r--pylib/gyp/input.py38
-rw-r--r--pylib/gyp/msvs_emulation.py77
-rw-r--r--pylib/gyp/xcode_emulation.py26
-rw-r--r--pylib/gyp/xcode_ninja.py1
-rw-r--r--pylib/gyp/xcodeproj_file.py8
-rw-r--r--test/analyzer/gyptest-analyzer.new.py199
-rw-r--r--test/analyzer/subdir/subdir.gyp17
-rw-r--r--test/analyzer/test.gyp26
-rw-r--r--test/ios/extension/ActionExtension/ActionViewController.h9
-rw-r--r--test/ios/extension/ActionExtension/ActionViewController.m31
-rw-r--r--test/ios/extension/ActionExtension/Info.plist42
-rw-r--r--test/ios/extension/ActionExtension/MainInterface.storyboard63
-rw-r--r--test/ios/extension/ExtensionContainer/AppDelegate.h12
-rw-r--r--test/ios/extension/ExtensionContainer/AppDelegate.m19
-rw-r--r--test/ios/extension/ExtensionContainer/Base.lproj/Main.storyboard25
-rw-r--r--test/ios/extension/ExtensionContainer/Images.xcassets/AppIcon.appiconset/Contents.json53
-rw-r--r--test/ios/extension/ExtensionContainer/Images.xcassets/LaunchImage.launchimage/Contents.json51
-rw-r--r--test/ios/extension/ExtensionContainer/Info.plist32
-rw-r--r--test/ios/extension/ExtensionContainer/ViewController.h11
-rw-r--r--test/ios/extension/ExtensionContainer/ViewController.m24
-rw-r--r--test/ios/extension/ExtensionContainer/main.m13
-rw-r--r--test/ios/extension/extension.gyp83
-rwxr-xr-xtest/ios/gyptest-extension.py28
-rw-r--r--test/mac/gyptest-loadable-module-bundle-product-extension.py28
-rw-r--r--test/mac/loadable-module-bundle-product-extension/src.cc7
-rw-r--r--test/mac/loadable-module-bundle-product-extension/test.gyp24
-rw-r--r--test/ninja/use-console/foo.bar5
-rw-r--r--test/ninja/use-console/gyptest-use-console.py29
-rw-r--r--test/ninja/use-console/use-console.gyp60
-rw-r--r--test/win/gyptest-system-include.py21
-rw-r--r--test/win/system-include/bar/header.h0
-rw-r--r--test/win/system-include/common/commonheader.h0
-rw-r--r--test/win/system-include/foo/header.h0
-rw-r--r--test/win/system-include/main.cc4
-rw-r--r--test/win/system-include/test.gyp26
38 files changed, 1297 insertions, 104 deletions
diff --git a/pylib/gyp/generator/analyzer.py b/pylib/gyp/generator/analyzer.py
index 8b83f807..dc55da67 100644
--- a/pylib/gyp/generator/analyzer.py
+++ b/pylib/gyp/generator/analyzer.py
@@ -4,18 +4,48 @@
"""
This script is intended for use as a GYP_GENERATOR. It takes as input (by way of
-the generator flag file_path) the list of relative file paths to consider. If
-any target has at least one of the paths as a source (or input to an action or
-rule) then 'Found dependency' is output, otherwise 'No dependencies' is output.
+the generator flag config_path) the path of a json file that dictates the files
+and targets to search for. The following keys are supported:
+files: list of paths (relative) of the files to search for.
+targets: list of targets to search for. The target names are unqualified.
+
+The following is output:
+error: only supplied if there is an error.
+warning: only supplied if there is a warning.
+targets: the set of targets passed in via targets that either directly or
+ indirectly depend upon the set of paths supplied in files.
+status: indicates if any of the supplied files matched at least one target.
+
+If the generator flag analyzer_output_path is specified, output is written
+there. Otherwise output is written to stdout.
"""
import gyp.common
import gyp.ninja_syntax as ninja_syntax
+import json
import os
import posixpath
+import sys
debug = False
+found_dependency_string = 'Found dependency'
+no_dependency_string = 'No dependencies'
+
+# MatchStatus is used indicate if and how a target depends upon the supplied
+# sources.
+# The target's sources contain one of the supplied paths.
+MATCH_STATUS_MATCHES = 1
+# The target has a dependency on another target that contains one of the
+# supplied paths.
+MATCH_STATUS_MATCHES_BY_DEPENDENCY = 2
+# The target's sources weren't in the supplied paths and none of the target's
+# dependencies depend upon a target that matched.
+MATCH_STATUS_DOESNT_MATCH = 3
+# The target doesn't contain the source, but the dependent targets have not yet
+# been visited to determine a more specific status yet.
+MATCH_STATUS_TBD = 4
+
generator_supports_multiple_toolsets = True
generator_wants_static_library_dependencies_adjusted = False
@@ -126,21 +156,79 @@ def __ExtractSources(target, target_dict, toplevel_dir):
class Target(object):
"""Holds information about a particular target:
- sources: set of source files defined by this target. This includes inputs to
- actions and rules.
- deps: list of direct dependencies."""
+ deps: set of the names of direct dependent targets.
+ match_staus: one of the MatchStatus values"""
def __init__(self):
- self.sources = []
- self.deps = []
+ self.deps = set()
+ self.match_status = MATCH_STATUS_TBD
+
+class Config(object):
+ """Details what we're looking for
+ look_for_dependency_only: if true only search for a target listing any of
+ the files in files.
+ files: set of files to search for
+ targets: see file description for details"""
+ def __init__(self):
+ self.look_for_dependency_only = True
+ self.files = []
+ self.targets = []
+
+ def Init(self, params):
+ """Initializes Config. This is a separate method as it may raise an
+ exception if there is a parse error."""
+ generator_flags = params.get('generator_flags', {})
+ # TODO(sky): nuke file_path and look_for_dependency_only once migrate
+ # recipes.
+ file_path = generator_flags.get('file_path', None)
+ if file_path:
+ self._InitFromFilePath(file_path)
+ return
+
+ # If |file_path| wasn't specified then we look for config_path.
+ # TODO(sky): always look for config_path once migrated recipes.
+ config_path = generator_flags.get('config_path', None)
+ if not config_path:
+ return
+ self.look_for_dependency_only = False
+ try:
+ f = open(config_path, 'r')
+ config = json.load(f)
+ f.close()
+ except IOError:
+ raise Exception('Unable to open file ' + config_path)
+ except ValueError as e:
+ raise Exception('Unable to parse config file ' + config_path + str(e))
+ if not isinstance(config, dict):
+ raise Exception('config_path must be a JSON file containing a dictionary')
+ self.files = config.get('files', [])
+ # Coalesce duplicates
+ self.targets = list(set(config.get('targets', [])))
+
+ def _InitFromFilePath(self, file_path):
+ try:
+ f = open(file_path, 'r')
+ for file_name in f:
+ if file_name.endswith('\n'):
+ file_name = file_name[0:len(file_name) - 1]
+ if len(file_name):
+ self.files.append(file_name)
+ f.close()
+ except IOError:
+ raise Exception('Unable to open file', file_path)
-def __GenerateTargets(target_list, target_dicts, toplevel_dir):
+def __GenerateTargets(target_list, target_dicts, toplevel_dir, files):
"""Generates a dictionary with the key the name of a target and the value a
- Target. |toplevel_dir| is the root of the source tree."""
+ Target. |toplevel_dir| is the root of the source tree. If the sources of
+ a target match that of |files|, then |target.matched| is set to True.
+ This returns a tuple of the dictionary and whether at least one target's
+ sources listed one of the paths in |files|."""
targets = {}
# Queue of targets to visit.
targets_to_visit = target_list[:]
+ matched = False
+
while len(targets_to_visit) > 0:
target_name = targets_to_visit.pop()
if target_name in targets:
@@ -148,35 +236,80 @@ def __GenerateTargets(target_list, target_dicts, toplevel_dir):
target = Target()
targets[target_name] = target
- target.sources.extend(__ExtractSources(target_name,
- target_dicts[target_name],
- toplevel_dir))
+ sources = __ExtractSources(target_name, target_dicts[target_name],
+ toplevel_dir)
+ for source in sources:
+ if source in files:
+ target.match_status = MATCH_STATUS_MATCHES
+ matched = True
+ break
for dep in target_dicts[target_name].get('dependencies', []):
- targets[target_name].deps.append(dep)
+ targets[target_name].deps.add(dep)
targets_to_visit.append(dep)
- return targets
+ return targets, matched
+
+def _GetUnqualifiedToQualifiedMapping(all_targets, to_find):
+ """Returns a mapping (dictionary) from unqualified name to qualified name for
+ all the targets in |to_find|."""
+ result = {}
+ if not to_find:
+ return result
+ to_find = set(to_find)
+ for target_name in all_targets.keys():
+ extracted = gyp.common.ParseQualifiedTarget(target_name)
+ if len(extracted) > 1 and extracted[1] in to_find:
+ to_find.remove(extracted[1])
+ result[extracted[1]] = target_name
+ if not to_find:
+ return result
+ return result
-def __GetFiles(params):
- """Returns the list of files to analyze, or None if none specified."""
- generator_flags = params.get('generator_flags', {})
- file_path = generator_flags.get('file_path', None)
- if not file_path:
- return None
+def _DoesTargetDependOn(target, all_targets):
+ """Returns true if |target| or any of its dependencies matches the supplied
+ set of paths. This updates |matches| of the Targets as it recurses.
+ target: the Target to look for.
+ all_targets: mapping from target name to Target.
+ matching_targets: set of targets looking for."""
+ if target.match_status == MATCH_STATUS_DOESNT_MATCH:
+ return False
+ if target.match_status == MATCH_STATUS_MATCHES or \
+ target.match_status == MATCH_STATUS_MATCHES_BY_DEPENDENCY:
+ return True
+ for dep_name in target.deps:
+ dep_target = all_targets[dep_name]
+ if _DoesTargetDependOn(dep_target, all_targets):
+ dep_target.match_status = MATCH_STATUS_MATCHES_BY_DEPENDENCY
+ return True
+ dep_target.match_status = MATCH_STATUS_DOESNT_MATCH
+ return False
+
+def _GetTargetsDependingOn(all_targets, possible_targets):
+ """Returns the list of targets in |possible_targets| that depend (either
+ directly on indirectly) on the matched files.
+ all_targets: mapping from target name to Target.
+ possible_targets: targets to search from."""
+ found = []
+ for target in possible_targets:
+ if _DoesTargetDependOn(all_targets[target], all_targets):
+ # possible_targets was initially unqualified, keep it unqualified.
+ found.append(gyp.common.ParseQualifiedTarget(target)[1])
+ return found
+
+def _WriteOutput(params, **values):
+ """Writes the output, either to stdout or a file is specified."""
+ output_path = params.get('generator_flags', {}).get(
+ 'analyzer_output_path', None)
+ if not output_path:
+ print json.dumps(values)
+ return
try:
- f = open(file_path, 'r')
- result = []
- for file_name in f:
- if file_name.endswith('\n'):
- file_name = file_name[0:len(file_name) - 1]
- if len(file_name):
- result.append(file_name)
+ f = open(output_path, 'w')
+ f.write(json.dumps(values) + '\n')
f.close()
- return result
- except IOError:
- print 'Unable to open file', file_path
- return None
+ except IOError as e:
+ print 'Error writing to output file', output_path, str(e)
def CalculateVariables(default_variables, params):
"""Calculate additional variables for use in the build (called by gyp)."""
@@ -202,26 +335,55 @@ def CalculateVariables(default_variables, params):
def GenerateOutput(target_list, target_dicts, data, params):
"""Called by gyp as the final stage. Outputs results."""
- files = __GetFiles(params)
- if not files:
- print 'Must specify files to analyze via file_path generator flag'
- return
+ config = Config()
+ try:
+ config.Init(params)
+ if not config.files:
+ if config.look_for_dependency_only:
+ print 'Must specify files to analyze via file_path generator flag'
+ return
+ raise Exception('Must specify files to analyze via config_path generator '
+ 'flag')
- toplevel_dir = os.path.abspath(params['options'].toplevel_dir)
- if os.sep == '\\' and os.altsep == '/':
- toplevel_dir = toplevel_dir.replace('\\', '/')
- if debug:
- print 'toplevel_dir', toplevel_dir
- targets = __GenerateTargets(target_list, target_dicts, toplevel_dir)
-
- files_set = frozenset(files)
- found_in_all_sources = 0
- for target_name, target in targets.iteritems():
- sources = files_set.intersection(target.sources)
- if len(sources):
- print 'Found dependency'
- if debug:
- print 'Found dependency in', target_name, target.sources
+ toplevel_dir = os.path.abspath(params['options'].toplevel_dir)
+ if os.sep == '\\' and os.altsep == '/':
+ toplevel_dir = toplevel_dir.replace('\\', '/')
+ if debug:
+ print 'toplevel_dir', toplevel_dir
+
+ all_targets, matched = __GenerateTargets(target_list, target_dicts,
+ toplevel_dir,
+ frozenset(config.files))
+
+ # Set of targets that refer to one of the files.
+ if config.look_for_dependency_only:
+ print found_dependency_string if matched else no_dependency_string
return
- print 'No dependencies'
+ warning = None
+ if matched:
+ unqualified_mapping = _GetUnqualifiedToQualifiedMapping(
+ all_targets, config.targets)
+ if len(unqualified_mapping) != len(config.targets):
+ not_found = []
+ for target in config.targets:
+ if not target in unqualified_mapping:
+ not_found.append(target)
+ warning = 'Unable to find all targets: ' + str(not_found)
+ qualified_targets = []
+ for target in config.targets:
+ if target in unqualified_mapping:
+ qualified_targets.append(unqualified_mapping[target])
+ output_targets = _GetTargetsDependingOn(all_targets, qualified_targets)
+ else:
+ output_targets = []
+
+ result_dict = { 'targets': output_targets,
+ 'status': found_dependency_string if matched else
+ no_dependency_string }
+ if warning:
+ result_dict['warning'] = warning
+ _WriteOutput(params, **result_dict)
+
+ except Exception as e:
+ _WriteOutput(params, error=str(e))
diff --git a/pylib/gyp/generator/ninja.py b/pylib/gyp/generator/ninja.py
index f31068a9..3d33d0ac 100644
--- a/pylib/gyp/generator/ninja.py
+++ b/pylib/gyp/generator/ninja.py
@@ -14,6 +14,7 @@ import subprocess
import sys
import gyp
import gyp.common
+from gyp.common import OrderedSet
import gyp.msvs_emulation
import gyp.MSVSUtil as MSVSUtil
import gyp.xcode_emulation
@@ -598,8 +599,9 @@ class NinjaWriter:
is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(action)
if self.flavor == 'win' else False)
args = action['action']
+ pool = 'console' if int(action.get('ninja_use_console', 0)) else None
rule_name, _ = self.WriteNewNinjaRule(name, args, description,
- is_cygwin, env=env)
+ is_cygwin, env, pool)
inputs = [self.GypPathToNinja(i, env) for i in action['inputs']]
if int(action.get('process_outputs_as_sources', False)):
@@ -637,8 +639,9 @@ class NinjaWriter:
('%s ' + generator_default_variables['RULE_INPUT_PATH']) % name)
is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(rule)
if self.flavor == 'win' else False)
+ pool = 'console' if int(rule.get('ninja_use_console', 0)) else None
rule_name, args = self.WriteNewNinjaRule(
- name, args, description, is_cygwin, env=env)
+ name, args, description, is_cygwin, env, pool)
# TODO: if the command references the outputs directly, we should
# simplify it to just use $out.
@@ -1426,7 +1429,7 @@ class NinjaWriter:
values = []
ninja_file.variable(var, ' '.join(values))
- def WriteNewNinjaRule(self, name, args, description, is_cygwin, env):
+ def WriteNewNinjaRule(self, name, args, description, is_cygwin, env, pool):
"""Write out a new ninja "rule" statement for a given command.
Returns the name of the new rule, and a copy of |args| with variables
@@ -1484,7 +1487,7 @@ class NinjaWriter:
# GYP rules/actions express being no-ops by not touching their outputs.
# Avoid executing downstream dependencies in this case by specifying
# restat=1 to ninja.
- self.ninja.rule(rule_name, command, description, restat=True,
+ self.ninja.rule(rule_name, command, description, restat=True, pool=pool,
rspfile=rspfile, rspfile_content=rspfile_content)
self.ninja.newline()
@@ -1777,8 +1780,15 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
wrappers[key_prefix] = os.path.join(build_to_root, value)
if flavor == 'win':
+ configs = [target_dicts[qualified_target]['configurations'][config_name]
+ for qualified_target in target_list]
+ shared_system_includes = None
+ if not generator_flags.get('ninja_use_custom_environment_files', 0):
+ shared_system_includes = \
+ gyp.msvs_emulation.ExtractSharedMSVSSystemIncludes(
+ configs, generator_flags)
cl_paths = gyp.msvs_emulation.GenerateEnvironmentFiles(
- toplevel_build, generator_flags, OpenOutput)
+ toplevel_build, generator_flags, shared_system_includes, OpenOutput)
for arch, path in cl_paths.iteritems():
if clang_cl:
# If we have selected clang-cl, use that instead.
diff --git a/pylib/gyp/generator/xcode.py b/pylib/gyp/generator/xcode.py
index 79724593..b4d1e196 100644
--- a/pylib/gyp/generator/xcode.py
+++ b/pylib/gyp/generator/xcode.py
@@ -69,6 +69,7 @@ generator_additional_path_sections = [
# The Xcode-specific keys that exist on targets and aren't moved down to
# configurations.
generator_additional_non_configuration_keys = [
+ 'ios_app_extension',
'mac_bundle',
'mac_bundle_resources',
'mac_framework_headers',
@@ -644,14 +645,15 @@ def GenerateOutput(target_list, target_dicts, data, params):
# com.googlecode.gyp.xcode.bundle, a pseudo-type that xcode.py interprets
# to create a single-file mh_bundle.
_types = {
- 'executable': 'com.apple.product-type.tool',
- 'loadable_module': 'com.googlecode.gyp.xcode.bundle',
- 'shared_library': 'com.apple.product-type.library.dynamic',
- 'static_library': 'com.apple.product-type.library.static',
- 'executable+bundle': 'com.apple.product-type.application',
- 'loadable_module+bundle': 'com.apple.product-type.bundle',
- 'loadable_module+xctest': 'com.apple.product-type.bundle.unit-test',
- 'shared_library+bundle': 'com.apple.product-type.framework',
+ 'executable': 'com.apple.product-type.tool',
+ 'loadable_module': 'com.googlecode.gyp.xcode.bundle',
+ 'shared_library': 'com.apple.product-type.library.dynamic',
+ 'static_library': 'com.apple.product-type.library.static',
+ 'executable+bundle': 'com.apple.product-type.application',
+ 'loadable_module+bundle': 'com.apple.product-type.bundle',
+ 'loadable_module+xctest': 'com.apple.product-type.bundle.unit-test',
+ 'shared_library+bundle': 'com.apple.product-type.framework',
+ 'executable+extension+bundle': 'com.apple.product-type.app-extension',
}
target_properties = {
@@ -662,6 +664,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
type = spec['type']
is_xctest = int(spec.get('mac_xctest_bundle', 0))
is_bundle = int(spec.get('mac_bundle', 0)) or is_xctest
+ is_extension = int(spec.get('ios_app_extension', 0))
if type != 'none':
type_bundle_key = type
if is_xctest:
@@ -669,6 +672,10 @@ def GenerateOutput(target_list, target_dicts, data, params):
assert type == 'loadable_module', (
'mac_xctest_bundle targets must have type loadable_module '
'(target %s)' % target_name)
+ elif is_extension:
+ assert is_bundle, ('ios_app_extension flag requires mac_bundle '
+ '(target %s)' % target_name)
+ type_bundle_key += '+extension+bundle'
elif is_bundle:
type_bundle_key += '+bundle'
diff --git a/pylib/gyp/input.py b/pylib/gyp/input.py
index e0813f35..bb853a54 100644
--- a/pylib/gyp/input.py
+++ b/pylib/gyp/input.py
@@ -994,23 +994,29 @@ def ExpandVariables(input, phase, variables, build_file):
# Prepare for the next match iteration.
input_str = output
- # Look for more matches now that we've replaced some, to deal with
- # expanding local variables (variables defined in the same
- # variables block as this one).
- gyp.DebugOutput(gyp.DEBUG_VARIABLES, "Found output %r, recursing.", output)
- if type(output) is list:
- if output and type(output[0]) is list:
- # Leave output alone if it's a list of lists.
- # We don't want such lists to be stringified.
- pass
- else:
- new_output = []
- for item in output:
- new_output.append(
- ExpandVariables(item, phase, variables, build_file))
- output = new_output
+ if output == input:
+ gyp.DebugOutput(gyp.DEBUG_VARIABLES,
+ "Found only identity matches on %r, avoiding infinite "
+ "recursion.",
+ output)
else:
- output = ExpandVariables(output, phase, variables, build_file)
+ # Look for more matches now that we've replaced some, to deal with
+ # expanding local variables (variables defined in the same
+ # variables block as this one).
+ gyp.DebugOutput(gyp.DEBUG_VARIABLES, "Found output %r, recursing.", output)
+ if type(output) is list:
+ if output and type(output[0]) is list:
+ # Leave output alone if it's a list of lists.
+ # We don't want such lists to be stringified.
+ pass
+ else:
+ new_output = []
+ for item in output:
+ new_output.append(
+ ExpandVariables(item, phase, variables, build_file))
+ output = new_output
+ else:
+ output = ExpandVariables(output, phase, variables, build_file)
# Convert all strings that are canonically-represented integers into integers.
if type(output) is list:
diff --git a/pylib/gyp/msvs_emulation.py b/pylib/gyp/msvs_emulation.py
index 63593a42..1b82adba 100644
--- a/pylib/gyp/msvs_emulation.py
+++ b/pylib/gyp/msvs_emulation.py
@@ -12,6 +12,7 @@ import re
import subprocess
import sys
+from gyp.common import OrderedSet
import gyp.MSVSVersion
windows_quoter_regex = re.compile(r'(\\*)"')
@@ -131,6 +132,54 @@ def _FindDirectXInstallation():
return dxsdk_dir
+def GetGlobalVSMacroEnv(vs_version):
+ """Get a dict of variables mapping internal VS macro names to their gyp
+ equivalents. Returns all variables that are independent of the target."""
+ env = {}
+ # '$(VSInstallDir)' and '$(VCInstallDir)' are available when and only when
+ # Visual Studio is actually installed.
+ if vs_version.Path():
+ env['$(VSInstallDir)'] = vs_version.Path()
+ env['$(VCInstallDir)'] = os.path.join(vs_version.Path(), 'VC') + '\\'
+ # Chromium uses DXSDK_DIR in include/lib paths, but it may or may not be
+ # set. This happens when the SDK is sync'd via src-internal, rather than
+ # by typical end-user installation of the SDK. If it's not set, we don't
+ # want to leave the unexpanded variable in the path, so simply strip it.
+ dxsdk_dir = _FindDirectXInstallation()
+ env['$(DXSDK_DIR)'] = dxsdk_dir if dxsdk_dir else ''
+ # Try to find an installation location for the Windows DDK by checking
+ # the WDK_DIR environment variable, may be None.
+ env['$(WDK_DIR)'] = os.environ.get('WDK_DIR', '')
+ return env
+
+def ExtractSharedMSVSSystemIncludes(configs, generator_flags):
+ """Finds msvs_system_include_dirs that are common to all targets, removes
+ them from all targets, and returns an OrderedSet containing them."""
+ all_system_includes = OrderedSet(
+ configs[0].get('msvs_system_include_dirs', []))
+ for config in configs[1:]:
+ system_includes = config.get('msvs_system_include_dirs', [])
+ all_system_includes = all_system_includes & OrderedSet(system_includes)
+ if not all_system_includes:
+ return None
+ # Expand macros in all_system_includes.
+ env = GetGlobalVSMacroEnv(GetVSVersion(generator_flags))
+ expanded_system_includes = OrderedSet([ExpandMacros(include, env)
+ for include in all_system_includes])
+ if any(['$' in include for include in expanded_system_includes]):
+ # Some path relies on target-specific variables, bail.
+ return None
+
+ # Remove system includes shared by all targets from the targets.
+ for config in configs:
+ includes = config.get('msvs_system_include_dirs', [])
+ if includes: # Don't insert a msvs_system_include_dirs key if not needed.
+ # This must check the unexpanded includes list:
+ new_includes = [i for i in includes if i not in all_system_includes]
+ config['msvs_system_include_dirs'] = new_includes
+ return expanded_system_includes
+
+
class MsvsSettings(object):
"""A class that understands the gyp 'msvs_...' values (especially the
msvs_settings field). They largely correpond to the VS2008 IDE DOM. This
@@ -139,11 +188,6 @@ class MsvsSettings(object):
def __init__(self, spec, generator_flags):
self.spec = spec
self.vs_version = GetVSVersion(generator_flags)
- self.dxsdk_dir = _FindDirectXInstallation()
-
- # Try to find an installation location for the Windows DDK by checking
- # the WDK_DIR environment variable, may be None.
- self.wdk_dir = os.environ.get('WDK_DIR')
supported_fields = [
('msvs_configuration_attributes', dict),
@@ -194,18 +238,7 @@ class MsvsSettings(object):
'$(PlatformName)': target_platform,
'$(ProjectDir)\\': '',
}
- # '$(VSInstallDir)' and '$(VCInstallDir)' are available when and only when
- # Visual Studio is actually installed.
- if self.vs_version.Path():
- replacements['$(VSInstallDir)'] = self.vs_version.Path()
- replacements['$(VCInstallDir)'] = os.path.join(self.vs_version.Path(),
- 'VC') + '\\'
- # Chromium uses DXSDK_DIR in include/lib paths, but it may or may not be
- # set. This happens when the SDK is sync'd via src-internal, rather than
- # by typical end-user installation of the SDK. If it's not set, we don't
- # want to leave the unexpanded variable in the path, so simply strip it.
- replacements['$(DXSDK_DIR)'] = self.dxsdk_dir if self.dxsdk_dir else ''
- replacements['$(WDK_DIR)'] = self.wdk_dir if self.wdk_dir else ''
+ replacements.update(GetGlobalVSMacroEnv(self.vs_version))
return replacements
def ConvertVSMacros(self, s, base_to_build=None, config=None):
@@ -897,7 +930,8 @@ def _ExtractCLPath(output_of_where):
if line.startswith('LOC:'):
return line[len('LOC:'):].strip()
-def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags, open_out):
+def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags,
+ system_includes, open_out):
"""It's not sufficient to have the absolute path to the compiler, linker,
etc. on Windows, as those tools rely on .dlls being in the PATH. We also
need to support both x86 and x64 compilers within the same build (to support
@@ -928,6 +962,13 @@ def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags, open_out):
args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
variables, _ = popen.communicate()
env = _ExtractImportantEnvironment(variables)
+
+ # Inject system includes from gyp files into INCLUDE.
+ if system_includes:
+ system_includes = system_includes | OrderedSet(
+ env.get('INCLUDE', '').split(';'))
+ env['INCLUDE'] = ';'.join(system_includes)
+
env_block = _FormatAsEnvironmentBlock(env)
f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'wb')
f.write(env_block)
diff --git a/pylib/gyp/xcode_emulation.py b/pylib/gyp/xcode_emulation.py
index 859cd5a9..2f34bc6f 100644
--- a/pylib/gyp/xcode_emulation.py
+++ b/pylib/gyp/xcode_emulation.py
@@ -218,6 +218,9 @@ class XcodeSettings(object):
def _IsBundle(self):
return int(self.spec.get('mac_bundle', 0)) != 0
+ def _IsIosAppExtension(self):
+ return int(self.spec.get('ios_app_extension', 0)) != 0
+
def GetFrameworkVersion(self):
"""Returns the framework version of the current target. Only valid for
bundles."""
@@ -237,7 +240,10 @@ class XcodeSettings(object):
'WRAPPER_EXTENSION', default=default_wrapper_extension)
return '.' + self.spec.get('product_extension', wrapper_extension)
elif self.spec['type'] == 'executable':
- return '.' + self.spec.get('product_extension', 'app')
+ if self._IsIosAppExtension():
+ return '.' + self.spec.get('product_extension', 'appex')
+ else:
+ return '.' + self.spec.get('product_extension', 'app')
else:
assert False, "Don't know extension for '%s', target '%s'" % (
self.spec['type'], self.spec['target_name'])
@@ -292,6 +298,10 @@ class XcodeSettings(object):
def GetProductType(self):
"""Returns the PRODUCT_TYPE of this target."""
+ if self._IsIosAppExtension():
+ assert self._IsBundle(), ('ios_app_extension flag requires mac_bundle '
+ '(target %s)' % self.spec['target_name'])
+ return 'com.apple.product-type.app-extension'
if self._IsBundle():
return {
'executable': 'com.apple.product-type.application',
@@ -794,6 +804,18 @@ class XcodeSettings(object):
for directory in framework_dirs:
ldflags.append('-F' + directory.replace('$(SDKROOT)', sdk_root))
+ if sdk_root and self._IsIosAppExtension():
+ # Adds the link flags for extensions. These flags are common for all
+ # extensions and provide loader and main function.
+ # These flags reflect the compilation options used by xcode to compile
+ # extensions.
+ ldflags.append('-lpkstart')
+ ldflags.append(sdk_root +
+ '/System/Library/PrivateFrameworks/PlugInKit.framework/PlugInKit')
+ ldflags.append('-fapplication-extension')
+ ldflags.append('-Xlinker -rpath '
+ '-Xlinker @executable_path/../../Frameworks')
+
self._Appendf(ldflags, 'CLANG_CXX_LIBRARY', '-stdlib=%s')
self.configname = None
@@ -921,7 +943,7 @@ class XcodeSettings(object):
"""Return a shell command to codesign the iOS output binary so it can
be deployed to a device. This should be run as the very last step of the
build."""
- if not (self.isIOS and self.spec['type'] == "executable"):
+ if not (self.isIOS and self.spec['type'] == 'executable'):
return []
settings = self.xcode_settings[configname]
diff --git a/pylib/gyp/xcode_ninja.py b/pylib/gyp/xcode_ninja.py
index 0e5a70c7..2a89fa98 100644
--- a/pylib/gyp/xcode_ninja.py
+++ b/pylib/gyp/xcode_ninja.py
@@ -90,6 +90,7 @@ def _TargetFromSpec(old_spec, params):
new_xcode_settings
ninja_target['mac_bundle'] = old_spec.get('mac_bundle', 0)
+ ninja_target['ios_app_extension'] = old_spec.get('ios_app_extension', 0)
ninja_target['type'] = old_spec['type']
if ninja_toplevel:
ninja_target['actions'] = [
diff --git a/pylib/gyp/xcodeproj_file.py b/pylib/gyp/xcodeproj_file.py
index 13eaf3aa..7c7f1fbd 100644
--- a/pylib/gyp/xcodeproj_file.py
+++ b/pylib/gyp/xcodeproj_file.py
@@ -2238,10 +2238,12 @@ class PBXNativeTarget(XCTarget):
# Mapping from Xcode product-types to settings. The settings are:
# filetype : used for explicitFileType in the project file
# prefix : the prefix for the file name
- # suffix : the suffix for the filen ame
+ # suffix : the suffix for the file name
_product_filetypes = {
'com.apple.product-type.application': ['wrapper.application',
'', '.app'],
+ 'com.apple.product-type.app-extension': ['wrapper.app-extension',
+ '', '.appex'],
'com.apple.product-type.bundle': ['wrapper.cfbundle',
'', '.bundle'],
'com.apple.product-type.framework': ['wrapper.framework',
@@ -2314,11 +2316,11 @@ class PBXNativeTarget(XCTarget):
if force_extension is not None:
# If it's a wrapper (bundle), set WRAPPER_EXTENSION.
+ # Extension override.
+ suffix = '.' + force_extension
if filetype.startswith('wrapper.'):
self.SetBuildSetting('WRAPPER_EXTENSION', force_extension)
else:
- # Extension override.
- suffix = '.' + force_extension
self.SetBuildSetting('EXECUTABLE_EXTENSION', force_extension)
if filetype.startswith('compiled.mach-o.executable'):
diff --git a/test/analyzer/gyptest-analyzer.new.py b/test/analyzer/gyptest-analyzer.new.py
new file mode 100644
index 00000000..db7e1251
--- /dev/null
+++ b/test/analyzer/gyptest-analyzer.new.py
@@ -0,0 +1,199 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Tests for analyzer
+"""
+
+import json
+import TestGyp
+
+# TODO(sky): when done migrating recipes rename to gyptest-analyzer and nuke
+# existing gyptest-analyzer.
+
+found = 'Found dependency'
+not_found = 'No dependencies'
+
+def _CreateTestFile(files, targets):
+ f = open('test_file', 'w')
+ to_write = {'files': files, 'targets': targets }
+ json.dump(to_write, f)
+ f.close()
+
+def _CreateBogusTestFile():
+ f = open('test_file','w')
+ f.write('bogus')
+ f.close()
+
+def _ReadOutputFileContents():
+ f = open('analyzer_output', 'r')
+ result = json.load(f)
+ f.close()
+ return result
+
+# NOTE: this would be clearer if it subclassed TestGypCustom, but that trips
+# over a bug in pylint (E1002).
+test = TestGyp.TestGypCustom(format='analyzer')
+
+def run_analyzer(*args, **kw):
+ """Runs the test specifying a particular config and output path."""
+ args += ('-Gconfig_path=test_file',
+ '-Ganalyzer_output_path=analyzer_output')
+ test.run_gyp('test.gyp', *args, **kw)
+
+def EnsureContains(targets=set(), matched=False):
+ """Verifies output contains |targets| and |direct_targets|."""
+ result = _ReadOutputFileContents()
+ if result.get('error', None):
+ print 'unexpected error', result.get('error')
+ test.fail_test()
+
+ if result.get('warning', None):
+ print 'unexpected warning', result.get('warning')
+ test.fail_test()
+
+ actual_targets = set(result['targets'])
+ if actual_targets != targets:
+ print 'actual targets:', actual_targets, '\nexpected targets:', targets
+ test.fail_test()
+
+ if matched and result['status'] != found:
+ print 'expected', found, 'got', result['status']
+ test.fail_test()
+ elif not matched and result['status'] != not_found:
+ print 'expected', not_found, 'got', result['status']
+ test.fail_test()
+
+def EnsureError(expected_error_string):
+ """Verifies output contains the error string."""
+ result = _ReadOutputFileContents()
+ if result.get('error', '').find(expected_error_string) == -1:
+ print 'actual error:', result.get('error', ''), '\nexpected error:', \
+ expected_error_string
+ test.fail_test()
+
+def EnsureWarning(expected_warning_string):
+ """Verifies output contains the warning string."""
+ result = _ReadOutputFileContents()
+ if result.get('warning', '').find(expected_warning_string) == -1:
+ print 'actual warning:', result.get('warning', ''), \
+ '\nexpected warning:', expected_warning_string
+ test.fail_test()
+
+# Verifies file_path must be specified.
+test.run_gyp('test.gyp',
+ stdout='Must specify files to analyze via file_path generator '
+ 'flag\n')
+
+# Verifies config_path must point to a valid file.
+test.run_gyp('test.gyp', '-Gconfig_path=bogus_file',
+ '-Ganalyzer_output_path=analyzer_output')
+EnsureError('Unable to open file bogus_file')
+
+# Verify get error when bad target is specified.
+_CreateTestFile(['exe2.c'], ['bad_target'])
+run_analyzer()
+EnsureWarning('Unable to find all targets')
+
+# Verifies config_path must point to a valid json file.
+_CreateBogusTestFile()
+run_analyzer()
+EnsureError('Unable to parse config file test_file')
+
+# Trivial test of a source.
+_CreateTestFile(['foo.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Conditional source that is excluded.
+_CreateTestFile(['conditional_source.c'], [])
+run_analyzer()
+EnsureContains(matched=False)
+
+# Conditional source that is included by way of argument.
+_CreateTestFile(['conditional_source.c'], [])
+run_analyzer('-Dtest_variable=1')
+EnsureContains(matched=True)
+
+# Two unknown files.
+_CreateTestFile(['unknown1.c', 'unoknow2.cc'], [])
+run_analyzer()
+EnsureContains()
+
+# Two unknown files.
+_CreateTestFile(['unknown1.c', 'subdir/subdir_sourcex.c'], [])
+run_analyzer()
+EnsureContains()
+
+# Included dependency
+_CreateTestFile(['unknown1.c', 'subdir/subdir_source.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Included inputs to actions.
+_CreateTestFile(['action_input.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Don't consider outputs.
+_CreateTestFile(['action_output.c'], [])
+run_analyzer()
+EnsureContains(matched=False)
+
+# Rule inputs.
+_CreateTestFile(['rule_input.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Ignore path specified with PRODUCT_DIR.
+_CreateTestFile(['product_dir_input.c'], [])
+run_analyzer()
+EnsureContains(matched=False)
+
+# Path specified via a variable.
+_CreateTestFile(['subdir/subdir_source2.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Verifies paths with // are fixed up correctly.
+_CreateTestFile(['parent_source.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Verifies relative paths are resolved correctly.
+_CreateTestFile(['subdir/subdir_source.h'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Various permutations when passing in targets.
+_CreateTestFile(['exe2.c', 'subdir/subdir2b_source.c'], ['exe', 'exe3'])
+run_analyzer()
+EnsureContains(matched=True, targets={'exe3'})
+
+_CreateTestFile(['exe2.c', 'subdir/subdir2b_source.c'], ['exe'])
+run_analyzer()
+EnsureContains(matched=True)
+
+# Verifies duplicates are ignored.
+_CreateTestFile(['exe2.c', 'subdir/subdir2b_source.c'], ['exe', 'exe'])
+run_analyzer()
+EnsureContains(matched=True)
+
+_CreateTestFile(['exe2.c'], ['exe'])
+run_analyzer()
+EnsureContains(matched=True)
+
+_CreateTestFile(['exe2.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+_CreateTestFile(['subdir/subdir2b_source.c', 'exe2.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+_CreateTestFile(['exe2.c'], [])
+run_analyzer()
+EnsureContains(matched=True)
+
+test.pass_test()
diff --git a/test/analyzer/subdir/subdir.gyp b/test/analyzer/subdir/subdir.gyp
index cd0f0134..bfa2df48 100644
--- a/test/analyzer/subdir/subdir.gyp
+++ b/test/analyzer/subdir/subdir.gyp
@@ -15,5 +15,22 @@
'<(trailing_dir_path)/parent_source.c',
],
},
+ {
+ 'target_name': 'subdir2a',
+ 'type': 'static_library',
+ 'sources': [
+ 'subdir2_source.c',
+ ],
+ 'dependencies': [
+ 'subdir2b',
+ ],
+ },
+ {
+ 'target_name': 'subdir2b',
+ 'type': 'static_library',
+ 'sources': [
+ 'subdir2b_source.c',
+ ],
+ },
],
}
diff --git a/test/analyzer/test.gyp b/test/analyzer/test.gyp
index 482ede39..afc312b2 100644
--- a/test/analyzer/test.gyp
+++ b/test/analyzer/test.gyp
@@ -53,5 +53,31 @@
},
],
},
+ {
+ 'target_name': 'exe2',
+ 'type': 'executable',
+ 'sources': [
+ 'exe2.c',
+ ],
+ },
+ {
+ 'target_name': 'exe3',
+ 'type': 'executable',
+ 'dependencies': [
+ 'subdir/subdir.gyp:foo',
+ 'subdir/subdir.gyp:subdir2a',
+ ],
+ 'sources': [
+ 'exe3.c',
+ ],
+ },
+ {
+ 'target_name': 'all',
+ 'type': 'executable',
+ 'dependencies': [
+ 'exe',
+ 'exe3',
+ ],
+ },
],
}
diff --git a/test/ios/extension/ActionExtension/ActionViewController.h b/test/ios/extension/ActionExtension/ActionViewController.h
new file mode 100644
index 00000000..1c925090
--- /dev/null
+++ b/test/ios/extension/ActionExtension/ActionViewController.h
@@ -0,0 +1,9 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+@interface ActionViewController : UIViewController
+
+@end
diff --git a/test/ios/extension/ActionExtension/ActionViewController.m b/test/ios/extension/ActionExtension/ActionViewController.m
new file mode 100644
index 00000000..d37bacda
--- /dev/null
+++ b/test/ios/extension/ActionExtension/ActionViewController.m
@@ -0,0 +1,31 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ActionViewController.h"
+#import <MobileCoreServices/MobileCoreServices.h>
+
+@interface ActionViewController ()
+
+@end
+
+@implementation ActionViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+ // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)done {
+ // Return any edited content to the host app.
+ // This template doesn't do anything, so we just echo the passed in items.
+ [self.extensionContext
+ completeRequestReturningItems:self.extensionContext.inputItems
+ completionHandler:nil];
+}
+
+@end
diff --git a/test/ios/extension/ActionExtension/Info.plist b/test/ios/extension/ActionExtension/Info.plist
new file mode 100644
index 00000000..f89cd790
--- /dev/null
+++ b/test/ios/extension/ActionExtension/Info.plist
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>ActionExtension</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.gyptest.extension.ActionExtension</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>XPC!</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>NSExtension</key>
+ <dict>
+ <key>NSExtensionAttributes</key>
+ <dict>
+ <key>NSExtensionActivationRule</key>
+ <string>TRUEPREDICATE</string>
+ <key>NSExtensionPointName</key>
+ <string>com.apple.ui-services</string>
+ <key>NSExtensionPointVersion</key>
+ <string>1.0</string>
+ </dict>
+ <key>NSExtensionMainStoryboard</key>
+ <string>MainInterface</string>
+ <key>NSExtensionPointIdentifier</key>
+ <string>com.apple.ui-services</string>
+ </dict>
+</dict>
+</plist>
diff --git a/test/ios/extension/ActionExtension/MainInterface.storyboard b/test/ios/extension/ActionExtension/MainInterface.storyboard
new file mode 100644
index 00000000..5aa58184
--- /dev/null
+++ b/test/ios/extension/ActionExtension/MainInterface.storyboard
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6148" systemVersion="14A229a" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="ObA-dk-sSI">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6147"/>
+ </dependencies>
+ <scenes>
+ <!--Action View Controller - Image-->
+ <scene sceneID="7MM-of-jgj">
+ <objects>
+ <viewController title="Image" id="ObA-dk-sSI" customClass="ActionViewController" customModuleProvider="" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="qkL-Od-lgU"/>
+ <viewControllerLayoutGuide type="bottom" id="n38-gi-rB5"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="zMn-AG-sqS">
+ <rect key="frame" x="0.0" y="0.0" width="320" height="528"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="9ga-4F-77Z">
+ <rect key="frame" x="0.0" y="64" width="320" height="464"/>
+ </imageView>
+ <navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NOA-Dm-cuz">
+ <rect key="frame" x="0.0" y="20" width="320" height="44"/>
+ <items>
+ <navigationItem id="3HJ-uW-3hn">
+ <barButtonItem key="leftBarButtonItem" title="Done" style="done" id="WYi-yp-eM6">
+ <connections>
+ <action selector="done" destination="ObA-dk-sSI" id="Qdu-qn-U6V"/>
+ </connections>
+ </barButtonItem>
+ </navigationItem>
+ </items>
+ </navigationBar>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstAttribute="trailing" secondItem="NOA-Dm-cuz" secondAttribute="trailing" id="A05-Pj-hrr"/>
+ <constraint firstItem="9ga-4F-77Z" firstAttribute="top" secondItem="NOA-Dm-cuz" secondAttribute="bottom" id="Fps-3D-QQW"/>
+ <constraint firstItem="NOA-Dm-cuz" firstAttribute="leading" secondItem="zMn-AG-sqS" secondAttribute="leading" id="HxO-8t-aoh"/>
+ <constraint firstAttribute="trailing" secondItem="9ga-4F-77Z" secondAttribute="trailing" id="Ozw-Hg-0yh"/>
+ <constraint firstItem="9ga-4F-77Z" firstAttribute="leading" secondItem="zMn-AG-sqS" secondAttribute="leading" id="XH5-ld-ONA"/>
+ <constraint firstItem="n38-gi-rB5" firstAttribute="top" secondItem="9ga-4F-77Z" secondAttribute="bottom" id="eQg-nn-Zy4"/>
+ <constraint firstItem="NOA-Dm-cuz" firstAttribute="top" secondItem="qkL-Od-lgU" secondAttribute="bottom" id="we0-1t-bgp"/>
+ </constraints>
+ </view>
+ <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+ <size key="freeformSize" width="320" height="528"/>
+ <connections>
+ <outlet property="imageView" destination="9ga-4F-77Z" id="5y6-5w-9QO"/>
+ <outlet property="view" destination="zMn-AG-sqS" id="Qma-de-2ek"/>
+ </connections>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="X47-rx-isc" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="252" y="-124"/>
+ </scene>
+ </scenes>
+ <simulatedMetricsContainer key="defaultSimulatedMetrics">
+ <simulatedStatusBarMetrics key="statusBar"/>
+ <simulatedOrientationMetrics key="orientation"/>
+ <simulatedScreenMetrics key="destination" type="retina4"/>
+ </simulatedMetricsContainer>
+</document>
diff --git a/test/ios/extension/ExtensionContainer/AppDelegate.h b/test/ios/extension/ExtensionContainer/AppDelegate.h
new file mode 100644
index 00000000..510e2300
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/AppDelegate.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
+
diff --git a/test/ios/extension/ExtensionContainer/AppDelegate.m b/test/ios/extension/ExtensionContainer/AppDelegate.m
new file mode 100644
index 00000000..1197bc1b
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/AppDelegate.m
@@ -0,0 +1,19 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication*)application
+ didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
+ // Override point for customization after application launch.
+ return YES;
+}
+
+@end
diff --git a/test/ios/extension/ExtensionContainer/Base.lproj/Main.storyboard b/test/ios/extension/ExtensionContainer/Base.lproj/Main.storyboard
new file mode 100644
index 00000000..e8f3cfb4
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/Base.lproj/Main.storyboard
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6162" systemVersion="14A238h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6160"/>
+ </dependencies>
+ <scenes>
+ <!--View Controller-->
+ <scene sceneID="tne-QT-ifu">
+ <objects>
+ <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+ <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+ <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+ </objects>
+ </scene>
+ </scenes>
+</document>
diff --git a/test/ios/extension/ExtensionContainer/Images.xcassets/AppIcon.appiconset/Contents.json b/test/ios/extension/ExtensionContainer/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 00000000..f697f61f
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,53 @@
+{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/test/ios/extension/ExtensionContainer/Images.xcassets/LaunchImage.launchimage/Contents.json b/test/ios/extension/ExtensionContainer/Images.xcassets/LaunchImage.launchimage/Contents.json
new file mode 100644
index 00000000..4458b40c
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/Images.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,51 @@
+{
+ "images" : [
+ {
+ "orientation" : "portrait",
+ "idiom" : "iphone",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "iphone",
+ "subtype" : "retina4",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "1x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "1x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/test/ios/extension/ExtensionContainer/Info.plist b/test/ios/extension/ExtensionContainer/Info.plist
new file mode 100644
index 00000000..31ccf4cc
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/Info.plist
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>ExtensionContainer</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.gyptest.extension</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+</dict>
+</plist>
diff --git a/test/ios/extension/ExtensionContainer/ViewController.h b/test/ios/extension/ExtensionContainer/ViewController.h
new file mode 100644
index 00000000..fad77547
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/ViewController.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+@interface ViewController : UIViewController
+
+
+@end
+
diff --git a/test/ios/extension/ExtensionContainer/ViewController.m b/test/ios/extension/ExtensionContainer/ViewController.m
new file mode 100644
index 00000000..3810fa9c
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/ViewController.m
@@ -0,0 +1,24 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ViewController.h"
+
+@interface ViewController ()
+
+
+@end
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ // Do any additional setup after loading the view, typically from a nib.
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+ // Dispose of any resources that can be recreated.
+}
+
+@end
diff --git a/test/ios/extension/ExtensionContainer/main.m b/test/ios/extension/ExtensionContainer/main.m
new file mode 100644
index 00000000..47aecb51
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/main.m
@@ -0,0 +1,13 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char* argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil,
+ NSStringFromClass([AppDelegate class]));
+ }
+}
diff --git a/test/ios/extension/extension.gyp b/test/ios/extension/extension.gyp
new file mode 100644
index 00000000..6fa468cc
--- /dev/null
+++ b/test/ios/extension/extension.gyp
@@ -0,0 +1,83 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'make_global_settings': [
+ ['CC', '/usr/bin/clang'],
+ ['CXX', '/usr/bin/clang++'],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'ExtensionContainer',
+ 'product_name': 'ExtensionContainer',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'mac_bundle_resources': [
+ 'ExtensionContainer/Base.lproj/Main.storyboard',
+ ],
+ 'sources': [
+ 'ExtensionContainer/AppDelegate.h',
+ 'ExtensionContainer/AppDelegate.m',
+ 'ExtensionContainer/ViewController.h',
+ 'ExtensionContainer/ViewController.m',
+ 'ExtensionContainer/main.m',
+ ],
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/ExtensionContainer.app/PlugIns',
+ 'files': [
+ '<(PRODUCT_DIR)/ActionExtension.appex',
+ ]}],
+ 'dependencies': [
+ 'ActionExtension'
+ ],
+
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-fobjc-abi-version=2',
+ ],
+ 'INFOPLIST_FILE': 'ExtensionContainer/Info.plist',
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'ARCHS': [ 'armv7' ],
+ 'SDKROOT': 'iphoneos',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+ },
+ },
+ {
+ 'target_name': 'ActionExtension',
+ 'product_name': 'ActionExtension',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'ios_app_extension': 1,
+ 'sources': [
+ 'ActionExtension/ActionViewController.h',
+ 'ActionExtension/ActionViewController.m',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ '$(SDKROOT)/System/Library/Frameworks/MobileCoreServices.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-fobjc-abi-version=2',
+ ],
+ 'INFOPLIST_FILE': 'ActionExtension/Info.plist',
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'ARCHS': [ 'armv7' ],
+ 'SDKROOT': 'iphoneos',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+ },
+ },
+ ],
+}
+
diff --git a/test/ios/gyptest-extension.py b/test/ios/gyptest-extension.py
new file mode 100755
index 00000000..103eb3fc
--- /dev/null
+++ b/test/ios/gyptest-extension.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that ios app extensions are built correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import sys
+if sys.platform == 'darwin' and TestMac.Xcode.Version()>="0600":
+ test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
+
+ test.run_gyp('extension.gyp', chdir='extension')
+
+ test.build('extension.gyp', 'ExtensionContainer', chdir='extension')
+
+ # Test that the extension is .appex
+ test.built_file_must_exist(
+ 'ExtensionContainer.app/PlugIns/ActionExtension.appex',
+ chdir='extension')
+
+ test.pass_test()
+
diff --git a/test/mac/gyptest-loadable-module-bundle-product-extension.py b/test/mac/gyptest-loadable-module-bundle-product-extension.py
new file mode 100644
index 00000000..90c20837
--- /dev/null
+++ b/test/mac/gyptest-loadable-module-bundle-product-extension.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Tests that loadable_modules don't collide when using the same name with
+different file extensions.
+"""
+
+import TestGyp
+
+import os
+import struct
+import sys
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+ CHDIR = 'loadable-module-bundle-product-extension'
+ test.run_gyp('test.gyp', chdir=CHDIR)
+ test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+ test.must_exist(test.built_file_path('Collide.foo', chdir=CHDIR))
+ test.must_exist(test.built_file_path('Collide.bar', chdir=CHDIR))
+
+ test.pass_test()
diff --git a/test/mac/loadable-module-bundle-product-extension/src.cc b/test/mac/loadable-module-bundle-product-extension/src.cc
new file mode 100644
index 00000000..3d878e96
--- /dev/null
+++ b/test/mac/loadable-module-bundle-product-extension/src.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int test() {
+ return 1337;
+}
diff --git a/test/mac/loadable-module-bundle-product-extension/test.gyp b/test/mac/loadable-module-bundle-product-extension/test.gyp
new file mode 100644
index 00000000..684a2c02
--- /dev/null
+++ b/test/mac/loadable-module-bundle-product-extension/test.gyp
@@ -0,0 +1,24 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+ 'targets': [{
+ 'target_name': 'test',
+ 'type': 'none',
+ 'dependencies': ['child_one', 'child_two'],
+ }, {
+ 'target_name': 'child_one',
+ 'product_name': 'Collide',
+ 'product_extension': 'bar',
+ 'sources': ['src.cc'],
+ 'type': 'loadable_module',
+ 'mac_bundle': 1,
+ }, {
+ 'target_name': 'child_two',
+ 'product_name': 'Collide',
+ 'product_extension': 'foo',
+ 'sources': ['src.cc'],
+ 'type': 'loadable_module',
+ 'mac_bundle': 1,
+ }],
+}
diff --git a/test/ninja/use-console/foo.bar b/test/ninja/use-console/foo.bar
new file mode 100644
index 00000000..07c476a8
--- /dev/null
+++ b/test/ninja/use-console/foo.bar
@@ -0,0 +1,5 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+This is a dummy file for rule/action input.
diff --git a/test/ninja/use-console/gyptest-use-console.py b/test/ninja/use-console/gyptest-use-console.py
new file mode 100644
index 00000000..f76fcd98
--- /dev/null
+++ b/test/ninja/use-console/gyptest-use-console.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure 'ninja_use_console' is supported in actions and rules.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['ninja'])
+
+test.run_gyp('use-console.gyp')
+
+no_pool = open(test.built_file_path('obj/no_pool.ninja')).read()
+if 'pool =' in no_pool:
+ test.fail_test()
+
+action_pool = open(test.built_file_path('obj/action_pool.ninja')).read()
+if 'pool = console' not in action_pool:
+ test.fail_test()
+
+rule_pool = open(test.built_file_path('obj/rule_pool.ninja')).read()
+if 'pool = console' not in rule_pool:
+ test.fail_test()
+
+test.pass_test()
diff --git a/test/ninja/use-console/use-console.gyp b/test/ninja/use-console/use-console.gyp
new file mode 100644
index 00000000..84e63184
--- /dev/null
+++ b/test/ninja/use-console/use-console.gyp
@@ -0,0 +1,60 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'no_pool',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'some_action',
+ 'action': ['echo', 'hello'],
+ 'inputs': ['foo.bar'],
+ 'outputs': ['dummy'],
+ },
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'some_rule',
+ 'extension': 'bar',
+ 'action': ['echo', 'hello'],
+ 'outputs': ['dummy'],
+ },
+ ],
+ 'sources': [
+ 'foo.bar',
+ ],
+ },
+ {
+ 'target_name': 'action_pool',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'some_action',
+ 'action': ['echo', 'hello'],
+ 'inputs': ['foo.bar'],
+ 'outputs': ['dummy'],
+ 'ninja_use_console': 1,
+ },
+ ],
+ },
+ {
+ 'target_name': 'rule_pool',
+ 'type': 'none',
+ 'rules': [
+ {
+ 'rule_name': 'some_rule',
+ 'extension': 'bar',
+ 'action': ['echo', 'hello'],
+ 'outputs': ['dummy'],
+ 'ninja_use_console': 1,
+ },
+ ],
+ 'sources': [
+ 'foo.bar',
+ ],
+ },
+ ],
+}
diff --git a/test/win/gyptest-system-include.py b/test/win/gyptest-system-include.py
new file mode 100644
index 00000000..9a47d985
--- /dev/null
+++ b/test/win/gyptest-system-include.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Checks that msvs_system_include_dirs works.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'system-include'
+ test.run_gyp('test.gyp', chdir=CHDIR)
+ test.build('test.gyp', test.ALL, chdir=CHDIR)
+ test.pass_test()
diff --git a/test/win/system-include/bar/header.h b/test/win/system-include/bar/header.h
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/win/system-include/bar/header.h
diff --git a/test/win/system-include/common/commonheader.h b/test/win/system-include/common/commonheader.h
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/win/system-include/common/commonheader.h
diff --git a/test/win/system-include/foo/header.h b/test/win/system-include/foo/header.h
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/win/system-include/foo/header.h
diff --git a/test/win/system-include/main.cc b/test/win/system-include/main.cc
new file mode 100644
index 00000000..b04ea8a5
--- /dev/null
+++ b/test/win/system-include/main.cc
@@ -0,0 +1,4 @@
+#include <commonheader.h>
+#include <header.h>
+
+int main() {}
diff --git a/test/win/system-include/test.gyp b/test/win/system-include/test.gyp
new file mode 100644
index 00000000..07f26365
--- /dev/null
+++ b/test/win/system-include/test.gyp
@@ -0,0 +1,26 @@
+{
+ 'target_defaults': {
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'WarningLevel': '4',
+ 'WarnAsError': 'true',
+ },
+ },
+ 'msvs_system_include_dirs': [
+ '$(ProjectName)', # Different for each target
+ 'common', # Same for all targets
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'foo',
+ 'type': 'executable',
+ 'sources': [ 'main.cc', ],
+ },
+ {
+ 'target_name': 'bar',
+ 'type': 'executable',
+ 'sources': [ 'main.cc', ],
+ },
+ ],
+}