Creating symlinks in OSX frameworks inside app bundle - macos

I need to create symlinks in frameworks inside an app on OSX (vers 10.10.1). I am outside of XCode as the app is developed in Qt. It provides the frameworks, but they need some retouches to work on the new codesigning rules.
I call "ln -s path_origin path_target_link" and apparently it works, the links are created and they resolve to the right place.
But when I codesign the app, I get an error "unsealed contents present in the root directory of an embedded framework"
(In order to verify my procedure, I copied a framework from another package downloaded that validates codesigning and I could sign it successfully, when I create a symlink my way codesign starts to give the error so I'm assuming the problem is my symlink creation)
I tried other methods with the same result so I must be missing something. Any ideas?

For the case it's useful to anyone. In my case the problem was that I was creating the links with absoulte paths. Obviously they should be relative: You move to the directory where the link should go and create the link relative to the current location.

Version 1 code sign recorded only files in the Resources directory and ignored the rest. But version 2 records substantially all files by default. So we have to sign each and every frameworks bundle's versions and app binaries.
Ensure your framework bundle structure is meet the requirement of apple.
According to Apple's documentation, framework bundles don't have a 'Contents' folder. Instead, each version folder gets a 'Resources' folder which contains the Info.plist file, and which is also symbolic linked at the top-level framework folder. Qt5 frameworks have incorrect layout after SDK build, so this isn't just a problem with macdeployqt, but whole framework assembly part.
so confirm, there is no faulty layout in your app bundle.
If you have a *.prl in your Qt framework bundle (i.e.QtCore.framework/QtCore.prl). *.prl file may cause trouble for you as codesign just bails out with "unsealed content presents in the root directory of an embedded framework" without telling exactly what's going on. Strip if you have any prl files.
It is necessary for the Info.plist to have the correct CFBundleExecutable field. At the moment it doesn't. The debug version of Info.plist would overwrite the release version, and it also happens to contain invalid data. In particular, CFBundleExecutable would contain the _debug suffixed library name, which it shouldn't. If you have this problem then modify the incorrect info.plist.
The last step is you have to codesign all the frameworks before you sign the entire app bundle.

For anyone confused about this issue, you can refer to Apple's documentation https://developer.apple.com/documentation/bundleresources/placing_content_in_a_bundle
It contains all the details for macOS/iOS/MacCatalyst/watchOS/tvOS...

Related

macOS Application Bundle Frameworks Directory Codesign

I am packing my macOS application into an application bundle. I need to codesign it and pass notarisation. It is possible to put the frameworks in the "Resources" directory?
I have two frameworks. Normally, I used to put such frameworks into the "Frameworks" directory of the bundle. However, for (stupid) designing reason I need to have some more libraries in the same directory of my frameworks. Since such libraries will prevent code signing if placed in the directory "Frameworks", I want to move frameworks + extra libraries into the "Resources" directory.
Reading Apple documentation it seems that frameworks should - of course - belong to the "Frameworks" directory, however I could not find any reference to what should NOT be included into the "Resources" directory. Is this bad practice? Would my .app structure not pass gatekeeper?
Any suggestion would be very much appreciated
You've probably already tried putting a frameworks in Resources by now. As you said, even if it works today, this is not a good idea.
You might be able to work around whatever issue caused you to want to do this by using the install_name_tool to change one of the paths built into your frameworks. Adding symbolic links are another handy device for issues like this. This kind of stuff can be done automatically in a Run Script Build Phase or a Build Phase Post Action.

Can I put info about multiple executables inside the same bundle in Info.plist?

I have a Qt app that uses Assistant to display help.
On Mac, I am packaging he Assistant inside the bundle. The only way I can include all its libraries is by placing the Assistant executable inside the same MacOS folder as the app executable, and properly link all the library dependencies.
Is there a way to place information about both executables in the Info.plist ?
No, you can't put info about multiple executables inside the same Info.plist. (Well, you an always puts custom keys into the Info.plist and store whatever property list data you like there, but the system won't pay any attention to those keys.)
Why not bundle the Assistant into its own bundle and put that bundle inside the main app's bundle? The Assistant bundle would have its own Info.plist file. Also, if you create a question about whatever linking or dynamic loading problems made you think you had to put it all into the main bundle, you might find there's a better solution.
placing the Assistant executable inside the same MacOS folder
I recommend not to do this. The Assistant is a resource to the main application and so it should reside in the resources folder. If you want to launch the Assistant app from the main app, you can then locate it by name.
You can only define one application in the Info.plist. If you were to add more, there would be a conflict in keys.
For example, CFBundleIdentifier is a unique URI that names the bundle (e.g. com.apple.calculator). The OS uses the URI to register the application with the OS when an application is, for example, copied to the /Applications folder. The OS expects the key to be a child of the root dictionary and its value must be unique. If there were multiple keys named CFBundleIdentifier, it would not know which is valid.
Although you can throw almost any junk into a Mac application bundle, much good will not come to you.
If I understand right, you have both a Mac Application (bundled normally) and a side-application you call the "Assistant" you want embedded in the same application bundle.
You also mention libraries (.dylib's I guess) that must reside in the same directory as the assistant.
Now - if these libraries are only used by the Assistant side-application, I would recommend that you bundle the assistant as a Code-bundle (Apple provides lots of information about these, and you have easy to use templates from Xcode). You can then use Xcode to copy it into the right place within the main application's bundle (I'd choose "Plugins") and use NSBundle APIs to launch it.
However, if those .dylibs are shared between the main app and the assistant - then I'd say go ahead, stick your assistant, .dylibs and main app's binary files in the same "MacOS-X" directory, and use posix APIs, or shell command to launch the assistant. Of course it will share (if possible) every resource of the main application, because they are located at the same place. However, the main app's bundle can only have ONE CFBundleExecutable entry, and that should point to your main application's binary.

