Home | History | Annotate | Download | only in win
      1 #!/usr/bin/env python
      2 
      3 # Copyright (c) 2013 Google Inc. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 """
      8 Make sure binary is relinked when manifest settings are changed.
      9 """
     10 
     11 import TestGyp
     12 
     13 import os
     14 import sys
     15 
     16 if sys.platform == 'win32':
     17   import pywintypes
     18   import win32api
     19   import winerror
     20 
     21   RT_MANIFEST = 24
     22 
     23   class LoadLibrary(object):
     24     """Context manager for loading and releasing binaries in Windows.
     25     Yields the handle of the binary loaded."""
     26     def __init__(self, path):
     27       self._path = path
     28       self._handle = None
     29 
     30     def __enter__(self):
     31       self._handle = win32api.LoadLibrary(self._path)
     32       return self._handle
     33 
     34     def __exit__(self, type, value, traceback):
     35       win32api.FreeLibrary(self._handle)
     36 
     37   def extract_manifest(path, resource_name):
     38     """Reads manifest from |path| and returns it as a string.
     39     Returns None is there is no such manifest."""
     40     with LoadLibrary(path) as handle:
     41       try:
     42         return win32api.LoadResource(handle, RT_MANIFEST, resource_name)
     43       except pywintypes.error as error:
     44         if error.args[0] == winerror.ERROR_RESOURCE_DATA_NOT_FOUND:
     45           return None
     46         else:
     47           raise
     48 
     49   test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
     50 
     51   CHDIR = 'linker-flags'
     52 
     53   gyp_template = '''
     54 {
     55  'targets': [
     56     {
     57       'target_name': 'test_update_manifest',
     58       'type': 'executable',
     59       'sources': ['hello.cc'],
     60       'msvs_settings': {
     61         'VCLinkerTool': {
     62           'EnableUAC': 'true',
     63           'UACExecutionLevel': '%(uac_execution_level)d',
     64         },
     65         'VCManifestTool': {
     66           'EmbedManifest': 'true',
     67           'AdditionalManifestFiles': '%(additional_manifest_files)s',
     68         },
     69       },
     70     },
     71   ],
     72 }
     73 '''
     74 
     75   gypfile = 'update-manifest.gyp'
     76 
     77   def WriteAndUpdate(uac_execution_level, additional_manifest_files, do_build):
     78     with open(os.path.join(CHDIR, gypfile), 'wb') as f:
     79       f.write(gyp_template % {
     80         'uac_execution_level': uac_execution_level,
     81         'additional_manifest_files': additional_manifest_files,
     82       })
     83     test.run_gyp(gypfile, chdir=CHDIR)
     84     if do_build:
     85       test.build(gypfile, chdir=CHDIR)
     86       exe_file = test.built_file_path('test_update_manifest.exe', chdir=CHDIR)
     87       return extract_manifest(exe_file, 1)
     88 
     89   manifest = WriteAndUpdate(0, '', True)
     90   test.fail_test('asInvoker' not in manifest)
     91   test.fail_test('35138b9a-5d96-4fbd-8e2d-a2440225f93a' in manifest)
     92 
     93   # Make sure that updating .gyp and regenerating doesn't cause a rebuild.
     94   WriteAndUpdate(0, '', False)
     95   test.up_to_date(gypfile, test.ALL, chdir=CHDIR)
     96 
     97   # But make sure that changing a manifest property does cause a relink.
     98   manifest = WriteAndUpdate(2, '', True)
     99   test.fail_test('requireAdministrator' not in manifest)
    100 
    101   # Adding a manifest causes a rebuild.
    102   manifest = WriteAndUpdate(2, 'extra.manifest', True)
    103   test.fail_test('35138b9a-5d96-4fbd-8e2d-a2440225f93a' not in manifest)
    104