ninja/win: Support VCLinkerTool.GenerateManifest
Currently Ninja generator always expects VCLinkerTool.GenerateManifest is true. With this CL, it will be configurable like MSVS generator.
BUG=gyp:389
TEST=python gyptest.py test/win/gyptest-link-generate-manifest.py
R=scottmg@chromium.org
Review URL: https://codereview.chromium.org/97873002
git-svn-id: http://gyp.googlecode.com/svn/trunk@1802 78cadc50-ecff-11dd-a971-7dbc132099af
diff --git a/pylib/gyp/generator/ninja.py b/pylib/gyp/generator/ninja.py
index f799fdf..a40c7fe 100644
--- a/pylib/gyp/generator/ninja.py
+++ b/pylib/gyp/generator/ninja.py
@@ -1581,18 +1581,24 @@
def _AddWinLinkRules(master_ninja, embed_manifest, link_incremental):
"""Adds link rules for Windows platform to |master_ninja|."""
def FullLinkCommand(ldcmd, out, binary_type):
- cmd = ('cmd /c %(ldcmd)s'
- ' && %(python)s gyp-win-tool manifest-wrapper $arch'
- ' cmd /c if exist %(out)s.manifest del %(out)s.manifest'
- ' && %(python)s gyp-win-tool manifest-wrapper $arch'
- ' $mt -nologo -manifest $manifests')
+ """Returns a one-liner written for cmd.exe to handle multiphase linker
+ operations including manifest file generation. The command will be
+ structured as follows:
+ cmd /c (linkcmd1 a b) && (linkcmd2 x y) && ... &&
+ if not "$manifests"=="" ((manifestcmd1 a b) && (manifestcmd2 x y) && ... )
+ Note that $manifests becomes empty when no manifest file is generated."""
+ link_commands = ['%(ldcmd)s',
+ 'if exist %(out)s.manifest del %(out)s.manifest']
+ mt_cmd = ('%(python)s gyp-win-tool manifest-wrapper'
+ ' $arch $mt -nologo -manifest $manifests')
if embed_manifest and not link_incremental:
# Embed manifest into a binary. If incremental linking is enabled,
# embedding is postponed to the re-linking stage (see below).
- cmd += ' -outputresource:%(out)s;%(resname)s'
+ mt_cmd += ' -outputresource:%(out)s;%(resname)s'
else:
# Save manifest as an external file.
- cmd += ' -out:%(out)s.manifest'
+ mt_cmd += ' -out:%(out)s.manifest'
+ manifest_commands = [mt_cmd]
if link_incremental:
# There is no point in generating separate rule for the case when
# incremental linking is enabled, but manifest embedding is disabled.
@@ -1600,11 +1606,14 @@
# See also implementation of _GetWinLinkRuleNameSuffix().
assert embed_manifest
# Make .rc file out of manifest, compile it to .res file and re-link.
- cmd += (' && %(python)s gyp-win-tool manifest-to-rc $arch'
- ' %(out)s.manifest %(out)s.manifest.rc %(resname)s'
- ' && %(python)s gyp-win-tool rc-wrapper $arch $rc'
- ' %(out)s.manifest.rc'
- ' && %(ldcmd)s %(out)s.manifest.res')
+ manifest_commands += [
+ ('%(python)s gyp-win-tool manifest-to-rc $arch %(out)s.manifest'
+ ' %(out)s.manifest.rc %(resname)s'),
+ '%(python)s gyp-win-tool rc-wrapper $arch $rc %(out)s.manifest.rc',
+ '%(ldcmd)s %(out)s.manifest.res']
+ cmd = 'cmd /c %s && if not "$manifests"=="" (%s)' % (
+ ' && '.join(['(%s)' % c for c in link_commands]),
+ ' && '.join(['(%s)' % c for c in manifest_commands]))
resource_name = {
'exe': '1',
'dll': '2',
diff --git a/pylib/gyp/msvs_emulation.py b/pylib/gyp/msvs_emulation.py
index 9ea86db..9c575bd 100644
--- a/pylib/gyp/msvs_emulation.py
+++ b/pylib/gyp/msvs_emulation.py
@@ -512,18 +512,26 @@
ldflags.append('/NXCOMPAT')
have_def_file = filter(lambda x: x.startswith('/DEF:'), ldflags)
- manifest_flags, intermediate_manifest_file = self._GetLdManifestFlags(
- config, manifest_base_name, is_executable and not have_def_file)
+ manifest_flags, manifest_files = self._GetLdManifestFlags(
+ config, manifest_base_name, gyp_to_build_path,
+ is_executable and not have_def_file)
ldflags.extend(manifest_flags)
- manifest_files = self._GetAdditionalManifestFiles(config, gyp_to_build_path)
- manifest_files.append(intermediate_manifest_file)
-
return ldflags, manifest_files
- def _GetLdManifestFlags(self, config, name, allow_isolation):
+ def _GetLdManifestFlags(self, config, name, gyp_to_build_path,
+ allow_isolation):
"""Returns the set of flags that need to be added to the link to generate
- a default manifest, as well as the name of the generated file."""
- # The manifest is generated by default.
+ a default manifest, as well as the list of all the manifest files to be
+ merged by the manifest tool."""
+ generate_manifest = self._Setting(('VCLinkerTool', 'GenerateManifest'),
+ config,
+ default='true')
+ if generate_manifest != 'true':
+ # This means not only that the linker should not generate the intermediate
+ # manifest but also that the manifest tool should do nothing even when
+ # additional manifests are specified.
+ return ['/MANIFEST:NO'], []
+
output_name = name + '.intermediate.manifest'
flags = [
'/MANIFEST',
@@ -551,7 +559,11 @@
if allow_isolation:
flags.append('/ALLOWISOLATION')
- return flags, output_name
+
+ manifest_files = [output_name]
+ manifest_files += self._GetAdditionalManifestFiles(config,
+ gyp_to_build_path)
+ return flags, manifest_files
def _GetAdditionalManifestFiles(self, config, gyp_to_build_path):
"""Gets additional manifest files that are added to the default one
diff --git a/test/win/gyptest-link-generate-manifest.py b/test/win/gyptest-link-generate-manifest.py
index e7d9bc7..ff03afd 100644
--- a/test/win/gyptest-link-generate-manifest.py
+++ b/test/win/gyptest-link-generate-manifest.py
@@ -14,31 +14,106 @@
import sys
if sys.platform == 'win32':
+ import pywintypes
+ import win32api
+ import winerror
+
+ RT_MANIFEST = 24
+
+ class LoadLibrary(object):
+ """Context manager for loading and releasing binaries in Windows.
+ Yields the handle of the binary loaded."""
+ def __init__(self, path):
+ self._path = path
+ self._handle = None
+
+ def __enter__(self):
+ self._handle = win32api.LoadLibrary(self._path)
+ return self._handle
+
+ def __exit__(self, type, value, traceback):
+ win32api.FreeLibrary(self._handle)
+
+ def extract_manifest(path, resource_name):
+ """Reads manifest from |path| and returns it as a string.
+ Returns None is there is no such manifest."""
+ with LoadLibrary(path) as handle:
+ try:
+ return win32api.LoadResource(handle, RT_MANIFEST, resource_name)
+ except pywintypes.error as error:
+ if error.args[0] == winerror.ERROR_RESOURCE_DATA_NOT_FOUND:
+ return None
+ else:
+ raise
+
test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
CHDIR = 'linker-flags'
test.run_gyp('generate-manifest.gyp', chdir=CHDIR)
test.build('generate-manifest.gyp', test.ALL, chdir=CHDIR)
- test.built_file_must_exist('test_manifest_exe.exe.manifest', chdir=CHDIR)
- test.built_file_must_exist('test_manifest_dll.dll.manifest', chdir=CHDIR)
- # Must contain the Win7 support GUID, but not the Vista one (from
- # extra2.manifest).
- extra1_manifest = test.built_file_path(
- 'test_manifest_extra1.exe.manifest', chdir=CHDIR)
- test.must_contain(extra1_manifest, '35138b9a-5d96-4fbd-8e2d-a2440225f93a')
- test.must_not_contain(extra1_manifest, 'e2011457-1546-43c5-a5fe-008deee3d3f0')
+ def test_manifest(filename, generate_manifest, embedded_manifest,
+ extra_manifest):
+ exe_file = test.built_file_path(filename, chdir=CHDIR)
+ if not generate_manifest:
+ test.must_not_exist(exe_file + '.manifest')
+ manifest = extract_manifest(exe_file, 1)
+ test.fail_test(manifest)
+ return
+ if embedded_manifest:
+ manifest = extract_manifest(exe_file, 1)
+ test.fail_test(not manifest)
+ else:
+ test.must_exist(exe_file + '.manifest')
+ manifest = test.read(exe_file + '.manifest')
+ test.fail_test(not manifest)
+ test.fail_test(extract_manifest(exe_file, 1))
+ if generate_manifest:
+ test.must_contain_any_line(manifest, 'requestedExecutionLevel')
+ if extra_manifest:
+ test.must_contain_any_line(manifest,
+ '35138b9a-5d96-4fbd-8e2d-a2440225f93a')
+ test.must_contain_any_line(manifest,
+ 'e2011457-1546-43c5-a5fe-008deee3d3f0')
- # Must contain both.
- extra2_manifest = test.built_file_path(
- 'test_manifest_extra2.exe.manifest', chdir=CHDIR)
- test.must_contain(extra2_manifest, '35138b9a-5d96-4fbd-8e2d-a2440225f93a')
- test.must_contain(extra2_manifest, 'e2011457-1546-43c5-a5fe-008deee3d3f0')
-
- # Same as extra2, but using list syntax instead.
- extra_list_manifest = test.built_file_path(
- 'test_manifest_extra_list.exe.manifest', chdir=CHDIR)
- test.must_contain(extra_list_manifest, '35138b9a-5d96-4fbd-8e2d-a2440225f93a')
- test.must_contain(extra_list_manifest, 'e2011457-1546-43c5-a5fe-008deee3d3f0')
-
+ test_manifest('test_generate_manifest_true.exe',
+ generate_manifest=True,
+ embedded_manifest=False,
+ extra_manifest=False)
+ test_manifest('test_generate_manifest_false.exe',
+ generate_manifest=False,
+ embedded_manifest=False,
+ extra_manifest=False)
+ test_manifest('test_generate_manifest_default.exe',
+ generate_manifest=True,
+ embedded_manifest=False,
+ extra_manifest=False)
+ test_manifest('test_generate_manifest_true_as_embedded.exe',
+ generate_manifest=True,
+ embedded_manifest=True,
+ extra_manifest=False)
+ test_manifest('test_generate_manifest_false_as_embedded.exe',
+ generate_manifest=False,
+ embedded_manifest=True,
+ extra_manifest=False)
+ test_manifest('test_generate_manifest_default_as_embedded.exe',
+ generate_manifest=True,
+ embedded_manifest=True,
+ extra_manifest=False)
+ test_manifest('test_generate_manifest_true_with_extra_manifest.exe',
+ generate_manifest=True,
+ embedded_manifest=False,
+ extra_manifest=True)
+ test_manifest('test_generate_manifest_false_with_extra_manifest.exe',
+ generate_manifest=False,
+ embedded_manifest=False,
+ extra_manifest=True)
+ test_manifest('test_generate_manifest_true_with_extra_manifest_list.exe',
+ generate_manifest=True,
+ embedded_manifest=False,
+ extra_manifest=True)
+ test_manifest('test_generate_manifest_false_with_extra_manifest_list.exe',
+ generate_manifest=False,
+ embedded_manifest=False,
+ extra_manifest=True)
test.pass_test()
diff --git a/test/win/linker-flags/generate-manifest.gyp b/test/win/linker-flags/generate-manifest.gyp
index fe5ee74..41f888f 100644
--- a/test/win/linker-flags/generate-manifest.gyp
+++ b/test/win/linker-flags/generate-manifest.gyp
@@ -1,64 +1,156 @@
-# Copyright (c) 2012 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_manifest_exe',
- 'type': 'executable',
- 'sources': ['hello.cc'],
- 'msvs_settings': {
- 'VCManifestTool': {
- 'EmbedManifest': 'false',
- }
- },
- },
- {
- 'target_name': 'test_manifest_dll',
- 'type': 'shared_library',
- 'sources': ['hello.cc'],
- 'msvs_settings': {
- 'VCManifestTool': {
- 'EmbedManifest': 'false',
- }
- },
- },
- {
- 'target_name': 'test_manifest_extra1',
- 'type': 'executable',
- 'sources': ['hello.cc'],
- 'msvs_settings': {
- 'VCManifestTool': {
- 'EmbedManifest': 'false',
- 'AdditionalManifestFiles': 'extra.manifest',
- }
- },
- },
- {
- 'target_name': 'test_manifest_extra2',
- 'type': 'executable',
- 'sources': ['hello.cc'],
- 'msvs_settings': {
- 'VCManifestTool': {
- 'EmbedManifest': 'false',
- 'AdditionalManifestFiles': 'extra.manifest;extra2.manifest',
- }
- },
- },
- {
- 'target_name': 'test_manifest_extra_list',
- 'type': 'executable',
- 'sources': ['hello.cc'],
- 'msvs_settings': {
- 'VCManifestTool': {
- 'EmbedManifest': 'false',
- 'AdditionalManifestFiles': [
- 'extra.manifest',
- 'extra2.manifest'
- ],
- }
- },
- },
- ]
-}
+# Copyright (c) 2012 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_generate_manifest_true',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'true',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_false',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'false',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_default',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_true_as_embedded',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'true',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_false_as_embedded',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'false',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_default_as_embedded',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_true_with_extra_manifest',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'true',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ 'AdditionalManifestFiles': 'extra.manifest;extra2.manifest',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_false_with_extra_manifest',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'false',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ 'AdditionalManifestFiles': 'extra.manifest;extra2.manifest',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_true_with_extra_manifest_list',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'true',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ 'AdditionalManifestFiles': [
+ 'extra.manifest',
+ 'extra2.manifest',
+ ],
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_false_with_extra_manifest_list',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'false',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ 'AdditionalManifestFiles': [
+ 'extra.manifest',
+ 'extra2.manifest',
+ ],
+ },
+ },
+ },
+ ]
+}