Giovanni Bajo wrote:
> On ven, 2009-01-23 at 17:02 +0100, Lorenzo Mancini wrote:
>> Hello guys,
>>
>> from Leopard on, the special name @executable_path cannot be used
>> anymore in library paths for runtime substitution; two new special names
>> (@rpath and @library_path) were introduced for similar purposes.
>
> The link you posted:
> http://www.codeshorts.ca/2007/nov/01/leopard-linking-making-relocatable-libraries-movin
>
> says that the ld flag "-executable_path" is gone, not the
> @executable_path special symbol within binaries.
True. I was misled to my original conclusion by erroneously asserting
that one-file PyInstaller deploys were actually working in Mac OS X <
10.5; I have since realized that I was just scratching the surface of
the real problem.
After some experiments, this is my understanding so far about the
current state of PyInstaller under Mac OS X.
* PyInstaller is able to produce one-dir deploys by prepending library
dependency paths the special name @executable_path (see bindepend.py,
function fixOsxPaths), which will be expanded during runtime to the
current one-dir workpath.
* the same trick doesn't work for one-file deploys, because the
executable first extracts the binary content in a temporary dir (see
source/linux/main.c), then fork()s itself and the child starts running;
later, the runtime will expand @executable_path during the execution of
the child, to the directory of the original executable, *not* the
temporary dir. As a consequence, PyInstaller at present is not able to
produce working one-file deploys under Mac OS X.
* it's not possible to set an arbitrary path for runtime substitution
of @executable_path; _NSGetExecutablePath exists for getting that value
during runtime, but I didn't find a setter.
A possible solution which doesn't use the @executable_path special name
neither @rpath consists in leaving the dependency path names as they are
(no more install_name_tool magic), therefore leaving the paths absolute,
and specifying the temporary dir path in DYLD_LIBRARY_PATH.
See section "The Library Search Process" in document [1], which details
the searching process for a dynamic library when the pathname contains a
directory name: it specifies that DYLD_LIBRARY_PATH is the first place
where the runtime will search for libraries. Therefore, changing the
DYLD_LIBRARY_PATH during loader's execution will make sure that the
temporary dir libraries will be picked up.
The major drawback of this approach is that the libraries in both
one-dir and one-file deploys will contain absolute paths, so analyzing
them with otool would erroneously suggest that they rely on system
libraries.
The proposed patch is attached. It basically removes the
install_name_tool magic and inserts the workpath at the beginning of
DYLD_LIBRARY_PATH if we are running under Mac OS X. It should work for
both one-file and one-dir deploys.
[1]
http://developer.apple.com/documentation/DeveloperTools/Conceptual/DynamicLibraries/DynamicLibraries.pdf
--
Lorenzo Mancini
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"PyInstaller" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/PyInstaller?hl=en
-~----------~----~----~----~------~----~------~--~---
Index: bindepend.py
===================================================================
--- bindepend.py (revision 21247)
+++ bindepend.py (working copy)
@@ -392,12 +392,6 @@
_bpath.extend(string.split(os.environ.get('PATH', ''), os.pathsep))
return _bpath
-def fixOsxPaths(moduleName):
- for name, lib in selectImports(moduleName):
- dest = os.path.join("@executable_path", name)
- cmd = "install_name_tool -change %s %s %s" % (lib, dest, moduleName)
- os.system(cmd)
-
def findLibrary(name):
"""Look for a library in the system.
Index: Build.py
===================================================================
--- Build.py (revision 21247)
+++ Build.py (working copy)
@@ -435,7 +435,7 @@
digest = md5.new(data).digest()
return digest
-def checkCache(fnm, strip, upx, fix_paths=1):
+def checkCache(fnm, strip, upx):
# On darwin a cache is required anyway to keep the libaries
# with relative install names
if not strip and not upx and sys.platform != 'darwin':
@@ -471,7 +471,7 @@
return cachedfile
if upx:
if strip:
- fnm = checkCache(fnm, 1, 0, fix_paths=0)
+ fnm = checkCache(fnm, 1, 0)
cmd = "upx --best -q \"%s\"" % cachedfile
else:
if strip:
@@ -480,9 +480,6 @@
os.chmod(cachedfile, 0755)
if cmd: os.system(cmd)
- if sys.platform == 'darwin' and fix_paths:
- bindepend.fixOsxPaths(cachedfile)
-
# update cache index
cache_index[basenm] = digest
_save_data(cacheindexfn, cache_index)
Index: source/linux/main.c
===================================================================
--- source/linux/main.c (revision 21247)
+++ source/linux/main.c (working copy)
@@ -36,14 +36,31 @@
{0, 0, 0}
};
#endif
+
+void exportWorkpath(char *workpath, char *envvar_name)
+{
+ char envvar[_MAX_PATH * 4 + 12];
+ char *old_envvar;
+
+ strcpy(envvar, envvar_name);
+ strcat(envvar, "=");
+ strcat(envvar, workpath);
+ envvar[strlen(envvar)-1] = '\0';
+ old_envvar = getenv(envvar_name);
+ if (old_envvar) {
+ strcat(envvar, ":");
+ strcat(envvar, old_envvar);
+ }
+ putenv(envvar);
+ VS("%s\n", envvar);
+}
+
int main(int argc, char* argv[])
{
char thisfile[_MAX_PATH];
char homepath[_MAX_PATH];
char magic_envvar[_MAX_PATH + 12];
- char ldlib_envvar[_MAX_PATH * 4 + 12];
char archivefile[_MAX_PATH + 5];
- char *oldldlib;
TOC *ptoc = NULL;
int rc = 0;
int pid;
@@ -109,17 +126,14 @@
strcpy(magic_envvar, "_MEIPASS2=");
strcat(magic_envvar, workpath);
putenv(magic_envvar);
- /* now LD_LIBRARY_PATH */
- strcpy(ldlib_envvar, "LD_LIBRARY_PATH=");
- strcat(ldlib_envvar, workpath);
- ldlib_envvar[strlen(ldlib_envvar)-1] = '\0';
- oldldlib = getenv("LD_LIBRARY_PATH");
- if (oldldlib) {
- strcat(ldlib_envvar, ":");
- strcat(ldlib_envvar, oldldlib);
- }
- putenv(ldlib_envvar);
- VS("%s\n", ldlib_envvar);
+
+ /* add workpath to LD_LIBRARY_PATH */
+ exportWorkpath(workpath, "LD_LIBRARY_PATH");
+#ifdef __APPLE__
+ /* add workpath to DYLD_LIBRARY_PATH */
+ exportWorkpath(workpath, "DYLD_LIBRARY_PATH");
+#endif
+
pid = fork();
if (pid == 0)
execvp(thisfile, argv);