name mode size
App 040000
Child 040000
Tool 040000
Umbrella Framework Symlinks.xctemplate 040000
Umbrella Framework.xctemplate 040000
Umbrella.xcworkspace 040000
Umbrella 040000
icon 040000
.gitignore 100644 0 kb
README.md 100644 6 kb
install-templates.sh 100755 1 kb
README.md
# Umbrella Frameworks What is an Umbrella framework ? It's a frameworks that contains and exposes embedded frameworks. You only link against the Umbrella framework. But you can include the headers of the embedded frameworks without having to set crazy search paths. > An example of an Umbrella framework in OS X is <tt>CoreService.framework</tt> Ideally for development you would have the Umbrella.framework in a convenient space to link against, which would be <tt>/Library/Frameworks</tt>. An app could then when you package it for distribution, copy this Framework into its bundle Frameworks folder, possibly stripping away the headers. ## What works and what not 1) The C compiler picks up the embedded Frameworks directory from the Umbrella framework and adds it (silently) to it's search path. So <tt><Child/Child.h></tt> is found. 2) The dynamic loader picks up the information during execution. The App is only linked against the Umbrella framework, and the Child framework gets loaded. 3) The linker is stupid. It only needs to link against Umbrella.framework, but it gets confused with the @rpath of the Child framework, which it eventually doesn't even link against. 4) Nothing gets code-signed in this example. ## What's in this project ? ======= This Xcode workspace contains a minimal project with a **Tool** and an **App** project, that share the same Umbrella framework. For the tool to run, the Umbrella framework should be installed in <tt>/Library/Frameworks</tt>. For the App the Framework is embedded into the App bundle. The settings of all the targets and projects have been pared down to the minimum. So when you look at the **Build Settings** with **Basic** and **Combined** set, you should get an easy enough overview. Of the remaining settings I tried to change as little as possible from the way Xcode set up the projects by default. > When building from the commandline make sure you use **-scheme** and not **-target**. ### Umbrella Framework.xctemplate With this Xcode template you can easily set up your own Umbrella framework project. Use ``install-templates.sh`` to copy it to your ~/Library folder and restart Xcode. It should show up under "OS X" "Framework & Library". After creating the Umbrella target add your embedded frameworks as dependencies to the framework and edit the user defined build setting `MULLE_UMBRELLA_EMBEDDED_FRAMEWORKS`. ### Umbrella Framework Symlinks.xctemplate This template does a lot of shell scripting phases, so that you do not have actual copies of the embedded frameworks residing in /Library/Frameworks but just symbolic links. The resulting Frameworks are much "nicer", but the scripts mave prove to be fragile in the long run. ## Various Thoughts ======= ### Xcode strips off the embedded framework Headers during copy When Xcode copies the a framework it strips off the headers... sometimes. I guess it depends on the destination of the copy phase. Maybe there are some settings that avoids excluding the headers, but I couldn't figure it out from the [Xcode documentation](https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html) ``` PBXCp /Volumes/Source/srcM/mulle-umbrella-example/build/Products/Debug/Child.framework /Volumes/Source/srcM/mulle-umbrella-example/build/Products/Debug/Umbrella.framework/Versions/A/Frameworks/Child.framework cd /Volumes/Source/srcM/mulle-umbrella-example/Umbrella builtin-copy -exclude .DS_Store -exclude CVS -exclude .svn -exclude .git -exclude .hg -exclude Headers -exclude PrivateHeaders -resolve-src-symlinks /Volumes/Source/srcM/mulle-umbrella-example/build/Products/Debug/Child.framework /Volumes/Source/srcM/mulle-umbrella-example/build/Products/Debug/Umbrella.framework/Versions/A/Frameworks ``` This isn't bad for deployment only. ### Xcode passes LDFLAGs to clang, which may choke on them clang isn't aware of all linker flags. It doesn't (yet) know about `-reexport_framework` so one needs to use <tt>-Xlinker</tt> to shield the linker parameters: ``` OTHER_LDFLAGS = -Xlinker -reexport_framework -Xlinker Child ``` I see no technical difference between `-reexport_framework` and `-sub_umbrella`. `-reexport_framework` is according to the documentation more "modern". ### SKIP_INSTALL SKIP_INSTALL on the embedded framework toggles, if it will show up in /Library/Frameworks when you archive/install. If you go for symlinks, it's nicer to have SKIP_INSTALL turned on, otherwise it should be turned off. ### Running the targets in Xcode may give surprising paths That is, because the Frameworks are lying besides the executable and are loaded first. (Isn't that a bug really ? gotta check that) ``` $ otool -L /tmp/App.app/Contents/MacOS/App /tmp/App.app/Contents/MacOS/App: /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1343.14.0) @rpath/Umbrella.framework/Versions/A/Umbrella (compatibility version 1.0.0, current version 1.0.0) /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1151.16.0) /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0) /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 283.0.0) /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1151.16.0) ``` Notice that Child does not appear in the listing, which is good. ### Module map is "Neuland" to me I added a `module.map` file, which I don't really know what it's good for (Swift?) to the symlinked Umbrella framework just in case... ### Stuff that didn't work * Adding <tt>/Library/Frameworks/Umbrella.framework/Frameworks</tt> to ` LD_RUNPATH_SEARCH_PATHS` in the Umbrella did not help the linker * neither did adding <tt>/Library/Frameworks</tt> to `FRAMEWORK_SEARCH_PATHS in the App target help the linker. Adding <tt>/Library/Frameworks/Umbrella.framework/Frameworks</tt> would fix it though, but this is unwieldy IMO. ## Author created by Nat! 2015 [www.mulle-kybernetik.com]()