summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2014-08-19 13:01:00 +0100
committerTorne (Richard Coles) <torne@google.com>2014-08-19 13:01:00 +0100
commit134bf12fce029efe7fa3f4bc18bdc58ebf7c90af (patch)
tree1f2118d02e2c8ec8cff71e13ecbdc3a9e1191d14
parentb1e05afbf9d31ac43e23478ba5709fd9165cb845 (diff)
parent31a32b697f297638d203d82f2b7b1b7fc82dfc98 (diff)
downloadgyp-134bf12fce029efe7fa3f4bc18bdc58ebf7c90af.tar.gz
Merge from Chromium at DEPS revision 290040android-wear-5.1.1_r1android-wear-5.1.0_r1
This commit was generated by merge_to_master.py. Change-Id: Ia957cd5569a5c62711d273132c342efa9c54f05b
-rw-r--r--pylib/gyp/generator/analyzer.py143
-rw-r--r--pylib/gyp/generator/ninja.py2
-rw-r--r--pylib/gyp/msvs_emulation.py14
-rw-r--r--pylib/gyp/xcode_ninja.py3
-rw-r--r--test/analyzer/common.gypi6
-rw-r--r--test/analyzer/gyptest-analyzer.new.py32
-rw-r--r--test/analyzer/subdir2/subdir.gyp18
-rw-r--r--test/analyzer/subdir2/subdir.includes.gypi9
-rw-r--r--test/analyzer/test2.gyp25
-rw-r--r--test/analyzer/test2.includes.gypi13
-rw-r--r--test/analyzer/test2.includes.includes.gypi9
-rw-r--r--test/analyzer/test2.toplevel_includes.gypi15
-rwxr-xr-xtest/generator-output/gyptest-actions.py1
-rwxr-xr-xtest/generator-output/gyptest-copies.py5
-rwxr-xr-xtest/generator-output/gyptest-rules.py1
-rw-r--r--test/win/idl-rules/Window.idl9
-rw-r--r--test/win/idl-rules/basic-idl.gyp109
-rw-r--r--test/win/idl-rules/idl_compiler.py17
18 files changed, 341 insertions, 90 deletions
diff --git a/pylib/gyp/generator/analyzer.py b/pylib/gyp/generator/analyzer.py
index dc55da67..8a8ac70c 100644
--- a/pylib/gyp/generator/analyzer.py
+++ b/pylib/gyp/generator/analyzer.py
@@ -64,16 +64,17 @@ for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
'CONFIGURATION_NAME']:
generator_default_variables[unused] = ''
-def __ExtractBasePath(target):
- """Extracts the path components of the specified gyp target path."""
- last_index = target.rfind('/')
- if last_index == -1:
- return ''
- return target[0:(last_index + 1)]
-def __ResolveParent(path, base_path_components):
+def _ToGypPath(path):
+ """Converts a path to the format used by gyp."""
+ if os.sep == '\\' and os.altsep == '/':
+ return path.replace('\\', '/')
+ return path
+
+
+def _ResolveParent(path, base_path_components):
"""Resolves |path|, which starts with at least one '../'. Returns an empty
- string if the path shouldn't be considered. See __AddSources() for a
+ string if the path shouldn't be considered. See _AddSources() for a
description of |base_path_components|."""
depth = 0
while path.startswith('../'):
@@ -88,7 +89,8 @@ def __ResolveParent(path, base_path_components):
return '/'.join(base_path_components[0:len(base_path_components) - depth]) + \
'/' + path
-def __AddSources(sources, base_path, base_path_components, result):
+
+def _AddSources(sources, base_path, base_path_components, result):
"""Extracts valid sources from |sources| and adds them to |result|. Each
source file is relative to |base_path|, but may contain '..'. To make
resolving '..' easier |base_path_components| contains each of the
@@ -103,7 +105,7 @@ def __AddSources(sources, base_path, base_path_components, result):
org_source = source
source = source[0] + source[1:].replace('//', '/')
if source.startswith('../'):
- source = __ResolveParent(source, base_path_components)
+ source = _ResolveParent(source, base_path_components)
if len(source):
result.append(source)
continue
@@ -111,19 +113,18 @@ def __AddSources(sources, base_path, base_path_components, result):
if debug:
print 'AddSource', org_source, result[len(result) - 1]
-def __ExtractSourcesFromAction(action, base_path, base_path_components,
- results):
+
+def _ExtractSourcesFromAction(action, base_path, base_path_components,
+ results):
if 'inputs' in action:
- __AddSources(action['inputs'], base_path, base_path_components, results)
+ _AddSources(action['inputs'], base_path, base_path_components, results)
-def __ExtractSources(target, target_dict, toplevel_dir):
+
+def _ExtractSources(target, target_dict, toplevel_dir):
# |target| is either absolute or relative and in the format of the OS. Gyp
# source paths are always posix. Convert |target| to a posix path relative to
# |toplevel_dir_|. This is done to make it easy to build source paths.
- if os.sep == '\\' and os.altsep == '/':
- base_path = target.replace('\\', '/')
- else:
- base_path = target
+ base_path = _ToGypPath(target)
if base_path == toplevel_dir:
base_path = ''
elif base_path.startswith(toplevel_dir + '/'):
@@ -131,7 +132,7 @@ def __ExtractSources(target, target_dict, toplevel_dir):
base_path = posixpath.dirname(base_path)
base_path_components = base_path.split('/')
- # Add a trailing '/' so that __AddSources() can easily build paths.
+ # Add a trailing '/' so that _AddSources() can easily build paths.
if len(base_path):
base_path += '/'
@@ -140,20 +141,21 @@ def __ExtractSources(target, target_dict, toplevel_dir):
results = []
if 'sources' in target_dict:
- __AddSources(target_dict['sources'], base_path, base_path_components,
- results)
+ _AddSources(target_dict['sources'], base_path, base_path_components,
+ results)
# Include the inputs from any actions. Any changes to these effect the
# resulting output.
if 'actions' in target_dict:
for action in target_dict['actions']:
- __ExtractSourcesFromAction(action, base_path, base_path_components,
- results)
+ _ExtractSourcesFromAction(action, base_path, base_path_components,
+ results)
if 'rules' in target_dict:
for rule in target_dict['rules']:
- __ExtractSourcesFromAction(rule, base_path, base_path_components, results)
+ _ExtractSourcesFromAction(rule, base_path, base_path_components, results)
return results
+
class Target(object):
"""Holds information about a particular target:
deps: set of the names of direct dependent targets.
@@ -162,6 +164,7 @@ class Target(object):
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
@@ -216,7 +219,32 @@ class Config(object):
except IOError:
raise Exception('Unable to open file', file_path)
-def __GenerateTargets(target_list, target_dicts, toplevel_dir, files):
+
+def _WasBuildFileModified(build_file, data, files):
+ """Returns true if the build file |build_file| is either in |files| or
+ one of the files included by |build_file| is in |files|."""
+ if _ToGypPath(build_file) in files:
+ if debug:
+ print 'gyp file modified', build_file
+ return True
+
+ # First element of included_files is the file itself.
+ if len(data[build_file]['included_files']) <= 1:
+ return False
+
+ for include_file in data[build_file]['included_files'][1:]:
+ # |included_files| are relative to the directory of the |build_file|.
+ rel_include_file = \
+ _ToGypPath(gyp.common.UnrelativePath(include_file, build_file))
+ if rel_include_file in files:
+ if debug:
+ print 'included gyp file modified, gyp_file=', build_file, \
+ 'included file=', rel_include_file
+ return True
+ return False
+
+
+def _GenerateTargets(data, 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. If the sources of
a target match that of |files|, then |target.matched| is set to True.
@@ -229,6 +257,10 @@ def __GenerateTargets(target_list, target_dicts, toplevel_dir, files):
matched = False
+ # Maps from build file to a boolean indicating whether the build file is in
+ # |files|.
+ build_file_in_files = {}
+
while len(targets_to_visit) > 0:
target_name = targets_to_visit.pop()
if target_name in targets:
@@ -236,13 +268,25 @@ def __GenerateTargets(target_list, target_dicts, toplevel_dir, files):
target = Target()
targets[target_name] = target
- 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
+
+ build_file = gyp.common.ParseQualifiedTarget(target_name)[0]
+ if not build_file in build_file_in_files:
+ build_file_in_files[build_file] = \
+ _WasBuildFileModified(build_file, data, files)
+
+ # If a build file (or any of its included files) is modified we assume all
+ # targets in the file are modified.
+ if build_file_in_files[build_file]:
+ target.match_status = MATCH_STATUS_MATCHES
+ matched = True
+ else:
+ 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.add(dep)
@@ -250,6 +294,7 @@ def __GenerateTargets(target_list, target_dicts, toplevel_dir, files):
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|."""
@@ -266,6 +311,7 @@ def _GetUnqualifiedToQualifiedMapping(all_targets, to_find):
return result
return result
+
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.
@@ -285,6 +331,7 @@ def _DoesTargetDependOn(target, all_targets):
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.
@@ -297,6 +344,7 @@ def _GetTargetsDependingOn(all_targets, possible_targets):
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(
@@ -311,6 +359,7 @@ def _WriteOutput(params, **values):
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)."""
flavor = gyp.common.GetFlavor(params)
@@ -333,6 +382,7 @@ def CalculateVariables(default_variables, params):
operating_system = 'linux' # Keep this legacy behavior for now.
default_variables.setdefault('OS', operating_system)
+
def GenerateOutput(target_list, target_dicts, data, params):
"""Called by gyp as the final stage. Outputs results."""
config = Config()
@@ -345,15 +395,28 @@ def GenerateOutput(target_list, target_dicts, data, params):
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('\\', '/')
+ toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir))
if debug:
print 'toplevel_dir', toplevel_dir
- all_targets, matched = __GenerateTargets(target_list, target_dicts,
- toplevel_dir,
- frozenset(config.files))
+ matched = False
+ matched_include = False
+
+ # If one of the modified files is an include file then everything is
+ # affected.
+ if params['options'].includes:
+ for include in params['options'].includes:
+ if _ToGypPath(include) in config.files:
+ if debug:
+ print 'include path modified', include
+ matched_include = True
+ matched = True
+ break
+
+ if not matched:
+ all_targets, matched = _GenerateTargets(data, 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:
@@ -361,7 +424,9 @@ def GenerateOutput(target_list, target_dicts, data, params):
return
warning = None
- if matched:
+ if matched_include:
+ output_targets = config.targets
+ elif matched:
unqualified_mapping = _GetUnqualifiedToQualifiedMapping(
all_targets, config.targets)
if len(unqualified_mapping) != len(config.targets):
diff --git a/pylib/gyp/generator/ninja.py b/pylib/gyp/generator/ninja.py
index 3d33d0ac..4eafb71c 100644
--- a/pylib/gyp/generator/ninja.py
+++ b/pylib/gyp/generator/ninja.py
@@ -530,7 +530,7 @@ class NinjaWriter:
def WriteWinIdlFiles(self, spec, prebuild):
"""Writes rules to match MSVS's implicit idl handling."""
assert self.flavor == 'win'
- if self.msvs_settings.HasExplicitIdlRules(spec):
+ if self.msvs_settings.HasExplicitIdlRulesOrActions(spec):
return []
outputs = []
for source in filter(lambda x: x.endswith('.idl'), spec['sources']):
diff --git a/pylib/gyp/msvs_emulation.py b/pylib/gyp/msvs_emulation.py
index 1b82adba..5f71e9e1 100644
--- a/pylib/gyp/msvs_emulation.py
+++ b/pylib/gyp/msvs_emulation.py
@@ -760,10 +760,16 @@ class MsvsSettings(object):
return True
return False
- def HasExplicitIdlRules(self, spec):
- """Determine if there's an explicit rule for idl files. When there isn't we
- need to generate implicit rules to build MIDL .idl files."""
- return self._HasExplicitRuleForExtension(spec, 'idl')
+ def _HasExplicitIdlActions(self, spec):
+ """Determine if an action should not run midl for .idl files."""
+ return any([action.get('explicit_idl_action', 0)
+ for action in spec.get('actions', [])])
+
+ def HasExplicitIdlRulesOrActions(self, spec):
+ """Determine if there's an explicit rule or action for idl files. When
+ there isn't we need to generate implicit rules to build MIDL .idl files."""
+ return (self._HasExplicitRuleForExtension(spec, 'idl') or
+ self._HasExplicitIdlActions(spec))
def HasExplicitAsmRules(self, spec):
"""Determine if there's an explicit rule for asm files. When there isn't we
diff --git a/pylib/gyp/xcode_ninja.py b/pylib/gyp/xcode_ninja.py
index 2a89fa98..a005dfde 100644
--- a/pylib/gyp/xcode_ninja.py
+++ b/pylib/gyp/xcode_ninja.py
@@ -80,7 +80,8 @@ def _TargetFromSpec(old_spec, params):
if 'configurations' in old_spec:
for config in old_spec['configurations'].iterkeys():
- old_xcode_settings = old_spec['configurations'][config]['xcode_settings']
+ old_xcode_settings = \
+ old_spec['configurations'][config].get('xcode_settings', {})
if 'IPHONEOS_DEPLOYMENT_TARGET' in old_xcode_settings:
new_xcode_settings['CODE_SIGNING_REQUIRED'] = "NO"
new_xcode_settings['IPHONEOS_DEPLOYMENT_TARGET'] = \
diff --git a/test/analyzer/common.gypi b/test/analyzer/common.gypi
new file mode 100644
index 00000000..7c664e40
--- /dev/null
+++ b/test/analyzer/common.gypi
@@ -0,0 +1,6 @@
+# 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.
+
+{
+}
diff --git a/test/analyzer/gyptest-analyzer.new.py b/test/analyzer/gyptest-analyzer.new.py
index db7e1251..b7368671 100644
--- a/test/analyzer/gyptest-analyzer.new.py
+++ b/test/analyzer/gyptest-analyzer.new.py
@@ -42,8 +42,14 @@ def run_analyzer(*args, **kw):
'-Ganalyzer_output_path=analyzer_output')
test.run_gyp('test.gyp', *args, **kw)
+def run_analyzer2(*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('test2.gyp', *args, **kw)
+
def EnsureContains(targets=set(), matched=False):
- """Verifies output contains |targets| and |direct_targets|."""
+ """Verifies output contains |targets|."""
result = _ReadOutputFileContents()
if result.get('error', None):
print 'unexpected error', result.get('error')
@@ -196,4 +202,28 @@ _CreateTestFile(['exe2.c'], [])
run_analyzer()
EnsureContains(matched=True)
+# Assertions when modifying build (gyp/gypi) files, especially when said files
+# are included.
+_CreateTestFile(['subdir2/d.cc'], ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2()
+EnsureContains(matched=True, targets={'exe', 'foo'})
+
+_CreateTestFile(['subdir2/subdir.includes.gypi'],
+ ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2()
+EnsureContains(matched=True, targets={'exe', 'foo'})
+
+_CreateTestFile(['subdir2/subdir.gyp'], ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2()
+EnsureContains(matched=True, targets={'exe', 'foo'})
+
+_CreateTestFile(['test2.includes.gypi'], ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2()
+EnsureContains(matched=True, targets={'exe', 'exe2', 'exe3'})
+
+# Verify modifying a file included makes all targets dirty.
+_CreateTestFile(['common.gypi'], ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2('-Icommon.gypi')
+EnsureContains(matched=True, targets={'exe', 'foo', 'exe2', 'exe3'})
+
test.pass_test()
diff --git a/test/analyzer/subdir2/subdir.gyp b/test/analyzer/subdir2/subdir.gyp
new file mode 100644
index 00000000..d6c709c9
--- /dev/null
+++ b/test/analyzer/subdir2/subdir.gyp
@@ -0,0 +1,18 @@
+# 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': 'foo',
+ 'type': 'static_library',
+ 'sources': [
+ 'subdir_source.c',
+ ],
+ 'includes': [
+ 'subdir.includes.gypi',
+ ],
+ },
+ ],
+}
diff --git a/test/analyzer/subdir2/subdir.includes.gypi b/test/analyzer/subdir2/subdir.includes.gypi
new file mode 100644
index 00000000..324e92bc
--- /dev/null
+++ b/test/analyzer/subdir2/subdir.includes.gypi
@@ -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.
+
+{
+ 'sources': [
+ 'd.cc'
+ ],
+}
diff --git a/test/analyzer/test2.gyp b/test/analyzer/test2.gyp
new file mode 100644
index 00000000..782b6e64
--- /dev/null
+++ b/test/analyzer/test2.gyp
@@ -0,0 +1,25 @@
+# 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': 'exe',
+ 'type': 'executable',
+ 'dependencies': [
+ 'subdir2/subdir.gyp:foo',
+ ],
+ },
+ {
+ 'target_name': 'exe2',
+ 'type': 'executable',
+ 'includes': [
+ 'test2.includes.gypi',
+ ],
+ },
+ ],
+ 'includes': [
+ 'test2.toplevel_includes.gypi',
+ ],
+}
diff --git a/test/analyzer/test2.includes.gypi b/test/analyzer/test2.includes.gypi
new file mode 100644
index 00000000..3e21de23
--- /dev/null
+++ b/test/analyzer/test2.includes.gypi
@@ -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.
+
+{
+ 'sources': [
+ 'a.cc',
+ 'b.cc'
+ ],
+ 'includes': [
+ 'test2.includes.includes.gypi',
+ ],
+}
diff --git a/test/analyzer/test2.includes.includes.gypi b/test/analyzer/test2.includes.includes.gypi
new file mode 100644
index 00000000..de3a025d
--- /dev/null
+++ b/test/analyzer/test2.includes.includes.gypi
@@ -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.
+
+{
+ 'sources': [
+ 'c.cc'
+ ],
+}
diff --git a/test/analyzer/test2.toplevel_includes.gypi b/test/analyzer/test2.toplevel_includes.gypi
new file mode 100644
index 00000000..54fa453b
--- /dev/null
+++ b/test/analyzer/test2.toplevel_includes.gypi
@@ -0,0 +1,15 @@
+# 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': 'exe3',
+ 'type': 'executable',
+ 'sources': [
+ 'e.cc',
+ ],
+ },
+ ],
+}
diff --git a/test/generator-output/gyptest-actions.py b/test/generator-output/gyptest-actions.py
index 2bd09c88..8c912e49 100755
--- a/test/generator-output/gyptest-actions.py
+++ b/test/generator-output/gyptest-actions.py
@@ -18,6 +18,7 @@ test = TestGyp.TestGyp(formats=['!android'])
test.writable(test.workpath('actions'), False)
test.run_gyp('actions.gyp',
'--generator-output=' + test.workpath('gypfiles'),
+ '-G', 'xcode_ninja_target_pattern=^pull_in_all_actions$',
chdir='actions')
test.writable(test.workpath('actions'), True)
diff --git a/test/generator-output/gyptest-copies.py b/test/generator-output/gyptest-copies.py
index 7524b17e..909aebf8 100755
--- a/test/generator-output/gyptest-copies.py
+++ b/test/generator-output/gyptest-copies.py
@@ -18,6 +18,7 @@ test.writable(test.workpath('copies'), False)
test.run_gyp('copies.gyp',
'--generator-output=' + test.workpath('gypfiles'),
+ '-G', 'xcode_ninja_target_pattern=^(?!copies_null)',
chdir='copies')
test.writable(test.workpath('copies'), True)
@@ -39,7 +40,7 @@ test.must_match(['relocate', 'copies', 'copies-out', 'file1'],
if test.format == 'xcode':
chdir = 'relocate/copies/build'
-elif test.format in ['make', 'ninja', 'cmake']:
+elif test.format in ['make', 'ninja', 'xcode-ninja', 'cmake']:
chdir = 'relocate/gypfiles/out'
else:
chdir = 'relocate/gypfiles'
@@ -50,7 +51,7 @@ test.must_match(['relocate', 'copies', 'subdir', 'copies-out', 'file3'],
if test.format == 'xcode':
chdir = 'relocate/copies/subdir/build'
-elif test.format in ['make', 'ninja', 'cmake']:
+elif test.format in ['make', 'ninja', 'xcode-ninja', 'cmake']:
chdir = 'relocate/gypfiles/out'
else:
chdir = 'relocate/gypfiles'
diff --git a/test/generator-output/gyptest-rules.py b/test/generator-output/gyptest-rules.py
index 324d5c2b..b95e005c 100755
--- a/test/generator-output/gyptest-rules.py
+++ b/test/generator-output/gyptest-rules.py
@@ -17,6 +17,7 @@ test.writable(test.workpath('rules'), False)
test.run_gyp('rules.gyp',
'--generator-output=' + test.workpath('gypfiles'),
+ '-G', 'xcode_ninja_target_pattern=^pull_in_all_actions$',
chdir='rules')
test.writable(test.workpath('rules'), True)
diff --git a/test/win/idl-rules/Window.idl b/test/win/idl-rules/Window.idl
new file mode 100644
index 00000000..d8ea01be
--- /dev/null
+++ b/test/win/idl-rules/Window.idl
@@ -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.
+
+[
+ WillBeGarbageCollected,
+] interface Window {
+ void alert();
+};
diff --git a/test/win/idl-rules/basic-idl.gyp b/test/win/idl-rules/basic-idl.gyp
index 9c083275..b74622ad 100644
--- a/test/win/idl-rules/basic-idl.gyp
+++ b/test/win/idl-rules/basic-idl.gyp
@@ -1,42 +1,67 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'variables': {
- 'midl_out_dir': '<(SHARED_INTERMEDIATE_DIR)',
- },
- 'target_defaults': {
- 'configurations': {
- 'Debug': {
- 'msvs_configuration_platform': 'Win32',
- },
- 'Debug_x64': {
- 'inherit_from': ['Debug'],
- 'msvs_configuration_platform': 'x64',
- },
- },
- },
- 'targets': [
- {
- 'target_name': 'idl_test',
- 'type': 'executable',
- 'sources': [
- 'history_indexer.idl',
- '<(midl_out_dir)/history_indexer.h',
- '<(midl_out_dir)/history_indexer_i.c',
- 'history_indexer_user.cc',
- ],
- 'libraries': ['ole32.lib'],
- 'include_dirs': [
- '<(midl_out_dir)',
- ],
- 'msvs_settings': {
- 'VCMIDLTool': {
- 'OutputDirectory': '<(midl_out_dir)',
- 'HeaderFileName': '<(RULE_INPUT_ROOT).h',
- },
- },
- },
- ],
-}
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'midl_out_dir': '<(SHARED_INTERMEDIATE_DIR)',
+ },
+ 'target_defaults': {
+ 'configurations': {
+ 'Debug': {
+ 'msvs_configuration_platform': 'Win32',
+ },
+ 'Debug_x64': {
+ 'inherit_from': ['Debug'],
+ 'msvs_configuration_platform': 'x64',
+ },
+ },
+ },
+ 'targets': [
+ {
+ 'target_name': 'idl_test',
+ 'type': 'executable',
+ 'sources': [
+ 'history_indexer.idl',
+ '<(midl_out_dir)/history_indexer.h',
+ '<(midl_out_dir)/history_indexer_i.c',
+ 'history_indexer_user.cc',
+ ],
+ 'libraries': ['ole32.lib'],
+ 'include_dirs': [
+ '<(midl_out_dir)',
+ ],
+ 'msvs_settings': {
+ 'VCMIDLTool': {
+ 'OutputDirectory': '<(midl_out_dir)',
+ 'HeaderFileName': '<(RULE_INPUT_ROOT).h',
+ },
+ },
+ },
+ {
+ 'target_name': 'idl_explicit_action',
+ 'type': 'none',
+ 'sources': [
+ 'Window.idl',
+ ],
+ 'actions': [{
+ 'action_name': 'blink_idl',
+ 'explicit_idl_action': 1,
+ 'msvs_cygwin_shell': 0,
+ 'inputs': [
+ 'Window.idl',
+ 'idl_compiler.py',
+ ],
+ 'outputs': [
+ 'Window.cpp',
+ 'Window.h',
+ ],
+ 'action': [
+ 'python',
+ 'idl_compiler.py',
+ 'Window.idl',
+ ],
+ }],
+ },
+ ],
+}
diff --git a/test/win/idl-rules/idl_compiler.py b/test/win/idl-rules/idl_compiler.py
new file mode 100644
index 00000000..a12b274d
--- /dev/null
+++ b/test/win/idl-rules/idl_compiler.py
@@ -0,0 +1,17 @@
+#!/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.
+
+# mock, just outputs empty .h/.cpp files
+
+import os
+import sys
+
+if len(sys.argv) == 2:
+ basename, ext = os.path.splitext(sys.argv[1])
+ with open('%s.h' % basename, 'w') as f:
+ f.write('// %s.h\n' % basename)
+ with open('%s.cpp' % basename, 'w') as f:
+ f.write('// %s.cpp\n' % basename)