Alternate titles to aid search
- Xcode can't find header
- Missing .h in Xcode
- Xcode .h file not found
- lexical or preprocessor issue file not found
I'm working on an iOS application project which came from Xcode 3. I have now moved to Xcode 4 my project builds a number of static libraries.
Those static libraries also declare public headers and those headers are used by the application code. In Xcode 3.x the headers were copied (as a build phase) to the public headers directory
, then in the application project the public headers directory
was added to the headers search list
.
Under Xcode 4 the build directory is moved to ~/Library/Developer/Xcode/DerivedData/my-project
.
The problem is how do I reference this new location in the headers search settings? It seems that:
public headers directory
is relative to DerivedData
directory, butheaders search
directory is relative to something else (possibly the project location)How should I set up a static library target for iOS development in Xcode 4 that will ensure the header files are made available to the clients that use the static library when trying to compile as a dependancy?
Each of the solutions I've seen to this problem have either seemed inelegant (copying headers into the application's project) or overly simplified to the point that they only work in trivial situations.
Add the following path to your User Header Search Paths
"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts"
First, we need to understand the problem. Under normal circumstances, which is to say when you Run, Test, Profile or Analyze, Xcode builds your project and puts the output in the Build/Products/Configuration/Products directory, which is available via the $BUILT_PRODUCTS_DIR macro.
Most guides regarding static libraries recommend setting the Public Headers Folder Path to $TARGET_NAME, which means that your lib file becomes $BUILT_PRODUCTS_DIR/libTargetName.a and your headers are put into $BUILT_PRODUCTS_DIR/TargetName. As long as your app includes $BUILT_PRODUCTS_DIR in its search paths, then imports will work in the 4 situations given above. However, this will not work when you try to archive.
When you archive a project, Xcode uses a different folder called ArchiveIntermediates. Within that folder you'll find /YourAppName/BuildProductsPath/Release-iphoneos/. This is the folder that $BUILT_PRODUCTS_DIR points to when you do an archive. If you look in there, you'll see that there is a symlink to your built static library file but the folder with the headers is missing.
To find the headers (and the lib file) you need to go to IntermediateBuildFilesPath/UninstalledProducts/. Remember when you were told to set Skip Install to YES for static libraries? Well this is the effect that setting has when you make an archive.
Side note: If you don't set it to skip install, your headers will be put into yet another location and the lib file will be copied into your archive, preventing you from exporting an .ipa file that you can submit to the App Store.
After a lot of searching, I couldn't find any macro that corresponds to the UninstalledProducts folder exactly, hence the need to construct the path with "$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts"
For your static library, make sure that you skip install and that your public headers are placed into $TARGET_NAME.
For your app, set your user header search paths to "$(BUILT_PRODUCTS_DIR)", which works fine for regular builds, and "$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts", which works for archive builds.
I ran into this same issue when developing my own static library and although Colin's answer was very helpful, I had to modify it a bit to work consistently and simply when both running and archiving projects under Xcode 4 using a Workspace.
What's different about my method is you can use a single user header path for all your build configurations.
My method is as follows:
include/LibraryName
I've adopted this from use with RestKit and found it works best with all my static libraries. What this does is tells Xcode to copy all the headers we moved to the "Public" headers section in step 1 to the folder we specify here which resides within the Derived Data folder when building. Like with RestKit, I like using a single "include" folder to contain each static library I'm using in a project.
I also don't like using macros here because it will allow us to use a single user header search path later when we configure the project using the static library.
In the same area find User Header Search Paths and add:
"$(PROJECT_TEMP_DIR)/../UninstalledProducts/include"
This tells Xcode to look for static libraries within the intermediate build folder that Xcode creates during the build process. In here, we have the "include" folder we are using for our static library locations we setup in step 2 for the static library project settings. This is the most important step in getting Xcode to correctly find your static libraries.
Here we want to configure the workspace so that it will build the static library when we build our app. This is done by editing the scheme used for our app.
Now, you should be able to import your static library using
import <LibraryName/LibraryName.h>
This method gets around the hassle of having to have different user header paths for different configurations, so you should have no problem compiling for archives.
It all depends on this path:
"$(PROJECT_TEMP_DIR)/../UninstalledProducts/include"
Because we configure our static library to use "Skip Install", the compiled files are moved to the "UninstalledProjects" folder within the temporary build directory. Our path here also resolves to the "include" folder we setup for our static library and use for our user header search path. The two working together lets Xcode know where to find our library during the compile process. Since this temporary build directory exists for both Debug and Release configurations, you only need a single path for Xcode to search for static libraries.
Related question: “lexical or preprocessor issue file not found ” in Xcode 4
Errors might include; missing header files, "lexical or preprocessor issue"
Solutions:
This was a very helpful thread. In researching for my own situation, I found that Apple has a 12-page document dated September 2012 titled "Using Static Libraries in iOS." Here's the pdf link: http://developer.apple.com/library/ios/technotes/iOSStaticLibraries/iOSStaticLibraries.pdf
It's much simpler than most of the Internet discussion, and with some small mods to account for how the external libraries I'm using are configured, it's working well for me. The most important part is probably:
If your library target has a “Copy Headers” build phase, you should delete it; copy headers build phases do not work correctly with static library targets when performing the “Archive” action in Xcode.
New static library targets created with Xcode 4.4 or later will come with an appropriately-configured Copy Files phase for headers, so you should check to see if you already have one before creating one. If you do not, press “Add Build Phase” at the bottom of the target editor and choose to “Add Copy Files.” Disclose the new Copy Files build phase and set the Destination to “Products Directory.” Set the Subpath to include/${PRODUCT_NAME}. This will copy files into a folder named after your library (taken from the PRODUCT_NAME build setting), inside a folder named include, inside your built products directory. The include folder inside a build products directory is in the default header search path for applications, so this is an appropriate place to put header files.
I am sure that in many existing situations Apple's approach may not be enough. I post this here for anyone who is just beginning their journey on the static library garden path - this may be the best starting point for simple cases.
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