mdavidsaver / setuptools_dso

setuptools extension for building non-Python Dynamic Shared Objects
Other
9 stars 6 forks source link

@rpath instead of @loader_path on MacOS #8

Closed mtikekar closed 4 years ago

mtikekar commented 4 years ago

I'm trying to use setuptools_dso to build a package that needs its DSOs to be available for linking in third-party executables which are outside the package. On MacOS, the DSOs are being built with @loader_path/libname.dylib as their install_names which makes it impossible for the external executables to load them.

Is it possible to build the DSOs with @rpath/libname.dylib so that external executables can also load them? I noticed that you're using install_name_tool to change the change the names of the dependencies from @loader_path/libname.dylib to @loader_path/relpath/libname.dylib. Instead of doing that, you can just add relpath to rpath when building and remove the install_name_tool step.

mdavidsaver commented 4 years ago

The short answer is that I think you can achieve the effect you want by running install_name_tool against your executable using a computed relative path (or an absolute one if you want to try the idea). You would have to assume that the placeholder install name for libA.dylib would remain @loader_path/libA.dylib.

The recipe involving install_name_tool and @loader_path/ is awkward. An equivalent, or more flexible, alternative would be welcomed.

The main limitation to my making progress here is my lack of experience with, and lack of access to, OSX. I'll admit right away that I don't understand @rpath. The name, and man 1 dyld, suggest that it is similar to the ELF feature, but I don't immediately see how to make use of it. Linking a library libA.dylib with -install_name @rpath/libA.dylib seems clear enough. But I'm not sure what to give when linking a dependent library. Maybe -rpath @loader_path/../../moduleA/lib? I don't have access to an OSX host, so it's difficult for me to experiment.

mtikekar commented 4 years ago

Turns out the following patch was good enough:

diff --git a/src/setuptools_dso/dsocmd.py b/src/setuptools_dso/dsocmd.py
index 70b15bc..8fc9f73 100644
--- a/src/setuptools_dso/dsocmd.py
+++ b/src/setuptools_dso/dsocmd.py
@@ -140,7 +140,9 @@ class dso2libmixin:
                         else:
                             raise RuntimeError("Something wierd happened.  Please report. %s"%full)

-                        self._osx_changes.append(('@loader_path/'+fullname, '@loader_path/%s/%s'%(os.path.relpath(dsopath, mypath), fullname)))
+                        p = os.path.relpath(dsopath, mypath)
+                        if p != '.':
+                            soargs.add('-Wl,-rpath,@loader_path/%s' % p)

                         # In theory '-dylib_file A:B' asks the linker to do the equivlaent of:
                         #     install_name_tool -change A B
@@ -341,7 +343,7 @@ class build_dso(dso2libmixin, Command):
         if sys.platform == 'darwin':
             # we always want to produce relocatable (movable) binaries
             # this install_name will be replaced below (cf. 'install_name_tool')
-            extra_args.extend(['-install_name', '@loader_path/%s'%solibbase])
+            extra_args.extend(['-install_name', '@rpath/%s'%solibbase, '-Wl,-rpath,@loader_path'])

         elif sys.platform == "win32":
             # The .lib is considered "temporary" for extensions, but not for us

The way I see it, if you link libA.dylib with -install_name @rpath/libA.dylib and link any dependent library with -rpath /path/to/libA.dylib, you get the the ELF-equivalent behaviour. And if you're using $ORIGIN to make it relocatable, you simply use @loader_path instead.

mdavidsaver commented 4 years ago

Can you make a pull request? I'd like to see the CI tests pass.

navytux commented 4 years ago

I don't have access to an OSX host, so it's difficult for me to experiment.

@mdavidsaver, FYI not having a physical Mac, I'm using https://github.com/kholia/OSX-KVM on a Linux host to verify how my Pygolang works under OSX. OSX-KVM works relatively ok.

navytux commented 4 years ago

(I see there are some changes on OSX-KVM side; For me it is working as of 64fcc1ef "Batch update for December - 2019", i.e. before switch to "open core")

navytux commented 4 years ago

(OpenCore turned out to be another bootloader, not a new development model)