Is there a best practice for importing static library headers in Xcode 4? Most of my projects depend on several other projects, so that I recently started to use the workspace feature to build all needed modules from one place (which I find very convenient).
What sucks is that we can’t use custom frameworks on iOS, so that the dependencies have to be built as static libraries and I get problems with header search paths. Whereas frameworks keep their headers with them inside the framework bundle, static libraries don’t have the option. I hate to set up user header search paths individually for each library I import. Ideally I’d like to drag the dependency project to the workspace, add the library to the main target and build, without further settings. Is this workflow supported?
The best solution I currently have is to keep all the supporting libraries in a common folder (say Support
), setting the header search path to Support/**
. Feels clumsy, but works.
What I do is rather complicated, but it works well for me.
In the settings of the static library project, in the "Packaging" section, I set the "Wrapper Extension" to "framework". I then change:
"Public Headers Folder Path" to "$(PRODUCT_NAME).$(WRAPPER_EXTENSION)/Headers"
and
"Private Headers Folder Path" to $(PRODUCT_NAME).$(WRAPPER_EXTENSION)/PrivateHeaders
The end result in the build products is a folder named "MyLibraryName.framework" the guts of which look just like... well.. a Framework. One thing I like about this is I can use Framework-style includes in my code:
#include <MyLibraryName/blah.h>
The downside is that (as discovered in the answer from "zoul") the "Archive" command doesn't work properly. The reason it doesn't work is because the Archive command separates the final build products and the target build products into separate directories. A normal "build" doesn't do that. When you archive the system tries to find the static libraries headers in the final build products directory and can't find them because the system put them in the target build directory for the static library.
If you think about it, Xcode thinks your static library's target has a single "product". That product is "libMyLibraryName.a". But really the target has two products... one is the library, and the other is the set of headers for the library. The problem with the Archive command is that the library is copied as a build product, but the headers are not. You end up with "header could not be found" when you try to run the archive.
To fix THAT, what I do is use a Run Script build phase. The script looks like this (written in Ruby):
if ENV["TARGET_BUILD_DIR"] != ENV["BUILT_PRODUCTS_DIR"] then
$product_name = ENV['PRODUCT_NAME']
$wrapper_extension = ENV['WRAPPER_EXTENSION']
$target_build_dir = ENV['TARGET_BUILD_DIR']
$built_products_dir = ENV['BUILT_PRODUCTS_DIR']
$source_file = File.join($target_build_dir, $product_name + "." + $wrapper_extension)
$dest_file = File.join($built_products_dir, $product_name + "." + $wrapper_extension)
system "ln -s #{$source_file} #{$dest_file}" if File.exist?($source_file)
end
So if the Target build directory and the built products directory don't match... create a symbolic link to the fake "Framework" I've created in the built products dir.
As I said, this is a complex scheme but it works and lets me use framework-style includes which I like. The whole mess would be greatly simplified if Xcode would let iOS developers create Frameworks (which would also mean that iOS would let developers create dynamic libraries, something Apple is reluctant to do) or if Apple would create a variant of frameworks... a package that contains a static library and the headers that go with it (a static_framework?) so that you have one build product that contains both the headers and the static library.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With