-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add functionality to Xcode template to bundle dylibs #7358
Conversation
@dimitre the drawback I see with your suggestion of combining script steps is that the Xcode script editor is annoying to work with, so longer scripts translates to more effort in scrolling/locating things... with separate steps the enabling flag conditional is right there at the top for all of them; makes it easier to figure out than a switch 25 lines down? |
@artificiel yeah I agree. in any case to read / edit I always copy to an editor. for the average OF user only uncommenting defines in Project.xcconfig will be all that is. if they need some of the flags. |
or: the Xcode script step is a single-liner that calls another script which is held in it's own .sh file? it augments readability and simplifies maintenance (fiddling with the json pbxproj is not exactly enjoyable...) |
It is the best! we can use the variable $OF_PATH to point to some path in OF project. Edit: Another advantage of a fixed script, is if we update and fix scripts in one place in OF, all projects are up to date automatically, no need to regenerate it using PG. |
Hmm I think a preferable solution would be one that didn't rely on installing brew and a 3rd party tool.
I have done this manually before and I think it could be fairly easy to automate. But maybe I am missing something here? Another script build phase which has been on the TODO list is App Notarization which with a few defines in the xcconfig could be automated too. Edit: this would also require that any dylibs that are linked to the project are copied to the Frameworks folder ( if that isn't happening currently it should ) so that should allow things to survive PG rebuilds. |
@ofTheo it is certainly possible to reproduce the functionality but macdylibbundler is ~1000 lines of C++ so I don't know if it can be said to be "fairly easy to automate". I initially started like everyone else trying to script it within Xcode (like this which is the basic starting point https://stackoverflow.com/questions/42022884/making-xcode-embed-necessary-dylibs), then after hitting many little friction zones looked at various more "complete" bash and python scripts (as documented in #7277) but they did not cover all aspects of my requirements, notably being recursive (my use case is a library that relies on another library). macdylibbundler worked correctly and completely (while being malleable with flags to cover different scenarios). After spending a bunch of semi~enjoyable hours with otool & company and (reading other's purpose-specific scripts) I don't see the value of re-implementing what is existing. I can re-state that the approach of having a post-process step in the addon_config (as implemented here openframeworks/projectGenerator#217) is a more generic solution that I might have harnessed without touching the Xcode template as the equivalent script and instructions would be provided within the addon and injected by PG -- but that opens another can of worms as Apple does not provide an API for manipulating the .pbxproj, so potential fragility/maintenance. Also re-state the goal: making use of an addon that provides .dylibs and produce a self-contained .app in a generic workflow (no pre-determined paths or dylib names) that survives PG. It's a bit specialized and currently not possible in a fluid manner, and at that point I find the requirement of brew a minor hurdle, considering the audience it is addressed to. From your comment I understand it's also a pre-requisite for notarization; I haven't been looking at notarization as it's out of the current project scope (can take a look a bit later) but yes things are copied (from #7277) : (Note that the config signs and puts the .dylibs by default in a ./Content/libs/ directory (and not ./Content/Frameworks/) -- that's changeable, but apparently better not to clutter the Frameworks/ with non-frameworks) |
@ofTheo what about starting with a solution which uses homebrew? |
@dimitre Will have another look over the changes, but I think that could be a good approach. |
well dylibbundler handles it all automatically! you just need to point it to your .app and a starting point (which are found by looking for *.dylibs in LD_FLAGS), then it hunts the dependencies, intelligently copies things (deduplicating if needed, and excludes system libs), and rewrites the paths (all that takes 1-2 seconds). some of them surprised me... and i was also surprised that it «just worked» when deploying on the other machines... |
heheh well grab the PR, curious to see it in action in another env. |
I can work in joining scripts after this one is merged |
Problem: moving an app between machines requires that (1) all required dylibs to be bundled within the .app and (2) their paths to be tweaked in order to be found at runtime (including paths in dylibs-depending-on-other-dylibs). It's a hairy process to do manually, and also hairy to automate in a manner that survives a PG project update (as all tweaks to the project are lost).
This leverages https://github.com/auriamg/macdylibbundler (commonly available as
brew install dylibbundler
). The script first scans the Xcode project for all referenced dylibs that would be provided by addons and passes them to dylibbundler, who will copy and work recursively from these dylibs, automating theinstall_name_tool
dance (and also signs the dylibs). A Project.xcconfig flag enables the script, which is disabled by default.So as an end user: make a new project in PG; choose an addon that provides macOS .dylibs; activate the flag; build the project; and the dylibs are copied and tweaked within the .app bundle, that you can then copy on another machine. (of how far that translates depend on many factors (are the dylibs ARM+intel, specific project compile flags, OS version, etc).
As an addon writer: collect the required .dylibs inside your addon libs/ directory and doctor them once to play well together (the case of custom dylibs relying on custom dylibs will be correctly tracked by macdylibbundler, however some
install_name_tool
'ing of the "leaf" dylibs might be required to handle both bundled and not bundled).more at #7277
NOTE: the problem this solves could have been addressed differently by augmenting the PG/addon with a post-processing step. I recently came about this PR openframeworks/projectGenerator#217 that could solve the problem by enabling the execution of a script that would "inject" another script step into the pbxproj. however it would rely on some less-common software to manipulate the pbxproj. It would also make it brittle against future template modifications. Likewise, a custom template could be made ("Xcode-dylibbundle") but would require future double-management of the Xcode template.
Having a disabled script tucked within the template is the best compromise. Tested between M1 and M2 machines with macOS12 and 13.
#changelog #osx