Use files from /usr/local/share inside OS X app bundle - macos

I’m writing Qt application using some 3rd party library. I want to package it into a bundle.
I’m using macdeployqt and this tool isn’t just copying Qt Frameworks, but also 3rd party library into Contents/Frameworks inside the app bundle.
The problem is that this 3rd party library need some additional file to work properly. Originally library is installed in /usr/local/lib and some necessary stuff is located at /usr/local/share.
How to package this stuff into app bundle?

I think it depends on how the specific library is coded. If the paths are hard coded as full paths or relative to some system path, then there's really nothing you can do. One possible solution is to include the files as resources and install them during the startup of your app when you detect that they are missing in the user's system.

Related

Adding swift framework extracted from IPA

I'm trying to run an IOS app created by another dev that is using a cocoapod from a private repository I have no access to. I managed to extract the .framework bundle from the IPA and add it to the xcode project but it is not being recognized (I get "No such module").
Is it possible to do what I'm trying to achieve?
So far, what I've tried:
build it in release as I guess the framework in the IPA is in release
add the .framework as embedded binary
add the .framework as Linked Framework and Libraries
copy the .framework to ~/System/Library/Framework
update the Frameworks Search Path including $(SRCROOT), recursive, hardcoded paths, etc.
change the .framework location to "Relative to Build Products"
Thanks!
It wasn't that much easy to get the frameworks used in project from ipa file.
Whenver the application runs for first time, also when you archive your application, all the linked .frameworks will get converted to .dylib that is dynamic libraries.
What is static library - a unit of code linked at compile time, which does not change.
What is dynamic library - a unit of code and/or assets linked at runtime that may change.
Framework - A framework is a hierarchical directory that encapsulates a dynamic library, header files, and resources, such as storyboards, image files, and localized strings, into a single package. Apps using frameworks need to embed the framework in the app's bundle.
Dynamic Library
A dynamic lib file is just resides inside the framework folder.
Following is a description from apple documentation
Dynamic libraries outside
of a framework bundle, which typically have the file extension .dylib,
are not supported on iOS, watchOS, or tvOS, except for the system
Swift libraries provided by Xcode.
Ref: Documentation
So you cannot simply copy a .dylib to xcode bundle and just use it. There is some sort of security too.
Another approch
It is possible to decompile the source code from .ipa files. You will get idea from below links.
SO Question regarding decompiling of ipa file
Decompilation Possibility
It seems that when an app is archived for distribution, the Headers and Modules folders are removed from the .framework bundle.
The Header folder contains the .h headers for Objective-C and the Modules folder contains the .swiftmodule equivalent files for Swift.
Without these files you have no public API to consume for the framework binary, so unfortunately this renders the frameworks unusable without reverse engineering.

dylib to dylib pathing on mac osx, how to make rpath work on mac?

We have a project which dynamically links against several dylibs. When copy the build to another mac. One need to run "otool" over the dylibs and executable in order to fix the shared library paths in them during "install".
Looks like OSX had some strange requirements for DLL to DLL pathing that made relative paths not work in them (i.e: using rpath). My questions here:
what is the the normal way to ship a software on mac? i.e: when running either a .pkg or .dmg installer, how one make sure the dylibs installed are able to link against each other in relative path? the dylib path must be fixed with either the rpath or some post install scripts
if we are not allowed to run a post install script to fix this, what are the other options?
Relative paths should work just fine. For example assume a macOS application bundle. The application lives in Contents/MacOS while the library lives in Contents/Frameworks. In this case you would relink the application's libraries to something like this #executable_path/../Frameworks/library.so. If you don't use an application bundle but have all files in the same directory simple using #executable_path should work too.
No need to use #rpath in these examples. you can use this too but it requires the application to define this path. This may be helpful if you want to distribute a library and people are supposed to link to your library. That way they can give an #rpath in their application to find the library without otool-ing them.
And you of course you make these changes before your package up your application into a .dmg or .pkg.

What are Embedded Binaries in Xcode?

I'm using Alamofire in a Swift project, and part of their manual installation instructions are to add Alamofire under Embedded Binaries in the General tab for my application target.
What are Embedded Binaries?
Embedded binaries are binary files that are copied to your application bundle when you build the project. Use embedded binaries when your application relies on third-party frameworks so people can use your application without needing those frameworks installed on their machine. Embedded binaries keep users from having to manually install third-party frameworks. Your application uses the framework you embedded.
In your Alamofire example your application relies on Alamofire. If you didn't embed the Alamofire framework, nobody would be able to use your application unless they installed Alamofire manually. By embedding Alamofire with your application everyone can run your application.
"Binary" means: compiled code — as opposed to "source code", which is what you are working with when you write code as text.
They could have given you source code and let you compile it, but they didn't; they are keeping the source code secret, so they've given it all to you after compilation, so that you can't read it.
"Embedded" means: to be included inside your app bundle, by copying them into it at build time.
So, they are handing you some compiled code (frameworks) and telling you how to include them inside your app bundle. These frameworks, unlike Cocoa's frameworks, do not already exist on the device, so if you don't include them inside the app, they won't be present and your app would be unable to call into them.
Contrast this to Cocoa's frameworks. They, too, are compiled code. But they do already exist on the device. Therefore they are not embedded inside your app; they are merely linked (and, if they appeared, would appear in the next group, Linked Frameworks and Libraries).
Embedding binaries copies the entire framework to the target.
A framework is a hierarchical directory that encapsulates a dynamic
library, header files, and resources, such as storyboards, image
files, and localized strings, into a single package. Apps using
frameworks need to embed the framework in the app's bundle.
So, when you embed a framework in your app, it increases the size of your app because it is copied to you app bundle. In most of the scenarios we will be using this sections when we are using third party framework.
When we add a framework to Embedded Binaries it automatically adds that framework to Linked Frameworks and Libraries also.
Refer to apple documentation for more details: https://developer.apple.com/library/archive/technotes/tn2435/_index.html

