Set install names using @loader_path in the extension modules and the wx libs so they can be loaded from the same folder and they can be included in the wx package dir.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@71226 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2012-04-18 03:33:07 +00:00
parent b59c0b5306
commit 9e70e1ba0e
5 changed files with 99 additions and 38 deletions

1
.gitignore vendored
View File

@@ -53,4 +53,5 @@
/wx/*.pi
/wx/*.so
/wx/*.pyd
/wx/*.dylib
/wx/locale

View File

@@ -20,7 +20,8 @@ import urllib2
from distutils.dep_util import newer, newer_group
from buildtools.config import Config, msg, opj, posixjoin, loadETG, etg2sip, findCmd, \
phoenixDir, wxDir, copyIfNewer
phoenixDir, wxDir, copyIfNewer, copyFile, \
macFixDependencyInstallName, macSetLoaderNames
import buildtools.version as version
@@ -360,21 +361,6 @@ def delFiles(fileList, verbose=True):
os.remove(afile)
def macFixDependencyInstallName(destdir, prefix, extension, buildDir):
print("**** macFixDependencyInstallName(%s, %s, %s, %s)" % (destdir, prefix, extension, buildDir))
pwd = os.getcwd()
os.chdir(destdir+prefix+'/lib')
dylibs = glob.glob('*.dylib')
for lib in dylibs:
#cmd = 'install_name_tool -change %s/lib/%s %s/lib/%s %s' % \
# (destdir+prefix,lib, prefix,lib, extension)
cmd = 'install_name_tool -change %s/lib/%s %s/lib/%s %s' % \
(buildDir,lib, prefix,lib, extension)
print(cmd)
os.system(cmd)
os.chdir(pwd)
def getSipCmd():
# Returns the sip command to use, checking for an explicit version and
@@ -863,15 +849,27 @@ def copyWxDlls(options):
dlls += glob.glob(os.path.join(msw.dllDir, "wx*%sud_*.pdb" % ver))
for dll in dlls:
shutil.copyfile(dll, posixjoin(phoenixDir(), cfg.PKGDIR, os.path.basename(dll)))
copyIfNewer(dll, posixjoin(phoenixDir(), cfg.PKGDIR, os.path.basename(dll)), verbose=True)
elif isDarwin:
# Copy the wxWidgets dylibs
cfg = Config()
wxlibdir = os.path.join(getBuildDir(options), "lib")
dlls = glob.glob(wxlibdir + '/*.dylib')
for dll in dlls:
copyIfNewer(dll, posixjoin(phoenixDir(), cfg.PKGDIR, os.path.basename(dll)), verbose=True)
# Now use install_name_tool to change the extension modules to look
# in the same folder for the wx libs, instead of the build dir. Also
# change the wx libs the same way.
macSetLoaderNames(glob.glob(opj(phoenixDir(), cfg.PKGDIR, '*.so')) +
glob.glob(opj(phoenixDir(), cfg.PKGDIR, '*.dylib')))
def setup_py(options, args):
cmdTimer = CommandTimer('setup_py')
copyWxDlls(options)
BUILD_DIR = getBuildDir(options)
DESTDIR = options.installdir
PREFIX = options.prefix
@@ -922,6 +920,8 @@ def setup_py(options, args):
(build_mode, " ".join(build_options), options.extra_setup)
runcmd(command)
copyWxDlls(options)
# Do an install?
if options.install:
# only add the --prefix flag if we have an explicit request to do
@@ -937,6 +937,8 @@ def setup_py(options, args):
(WXPY_PREFIX, " ".join(build_options), options.extra_setup)
runcmd(command)
# NOTE: Can probably get rid of this if we keep the code that is
# setting @loader_path in the install names...
if isDarwin and DESTDIR:
# Now that we are finished with the build fix the ids and
# names in the wx .dylibs
@@ -962,8 +964,6 @@ def waf_py(options, args):
cmdTimer = CommandTimer('waf_py')
waf = getWafCmd()
copyWxDlls(options)
BUILD_DIR = getBuildDir(options)
DESTDIR = options.installdir
PREFIX = options.prefix
@@ -990,6 +990,13 @@ def waf_py(options, args):
cmd = '%s %s %s configure build %s' % (PYTHON, waf, ' '.join(build_options), options.extra_waf)
runcmd(cmd)
copyWxDlls(options)
# Do an install?
if options.install:
pass # TODO...
print("\n------------ BUILD FINISHED ------------")
print("To run the wxPython demo:")
print(" - Set your PYTHONPATH variable to %s." % phoenixDir())
@@ -1037,7 +1044,7 @@ def clean_py(options, args):
deleteIfExists(build_base)
deleteIfExists('build_waf') # make this smarter later, or just use 'build' for waf too
files = list()
for wc in ['*.py', '*.pyc', '*.so', '*.pyd', '*.pdb', '*.pi']:
for wc in ['*.py', '*.pyc', '*.so', '*.dylib', '*.pyd', '*.pdb', '*.pi']:
files += glob.glob(opj(cfg.PKGDIR, wc))
if isWindows:
msw = getMSWSettings(options)
@@ -1212,9 +1219,9 @@ def bdist(options, args):
from ftplib import FTP
ftp = FTP(parser.get("FTP", "host"))
ftp.login(parser.get("FTP", "user"), parser.get("FTP", "pass"))
f = open(tarfilename, 'rb')
ftp_dir = parser.get("FTP", "dir")
old_files = ftp.nlst(ftp_dir)
old_files.sort()
to_delete = []
for afile in old_files:
@@ -1226,6 +1233,7 @@ def bdist(options, args):
ftp.delete("%s/%s" % (ftp_dir, to_delete[i]))
ftp_path = '%s/%s' % (ftp_dir, os.path.basename(tarfilename))
print("Uploading package (this may take some time)...")
f = open(tarfilename, 'rb')
ftp.storbinary('STOR %s' % ftp_path, f)
ftp.close()

View File

@@ -524,7 +524,7 @@ def Config(*args, **kw):
def msg(text):
if not runSilently:
print text
print(text)
def opj(*args):
@@ -616,11 +616,28 @@ def wxDir():
return WXWIN
def copyIfNewer(src, dest):
def copyFile(src, dest, verbose=False):
"""
Copy file from src to dest, preserving permission bits, etc. If src is a
symlink then dest will be a symlink as well instead of just copying the
linked file's contents to a new file.
"""
if verbose:
msg('copying %s --> %s' % (src, dest))
if os.path.islink(src):
if os.path.exists(dest):
os.unlink(dest)
linkto = os.readlink(src)
os.symlink(linkto, dest)
else:
shutil.copy2(src, dest)
def copyIfNewer(src, dest, verbose=False):
if os.path.isdir(dest):
dest = os.path.join(dest, os.path.basename(src))
if newer(src, dest):
shutil.copy(src, dest)
copyFile(src, dest, verbose)
def writeIfChanged(filename, text):
@@ -641,3 +658,38 @@ def writeIfChanged(filename, text):
f = codecs.open(filename, 'w', 'utf-8')
f.write(text.encode('utf-8'))
f.close()
# TODO: we might be able to get rid of this when the install code is updated...
def macFixDependencyInstallName(destdir, prefix, extension, buildDir):
print("**** macFixDependencyInstallName(%s, %s, %s, %s)" % (destdir, prefix, extension, buildDir))
pwd = os.getcwd()
os.chdir(destdir+prefix+'/lib')
dylibs = glob.glob('*.dylib')
for lib in dylibs:
#cmd = 'install_name_tool -change %s/lib/%s %s/lib/%s %s' % \
# (destdir+prefix,lib, prefix,lib, extension)
cmd = 'install_name_tool -change %s/lib/%s %s/lib/%s %s' % \
(buildDir,lib, prefix,lib, extension)
print(cmd)
os.system(cmd)
os.chdir(pwd)
def macSetLoaderNames(filenames):
"""
Scan the list of dynamically loaded files for each file in filenames,
replacing the path for the wxWidgets libraries with "@loader_path"
"""
for filename in filenames:
if not os.path.isfile(filename):
continue
for line in os.popen('otool -L %s' % filename, 'r').readlines(): # -arch all ??
if line.startswith('\t') and 'libwx_' in line:
line = line.strip()
endPos = line.rfind(' (')
curName = line[:endPos]
newName = '@loader_path/' + os.path.basename(curName)
cmd = 'install_name_tool -change %s %s %s' % (curName, newName, filename)
os.system(cmd)

View File

@@ -44,15 +44,18 @@ nothing extra should be needed because the system will automatically
look for the DLLs in the same folder that the extension modules are
located in.
For Unix-like systems like Linux or OSX the locations that are
searched for the dynamic libraries can be controlled by setting
environment variables, DYLD_LIBRARY_PATH for OSX or LD_LIBRARY_PATH
for the others. Basically you just need to set that variable to the
path of the wx package, for example if you're on a Mac and currently
in the folder where this README is located, then you can do something
like this::
For Mac OSX there should also not be anything extra needed to help Phoenix
find the wxWidgets dynamic libraries because the install names have been
modified to use @loader_path so they can find the libraries in the same
folder as the extension modules.
export DYLD_LIBRARY_PATH=`pwd`/wx
For Unix-like systems like Linux the locations that are searched for the
dynamic libraries can be controlled by setting the LD_LIBRARY_PATH
environment variable. Basically you just need to set that variable to the
path of the wx package, for example if you're in the folder where this README
is located, then you can do something like this::
export LD_LIBRARY_PATH=`pwd`/wx
The phoenix_environ.sh shell script included with this build can help
you do that, just be sure to use the "source" command so the variables
@@ -60,6 +63,4 @@ in the current shell's environment will be modified.
It is also possible to embed the path that the dynamic library should
be loaded from directly into the extension module. For now at least
this is left as an exercise for the reader. For OSX look at the man
pages for the otool and install_name_tool commands. For the other
unix-like platforms look at chrpath.
this is left as an exercise for the reader. Look for the chrpath tool.

View File

@@ -1,4 +1,3 @@
DIR=$(cd $(dirname "$BASH_SOURCE") && pwd)
export PYTHONPATH=$DIR
export DYLD_LIBRARY_PATH=$DIR/wx
export LD_LIBRARY_PATH=$DIR/wx