codesign wants me to sign my data files as well?

I have an OSX application, and in the bundle's MacOS directory, I have an executable and a bunch of dylibs. The executable is, of course, pointed to by the Info.plist's CFBundleExecutable entry. When I try to sign it, codesign complains (as of 10.9) that my dylibs aren't signed, which makes sense. So I sign all of the dylibs, which I would think would let me sign the main executable now.
The problem is that I actually have a couple of data files in my MacOS dir, as well. The application is a cross-platform Qt application and the data files are localizations files that are found with respect to the main executable. codesign complains that it doesn't want to sign my main executable until the data files are signed.
Is this just a fundamentally wrong thing to be doing - putting anything that isn't mach-o into MacOS? Is signing those data files even a reasonable thing to do - ie like a .cat file on Windows? Clearly I wouldn't want codesign haphazardly slapping a digest hash on to the end of my data files.
Yes those data files should go into the Resources folder.
From the Bundle Programming Guide
MacOS (Required)
Contains the application’s standalone executable code. Typically, this directory contains only one binary file with
your application’s main entry point and statically linked code.
However, you may put other standalone executables (such as
command-line tools) in this directory as well.
Resources
Contains all of the application’s resource files. This contents of this directory are further organized to distinguish
between localized and nonlocalized resources. For more information
about the structure of this directory, see “The Resources Directory”
Codesigning the data files won't change them; they are simply recorded in the _CodeSignature/CodeResources file.

Using Dylibs Inside App Bundle

I am trying to compile an app that uses multiple libraries using Xcode. To do so, I created a script that copies all of my .dylibs from a location on my computer to the Frameworks folder inside my app bundle.
After adding the necessary linker flags and header search paths, I must now add my library search paths.
Since I have copied all the libraries inside my Frameworks folder of my app bundle, I have deduced that I must add $(FRAMEWORKS_FOLDER_PATH) to the library search paths setting. Adding this fails, because the linker can not find that directory.
I am guessing that the Frameworks folder isn't created until after searching the library search paths setting. If so, how am I supposed to use the libraries that I have copied inside my app bundle?
Placing the .dylib files in the Frameworks folder is something you do so that the application can find them when it runs.. dylib files are dynamically linked, so the application loads them at run time.
Setting Xcode up to link to the .dylibs at compile time should just be a matter of dragging the .dylib from the Finder into your Xcode project. I've shown this with a simple example project that uses libxar.dylib in the attached screenshot.

Creating a Cocoa Framework

I've created a working Cocoa framework which I wish to redistribute. The problem is however, it won't run outside of Xcode. I've read something about #executable_path/../Frameworks, which I did not include, because I don't know where to put it :/
Therefore I run my app in Xcode using the DYLD_FRAMEWORK_PATH variable which works fine, but only in Xcode - if I try to run it on its own it crashes straight away and says IMAGE NOT FOUND.
I'm sure #executable_path/../Frameworks is what's missing, but I don't know where to put it.
Could anyone help me out please? :)
Thanks
Here is how I usually manage things:
In the framework's Xcode project, set the Installation Directory to #rpath
Add the framework to your application's Xcode project. Add a Copy Files build phase, select Frameworks in the Destination popup, and ensure your framework is added so it will be copied to your application's Frameworks directory when it is built.
Finally, in your project's settings, add #loader_path/../Frameworks to Runpath Search Paths.
Are you actually copying the framework into your applications bundle? Look for the folder called MacOS which is what contains the binary. There should be another folder at the same level called Frameworks and it should have the framework inside it.
If it's not there you need to create a copy files build phase for the application that copies the framework into the Frameworks folder.

Resources