More robust removal of CRT dependencies from dlls in the windows build

Fixes a problem with the 64-bit ImageMagick core DLL getting corrupted
by the old removal process.
This commit is contained in:
Kovid Goyal 2014-06-10 15:37:35 +05:30
parent 9c7851ea05
commit 4e7ce1fece

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import with_statement from __future__ import with_statement, print_function
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
@ -50,6 +50,50 @@ def walk(dir):
for f in record[-1]: for f in record[-1]:
yield os.path.join(record[0], f) yield os.path.join(record[0], f)
# Remove CRT dep from manifests {{{
def get_manifest_from_dll(dll):
import win32api, pywintypes
LOAD_LIBRARY_AS_DATAFILE = 2
d = win32api.LoadLibraryEx(os.path.abspath(dll), 0, LOAD_LIBRARY_AS_DATAFILE)
try:
resources = win32api.EnumResourceNames(d, 24)
except pywintypes.error as err:
if err.winerror == 1812:
return None, None # no resource section (probably a .pyd file)
raise
if resources:
return resources[0], win32api.LoadResource(d, 24, resources[0])
return None, None
def update_manifest(dll, rnum, manifest):
import win32api
h = win32api.BeginUpdateResource(dll, 0)
win32api.UpdateResource(h, 24, rnum, manifest)
win32api.EndUpdateResource(h, 0)
_crt_pat = re.compile(r'Microsoft\.VC\d+\.CRT')
def remove_CRT_from_manifest(dll, log=print):
from lxml import etree
rnum, manifest = get_manifest_from_dll(dll)
if manifest is None:
return
root = etree.fromstring(manifest)
found = False
for ai in root.xpath('//*[local-name()="assemblyIdentity" and @name]'):
name = ai.get('name')
if _crt_pat.match(name):
p = ai.getparent()
pp = p.getparent()
pp.remove(p)
if len(pp) == 0:
pp.getparent().remove(pp)
found = True
if found:
manifest = etree.tostring(root, pretty_print=True)
update_manifest(dll, rnum, manifest)
log('\t', os.path.basename(dll))
# }}}
class Win32Freeze(Command, WixMixIn): class Win32Freeze(Command, WixMixIn):
@ -101,26 +145,12 @@ class Win32Freeze(Command, WixMixIn):
The dependency on the CRT is removed from the manifests of all DLLs. The dependency on the CRT is removed from the manifests of all DLLs.
This allows the CRT loaded by the .exe files to be used instead. This allows the CRT loaded by the .exe files to be used instead.
''' '''
search_pat = re.compile(r'(?is)<dependency>.*Microsoft\.VC\d+\.CRT') self.info('Removing CRT dependency from manifests of:')
repl_pat = re.compile(
r'(?is)<dependency>.*?Microsoft\.VC\d+\.CRT.*?</dependency>')
for dll in chain(walk(self.dll_dir), walk(self.plugins_dir)): for dll in chain(walk(self.dll_dir), walk(self.plugins_dir)):
bn = self.b(dll) bn = self.b(dll)
if bn.rpartition('.')[-1] not in {'dll', 'pyd'}: if bn.lower().rpartition('.')[-1] not in {'dll', 'pyd'}:
continue continue
with open(dll, 'rb') as f: remove_CRT_from_manifest(dll, self.info)
raw = f.read()
match = search_pat.search(raw)
if match is None:
continue
self.info('Removing CRT dependency from manifest of: %s'%bn)
# Blank out the bytes corresponding to the dependency specification
nraw = repl_pat.sub(lambda m: b' '*len(m.group()), raw)
if len(nraw) != len(raw) or nraw == raw:
raise Exception('Something went wrong with %s'%bn)
with open(dll, 'wb') as f:
f.write(nraw)
def initbase(self): def initbase(self):
if self.e(self.base): if self.e(self.base):
@ -276,10 +306,9 @@ class Win32Freeze(Command, WixMixIn):
if not x.endswith('.dll'): if not x.endswith('.dll'):
os.remove(self.j(dirpath, x)) os.remove(self.j(dirpath, x))
print self.info('\nAdding third party dependencies')
print 'Adding third party dependencies'
print '\tAdding misc binary deps' self.info('\tAdding misc binary deps')
bindir = os.path.join(SW, 'bin') bindir = os.path.join(SW, 'bin')
for x in ('pdftohtml', 'pdfinfo', 'pdftoppm'): for x in ('pdftohtml', 'pdfinfo', 'pdftoppm'):
shutil.copy2(os.path.join(bindir, x+'.exe'), self.base) shutil.copy2(os.path.join(bindir, x+'.exe'), self.base)