Creating static framework for OS X - xcode

With the use of a mild hack, it is possible to make static frameworks for iOS. Static frameworks are quite convenient to use: they can simply be dropped into new projects without extra steps (like adding them to the build and adding header search paths).
I've recently started doing OS X programming, and the first thing I noticed was that static frameworks don't seem to be available. Dynamic frameworks are obviously available and recommended, but as I want to make a little private framework intended for application use (not installation in /Library/Frameworks), using a dynamic framework in new application projects still requires a bunch of extra steps.
In my ideal world, I'd create a static framework (a framework which contains header files and a compiled .a file), drag & drop the framework onto a new project, and start coding. Is there any way to make such a static framework on OS X?
P.S. I already tried setting the Mach-O output type to "static library" in a normal framework project, but I just get the error Framework target has invalid MACH_O_TYPE value of 'staticlib'..

You can create a dynamic framework on Mac OS X. In your dynamic framework you can set the LD_DYLIB_INSTALL_NAME as #rpath/Foo.framework/Versions/A/Foo
If you have an app that wants to link with this framework then you make sure you run the
install_name_tool -add_rpath <rpath> <full-path-to-app-binary>
So if I had Foo.app
install_name_tool -add_rpath Foo.app/Contents/Library Foo.app/Contents/MacOS/Foo
Now if you just copy your Foo.framework into Contents/Library it should get loaded and everything should work.
I hope this helps.
Probably simpler would be to use a static library with public headers. When you build the static lib you can have Xcode copy the headers for you automatically. And in your target you can add the folder to your search path.
If you use a static library Xcode will strip away some dead code that your app doesn't really need but is compiled into the static lib.

Static frameworks aren't really supported on OS X. They're fairly brittle anyway, and solve a specific problem that exists on iOS but not on OS X.
If you're looking to make it easy for developers to use a library you create, you have a couple options:
Use Cocoapods. They have a tutorial for publishing your library on CocoaPods. This is probably the easiest way to distribute a library on OS X.
Package your library as a framework. If you set the install name correctly (to #rpath/<library name>), the downstream developer merely needs to copy the framework into their Xcode project and set the runtime search path of their application to #executable_path/../Frameworks).

Related

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.

Making framework private with install_name_tool being ignored

I have written a simple application using the GPhoto2 Framework, and this works so long as the framework is in the location where it was originally compiled. I would like to move this inside the app bundle, though, so it does not need separate installation, so I need to make it work relative to this main executable.
Unfortunately the framework is not an Xcode project. It uses a script to build, so I cannot simply change the installation directory build setting, which is the solution that I have frequently seen while searching for an answer. Being quite new to Xcode and Mac programming it is also beyond my abilities to know how to convert the framework into an Xcode project.
The other advice I came across was to use install_name_tool to update the library ID and dependencies, replacing the absolute paths with ones of the form "#executable_path/../Frameworks/GPhoto2.framework". The framework is not a single binary, but contains a number of .dylib and .so libraries, but updating all of these has only been half successful.
I have set Xcode to copy the framework into the app bundle when it builds it. Then if I remove the framework from its originally compiled location the application fails to load, with the report generated by OS X saying the libgphoto2 library can no longer be found, as to be expected.
If I then use install_name_tool to update the references in all of the framework libraries inside the app bundle, and also in the app binary itself, then the application will load but fails to find any camera connected. Using otool I am able to verify that all references have correctly been changed.
But if I replace a copy of the framework to its original location it then works properly again, recognizing connected cameras, regardless of whether that framework uses relative or absolute locations. Clearly it is still looking at this location despite loading. I have even tried removing each of the individual library files from the framework in its original location in turn to see if the problem was just the result of a dependency in of these, but no matter which is missing the app will not work.
Incidentally, if I build the app using an updated version of the framework, it fails saying it cannot find the library "#executable_path/../Frameworks/GPhoto2.framework/prefix/lib/libgphoto2.2.dylib"
Am I doing something wrong or missing a step, or is what I am trying to do impossible for frameworks created outside Xcode?
In case someone comes across this future, the answer to my question was that I was doing nothing wrong. The problem was that the .so files were being loaded by libtool ltdl, at it requires absolute paths so these were being set at build time.
I patched the files gphoto2-abilities-list.c and gphoto2-port-info-list.c so that at runtime it would combine the relative library paths with the executable location. As a result I also needed to increase the FILENAME_MAX constant to allow it the mail application to run from, for example, the Desktop. But this, along with the use of install_name_tool allowed me to add GPhoto2 as a framework inside my application without needing any external dependencies.
The final problem of not being able to build my app in XCode with the framework after using install_name_tool remained, but for that I just used the original framework build, then after compilation I updated the references in the copied framework at the same time as I updated the ones in the main executable.

What steps are involoved in loading a .Framework under MacOS X?

I am realtivly new to the concept of dynamic loading and shared libraries. While I fully understand how dlopen() could be used to reference symbols in a shared library I have yet to fullt grasp what MacOS does behind the scenes when I don't statically link against something. When adding a framework to Xcode I have the option to load it into my project or I can just provide some form of symlink to it(the actual implementation is obfuscated be the easy to use interface).
There after all I seem to need to do is import the header files that porvide and API to these frameworks and I can just invoke their symbols free of hassle. Can someone explain to me what I am actually doing, because it make no sense to me.
The sheet you're referring to has nothing to do with the actual linking of the framework. The copy vs. link choice refers to how you want to include the framework in your Xcode project, not your app binary.
For system frameworks there really isn't anything you need to do but import the headers.
For custom frameworks (your own or third-party) the framework must reside at the load path directory when your app launches. Typically the load path will point to your app bundle's Frameworks (sub)directory, so you must add a Copy Files build phase that copies the framework to your app bundle's Frameworks directory.
Remember to check out Apple's Framework Programming Guide, especially the section on frameworks embedded in your app bundle.

Creating a library (.a) in Mac OS X and Xcode

I'm in the process of porting some code from Linux to Mac OS X. The code is a static library that you add to your code. Basically after you compile the code you get a MyLib.a that can be linked to whatever project you want.
I'm managing the "project" via a Makefile.
Is there a way to have a project on Xcode that ultimately produces the same kind of library? How?
Thank you for the help.
Sure. You don't say so, but I am assuming you are using C or C++ as source.
Assuming you are using Xcode 3.2.2, you can create a new project (File > New Project...), which will bring up a New Project window with available project templates. Select the "Framework & Library" category under Mac OSX from the list on the left. You should now see a "BSD C Library" and "STL C++ Library" among the other library and framework types. For building a static library like you described you want the "BSD C Library" option. There are static and dynamic options for this which you will see when you click on the icon, but static is default.
Depending on which version of Xcode you are using, the location of the project template may be a little different since Apple has been changing this UI for the New Project window fairly frequently. So if you are not using 3.2.2 you may need to poke around the available projects a little bit.
Oh, and don't worry if you are trying to build C++. Event though this says it is for C, C++ libs build just fine as well.

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