/usr/lib/python3/dist-packages/pyzolib/dllutils.py is in python3-pyzolib 0.3.4-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | # -*- coding: utf-8 -*-
# Copyright (C) 2012 Almar Klein
# This module is distributed under the terms of the (new) BSD License.
""" Various utilities to modify Dynamic Link libraries.
Needed to build the Pyzo distro, and it's possible that this
functionality is needed to fix extension modules after installation in
a Pyzo distro.
This is a mix of utilities for Windows, Mac and Linux.
"""
import os
import stat
import sys
import subprocess
import time
import re
_COMMAND_TO_SEARCH_PATH = []
def get_command_to_set_search_path():
""" Get the command to change the RPATH of executables and dynamic
libraries. Returns None if there is no such command or if it
cannot be found.
"""
# Check if already computed
if _COMMAND_TO_SEARCH_PATH:
return _COMMAND_TO_SEARCH_PATH[0]
# Get name of the utility
# In Pyzo it should be present in 'shared'.
utilCommand = None
if sys.platform.startswith('win'):
return
if sys.platform.startswith('linux'):
utilname = 'patchelf'
if sys.platform.startswith('darwin'):
utilname = 'install_name_tool'
if True:
# Try old Pyzo
utilCommand = os.path.join(sys.prefix, 'shared', utilname)
if not os.path.isfile(utilCommand):
utilCommand = utilname
# Try new Pyzo / anaconda
utilCommand = os.path.join(sys.prefix, 'bin', utilname)
if not os.path.isfile(utilCommand):
utilCommand = utilname
# Test whether it exists
try:
subprocess.check_output(['which', utilCommand])
except Exception:
raise RuntimeError('Could not get command (%s) to set search path.' % utilCommand)
# Store and return
_COMMAND_TO_SEARCH_PATH.append(utilCommand)
return utilCommand
def set_search_path(fname, *args):
""" set_search_path(fname, *args)
For the given library/executable, set the search path to the
relative paths specified in args.
For Linux: The RPATH is the path to search for its dependencies.
http://enchildfone.wordpress.com/2010/03/23/a-description-of-rpath-origin-ld_library_path-and-portable-linux-binaries/
For Mac: We use the @rpath identifier to get similar behavior to
Linux. But each dependency must be specified. To realize this, we
need to check for each dependency whether it is on one of te given
search paths.
For Windows: not supported in any way. Windows searches next to the
library and then in system paths and PATH.
"""
# Prepare
args = [arg.lstrip('/') for arg in args if arg]
args = [arg for arg in args if arg != '.'] # Because we add empty dir anyway
args.append('') # make libs search next to themselves
command = get_command_to_set_search_path()
if sys.platform.startswith('linux'):
# Create search path value
rpath = ':'.join( ['$ORIGIN/'+arg for arg in args] )
# Modify rpath using a call to patchelf utility
cmd = [command, '--set-rpath', rpath, fname]
subprocess.check_call(cmd)
print('Set RPATH for %r' % os.path.basename(fname))
#print('Set RPATH for %r: %r' % (os.path.basename(fname), rpath))
elif sys.platform.startswith('darwin'):
# ensure write permissions
mode = os.stat(fname).st_mode
if not (mode & stat.S_IWUSR):
os.chmod(fname, mode | stat.S_IWUSR)
# let the file itself know its place (simpyl on rpath)
name = os.path.basename(fname)
subprocess.call(('install_name_tool', '-id', '@rpath/'+name, fname))
# find the references: call otool -L on the file
otool = subprocess.Popen(('otool', '-L', fname),
stdout = subprocess.PIPE)
references = otool.stdout.readlines()[1:]
# Replace each reference
rereferencedlibs = []
for reference in references:
# find the actual referenced file name
referencedFile = reference.decode().strip().split()[0]
if referencedFile.startswith('@'):
continue # the referencedFile is already a relative path
# Get lib name
_, name = os.path.split(referencedFile)
if name.lower() == 'python':
name = 'libpython' # Rename Python lib on Mac
# see if we provided the referenced file
potentiallibs = [os.path.join(os.path.dirname(fname), arg, name)
for arg in args]
# if so, change the reference and rpath
if any([os.path.isfile(p) for p in potentiallibs]):
subprocess.call(('install_name_tool', '-change',
referencedFile, '@rpath/'+name, fname))
for arg in args:
mac_add_rpath(fname, '@loader_path/' + arg)
mac_add_rpath(fname, '@executable_path/') # use libpython next to exe
rereferencedlibs.append(name)
if rereferencedlibs:
print('Replaced refs for "%s": %s' %
(os.path.basename(fname), ', '.join(rereferencedlibs)) )
elif sys.platform.startswith('win'):
raise RuntimeError('Windows has no way of setting the search path on a library or exe.')
else:
raise RuntimeError('Do not know how to set search path of library or exe on %s' % sys.platform)
def mac_add_rpath(fname, rpath):
""" mac_add_rpath(fname, rpath)
Set the rpath for a Mac library or executble. If the rpath is already
registered, it is ignored.
"""
cmd = ['install_name_tool', '-add_rpath', rpath, fname]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while p.poll() is None:
time.sleep(0.01)
if p.returncode:
msg = p.stdout.read().decode('utf-8')
if 'would duplicate path' in msg:
pass # Ignore t
else:
raise RuntimeError('Could not set rpath: ' + msg)
def remove_CRT_dependencies(dirname, recurse=True):
""" remove_CRT_dependencies(path, recurse=True)
Check all .dll and .pyd files in the given directory (and its
subdirectories if recurse is True), removing the dependency on the
Windows C runtime from the embedded manifest.
"""
dllExt = ['.dll', '.pyd']
for entry in os.listdir(dirname):
p = os.path.join(dirname, entry)
if recurse and os.path.isdir(p):
remove_CRT_dependencies(p, recurse)
elif os.path.isfile(p) and os.path.splitext(p)[1].lower() in dllExt:
remove_CRT_dependency(p)
def remove_CRT_dependency(filename):
""" remove_CRT_dependency(filename)
Modify the embedded manifest of a Windows dll (or pyd file),
such that it no longer depends on the Windows C runtime.
In effect, the dll will fall back to using the C runtime that
the executable depends on (and has loaded in memory).
This function is not necessary for dll's and pyd's that come with
Python, because these are build without the CRT dependencies for a
while. However, some third party packages (e.g. PySide) do have
these dependencies, and they need to be removed in order to work
on a system that does not have the C-runtime installed.
Based on this diff by C. Gohlke:
http://bugs.python.org/file15113/msvc9compiler_stripruntimes_regexp2.diff
See discussion at: http://bugs.python.org/issue4120
"""
if 'QtCore' in filename:
1/0
# Read the whole file
with open(filename, 'rb') as f:
try:
bb = f.read()
except IOError:
#raise IOError('Could not read %s'%filename)
print('Warning: could not read %s'%filename)
return
# Remove assemblyIdentity tag
# This code is different from that in python's distutils/msvc9compiler.py
# by removing re.DOTALL and replaceing the second DOT with "(.|\n|\r)",
# which means that the first DOT cannot contain newlines. Would we not do
# this, the match is too greedy (and causes tk85.dll to break).
pattern = r"""<assemblyIdentity.*?name=("|')Microsoft\."""\
r"""VC\d{2}\.CRT("|')(.|\n|\r)*?(/>|</assemblyIdentity>)"""
pattern = re.compile(pattern.encode('ascii'))
bb, hasMatch = _replacePatternWithSpaces(pattern, bb)
if hasMatch:
# Remove dependentAssembly tag if it's empty
pattern = "<dependentAssembly>\s*</dependentAssembly>".encode('ascii')
bb, hasMatch = _replacePatternWithSpaces(pattern, bb)
# Write back
with open(filename, "wb") as f:
f.write(bb)
print('Removed embedded MSVCR dependency for: %s' % filename)
def _replacePatternWithSpaces(pattern, bb):
match = re.search(pattern, bb)
if match is not None:
L = match.end() - match.start()
bb = re.sub(pattern, b" "*L, bb)
return bb, True
else:
return bb, False
|