Index: pylib/gyp/msvs_emulation.py |
diff --git a/pylib/gyp/msvs_emulation.py b/pylib/gyp/msvs_emulation.py |
index 723201eb6a1ea0071672059c828cfe01aa312b4d..a9f65a128c500008ad5f59711eff81f140a6201b 100644 |
--- a/pylib/gyp/msvs_emulation.py |
+++ b/pylib/gyp/msvs_emulation.py |
@@ -454,7 +454,7 @@ class MsvsSettings(object): |
return output_file |
def GetLdflags(self, config, gyp_to_build_path, expand_special, |
- manifest_base_name, is_executable): |
+ manifest_base_name, is_executable, build_dir): |
"""Returns the flags that need to be added to link commands, and the |
manifest files.""" |
config = self._TargetConfig(config) |
@@ -531,17 +531,21 @@ class MsvsSettings(object): |
ldflags.append('/NXCOMPAT') |
have_def_file = filter(lambda x: x.startswith('/DEF:'), ldflags) |
- manifest_flags, manifest_files = self._GetLdManifestFlags( |
- config, manifest_base_name, gyp_to_build_path, |
- is_executable and not have_def_file) |
+ manifest_flags, intermediate_manifest, manifest_files = \ |
+ self._GetLdManifestFlags(config, manifest_base_name, gyp_to_build_path, |
+ is_executable and not have_def_file, build_dir) |
ldflags.extend(manifest_flags) |
- return ldflags, manifest_files |
+ return ldflags, intermediate_manifest, manifest_files |
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 list of all the manifest files to be |
- merged by the manifest tool.""" |
+ allow_isolation, build_dir): |
+ """Returns a 3-tuple: |
+ - the set of flags that need to be added to the link to generate |
+ a default manifest |
+ - the intermediate manifest that the linker will generate that should be |
+ used to assert it doesn't add anything to the merged one. |
+ - the list of all the manifest files to be merged by the manifest tool and |
+ included into the link.""" |
generate_manifest = self._Setting(('VCLinkerTool', 'GenerateManifest'), |
config, |
default='true') |
@@ -549,7 +553,7 @@ class MsvsSettings(object): |
# 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'], [] |
+ return ['/MANIFEST:NO'], [], [] |
output_name = name + '.intermediate.manifest' |
flags = [ |
@@ -557,9 +561,25 @@ class MsvsSettings(object): |
'/ManifestFile:' + output_name, |
] |
+ # Instead of using the MANIFESTUAC flags, we generate a .manifest to |
+ # include into the list of manifests. This allows us to avoid the need to |
+ # do two passes during linking. The /MANIFEST flag and /ManifestFile are |
+ # still used, and the intermediate manifest is used to assert that the |
+ # final manifest we get from merging all the additional manifest files |
+ # (plus the one we generate here) isn't modified by merging the |
+ # intermediate into it. |
+ |
+ # Always NO, because we generate a manifest file that has what we want. |
+ flags.append('/MANIFESTUAC:NO') |
+ |
config = self._TargetConfig(config) |
enable_uac = self._Setting(('VCLinkerTool', 'EnableUAC'), config, |
default='true') |
+ manifest_files = [] |
+ generated_manifest_outer = \ |
+"<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" \ |
+"<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>%s" \ |
+"</assembly>" |
if enable_uac == 'true': |
execution_level = self._Setting(('VCLinkerTool', 'UACExecutionLevel'), |
config, default='0') |
@@ -571,18 +591,38 @@ class MsvsSettings(object): |
ui_access = self._Setting(('VCLinkerTool', 'UACUIAccess'), config, |
default='false') |
- flags.append('''/MANIFESTUAC:"level='%s' uiAccess='%s'"''' % |
- (execution_level_map[execution_level], ui_access)) |
+ |
+ inner = ''' |
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> |
+ <security> |
+ <requestedPrivileges> |
+ <requestedExecutionLevel level='%s' uiAccess='%s' /> |
+ </requestedPrivileges> |
+ </security> |
+</trustInfo>''' % (execution_level_map[execution_level], ui_access) |
else: |
- flags.append('/MANIFESTUAC:NO') |
+ inner = '' |
+ |
+ generated_manifest_contents = generated_manifest_outer % inner |
+ generated_name = name + '.generated.manifest' |
+ # Need to join with the build_dir here as we're writing it during |
+ # generation time, but we return the un-joined version because the build |
+ # will occur in that directory. We only write the file if the contents |
+ # have changed so that simply regenerating the project files doesn't |
+ # cause a relink. |
+ build_dir_generated_name = os.path.join(build_dir, generated_name) |
+ gyp.common.EnsureDirExists(build_dir_generated_name) |
+ f = gyp.common.WriteOnDiff(build_dir_generated_name) |
+ f.write(generated_manifest_contents) |
+ f.close() |
+ manifest_files = [generated_name] |
if allow_isolation: |
flags.append('/ALLOWISOLATION') |
- manifest_files = [output_name] |
manifest_files += self._GetAdditionalManifestFiles(config, |
gyp_to_build_path) |
- return flags, manifest_files |
+ return flags, output_name, manifest_files |
def _GetAdditionalManifestFiles(self, config, gyp_to_build_path): |
"""Gets additional manifest files that are added to the default one |