install app on mac with shared libraries outside bundle

I am working on a Qt app with some library dependencies, for which I will have to make an installer.
From everything I read, seems like the best way is to make a bundle app with all library dependencies, and the required Qt frameworks, inside myapp.app/Contents/Frameworks
There are other applications created in parallel... that will get to be deployed on mac as well. They will have the same library dependencies and will be built using the same Qt version.
In that case it makes sense for the libraries and Qt to be installed OUTSIDE the bundle... so both (all) apps have access without having multiple copies of the same libraries.
Does that seem reasonable - and do-able with mac osx concept of bundle islands ? And how would I create such an installer that places libraries outside the app bundle ?
The simplest method of deploying Qt for OS X is to use the macdeployqt command line tool, and you have identified correctly that the normal method is to place the frameworks inside the app bundle, but multiple apps will each have copies of the frameworks.
It is reasonable to suggest moving the Qt frameworks to a separate, external location and linking to that instead. However, you will need to manage the framework carefully, especially when it comes to providing updates and be aware that if the framework is removed or altered, all your applications will fail to load. This, however is the same for any framework dependent application.
The thing to consider is where to place the framework. Normally, external frameworks reside in /Library/Frameworks, but if we all start to use that for Qt, problems may occur when your app is installed and another developer installs their app's frameworks with a different version of the libraries.
Apple defines various 'key directories' for applications and initially, the most likely location would appear to be the "Application Support Directory", but the documentation states that this is for: -
any type of file that supports the app but is not required for the app to run
This location is often used for support files, such as templates for the user to select.
If your application is to be deployed via the Apple Store, I wouldn't be surprised if it is rejected if you use this location. However, you're not using the Apple Store, then you could deploy the frameworks here.
If the Apple Store is your method of deployment, then /Library/Frameworks is probably the only place acceptable for the Qt framework to reside, with the possibility of the problems I've mentioned above.
Alternatively, consider just how many applications you're developing and is it really an issue to bundle the frameworks multiple times against the advantages that it brings, such as allowing the user to cleanly remove the application and all of its dependencies, as well as reducing problems of the framework being altered or removed accidentally?
If you choose to move them externally, you can refer to the answer to this question, which comprehensively explains how to make installer packages, after having updated your binary dependencies on the frameworks with the install_name_tool, as outlined here.

Using frameworks in a command line tool

I've built a command-line utility (Foundation tool) in Xcode, using Cocoa. The tool makes use of a 3rd party framework.
Everything works OK in Xcode, but how do I deploy this program?
If I run the app from Finder, it can't find the library because it's looking in ../Frameworks/etc. Can I statically link in the 3rd party framework?
Unfortunately, there is no way to bundle a framework with a command-line Utility in OS X and I suspect that the framework you're linking to is expecting to be bundled in the app bundle's Frameworks/ directory. If you have access to the framework source code, you can compile a static library and statically link it to your application (or include the source in your application target directly). If you don't have the source code or you don't want to statically link the library for some reason, there are two remaining options:
If you have access to the system-wide /Library/Frameworks folder, you can install the 3rd party framework there. This require that the framework's Installation Path (the INSTALL_PATH build setting) be set to /Library/Frameworks at build time or that you use the install_name_tool to change the frameworks install path to /Library/Frameworks (if you don't have the framework's source code).
Build an application bundle (as if you were building a GUI app) with your command-line utility as the app bundle's executable (i.e. in AppBundle.app/Contents/MacOS/). You can then copy the 3rd party framework to the app bundle's frameworks directory. You can then put the app bundle anywhere you want and create a symbolic link to the command line utility.
Option 1 is definitely the more accepted approach, but I've used option 2 when there was a valid reason.
You can find more information on building, linking, and installing frameworks in Apple's Frameworks Programming Guide.
Another way, if you have the source code for the framework, is to add a static library target and build a static lib from it. Then you can statically link it into your command-line tool.
As of Xcode 9.3.1, I was able to have the framework added to the command line tool by setting the Mach-O Type to Static Library for the framework. Then in the command line target make sure to add the framework to the Target Dependencies & the Link Binary With Libraries Build Phases. The built executable was then able to run with no issues.
You can use marathon to manage dependencies
https://github.com/JohnSundell/Marathon
This would need more thought if you wanted to distribute app. (You would probably want to install into frameworks folder in that use case.) your mileage may vary with this solution.

Resources