Xcode 4 can't locate public header files from static library dependency
Asked Answered
K

18

92

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, but
  • headers 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?

Kaykaya answered 4/4, 2011 at 20:18 Comment(1)
Could be related with path names. Pl check this post. [Static libraries in Xcode 4][1] [1]: https://mcmap.net/q/24048/-static-libraries-in-xcode-4/…Ordeal
K
16

Xcode 4 Project Fails to compile a static library

Related question: “lexical or preprocessor issue file not found ” in Xcode 4

Errors might include; missing header files, "lexical or preprocessor issue"

Solutions:

  1. Check the "user header paths" are correct
  2. Set "Always search user paths" to YES
  3. Create a group call "Indexing headers" in your project and drag the headers to this group, DO NOT add to any targets when prompted.
Kaykaya answered 9/4, 2011 at 19:36 Comment(2)
Another easily overlooked but extremely important step: Ensure that your search paths are wrapped in double quotes to escape any spaces. I always forget to do that.Lallans
Thanks @Brad, this is indeed a very important and helpful remark.Charcuterie
V
124

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.

The short answer

Add the following path to your User Header Search Paths

"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts"

Why does this work?

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.

Archiving works a little differently

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"

Summary

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.

Volkman answered 1/3, 2012 at 2:29 Comment(15)
How does this relate to the DerivedData folder?Kaykaya
Regular builds go to: DerivedData/WorkspaceName-hash/Build/Products/Debug-iphoneos/TargetName.app --- Archive builds go to: DerivedData/WorkspaceName-hash/Build/Intermediates/ArchiveIntermediates/TargetName/BuildProductsPath/Release-iphoneos/TargetName.appVolkman
Combine this solution with Collins solution and that did it for me.Jeopardy
I've added a modified version of this that does not require multiple build paths and makes configuration a little easier. See what you think: https://mcmap.net/q/24047/-xcode-4-can-39-t-locate-public-header-files-from-static-library-dependencyShinar
For me, using "$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts" with the recursive checkbox did not work. As soon as I used "$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/<nameOfStaticLibrary>" without the recursive flag, it worked for me.Emmalynne
I just wanted to echo that I found the same result as TPoschel. I wish I'd found that there was one more comment here about 45 minutes ago! I was pulling my hair out. It appears that the recursive setting doesn't carry through to the build here?Gerrald
Curious that the recursive setting isn't working for you guys, yet specifying one more nested folder does work. I'm using multiple static libraries in my project and it'd be a real pain to have to add a line for each one!Volkman
This method sometimes doesn't work by user's build settings which is very hard to predict. I recommend to put libs and headers somewhere in source file directory and adding relative path to $(SRCROOT) to search path option.Coextensive
Note that your $(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts is actually $(TARGET_BUILD_DIR). Even while archiving. ;)Staford
I had this under 'Distribution' but I needed to add it to 'Release'. Thanks!Instigation
For me in Xcode 5: $(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/include/NAME OF LIBRARY I didn't set to YES: Always search user paths.Fancyfree
This was close: didn't quite work for me, but the following did: "$(TEMP_ROOT)/UninstalledProducts/$(PLATFORM_NAME)"Antimatter
For Xcode 7 this worked - "$(OBJROOT)/UninstalledProducts/$(PLATFORM_NAME)/" Source: https://mcmap.net/q/24049/-xcode-7-2-in-archive-getting-the-issue-cordova-cdvviewcontroller-h-file-not-found-while-there-is-no-such-issues-in-building-the-appMetallist
The only thing I could get to work in XCode 7, was a recursive "$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/iphoneos/include/"Suzannesuzerain
Does NOT work. Followed instructions to a tee. Same problem: can not find my framework header file. Builds fine, installs fine, on both simulator and side-load to device. Can not archive.Petree
S
89

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:

Create a Workspace

  1. Under Xcode 4, go to File, New, Workspace.
  2. From Finder you can then drag in the .xcodeproj projects for both the static library you want to use, and the new app you are building that uses the library. See Apple Docs for more info on setting up Workspaces: https://developer.apple.com/library/content/featuredarticles/XcodeConcepts/Concept-Workspace.html

Static Library Project Settings

  1. Make sure all the static library's headers are set to copy to "Public". This is done under the settings for the static library target > Build Phases. In the "Copy Headers" phase, make sure all your headers are within the "Public" section.
  2. Next go to Build Settings, find "Public Headers Folder Path" and type in a path for your library. I choose to use this:

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.

  1. Find "Skip Install" and make sure this is set to YES.

Settings for the Project Using the Static Library

  1. Add the static library as a framework under Build Phases > Link Binary With Libraries and add the libLibraryName.a file for whatever static library you want to use.
  2. Next make sure project is set to search for User Search Paths. This is done under Build Settings > Always Search User Paths and make sure its set to YES.
  3. 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.

Configure the Workspace

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.

  1. Make sure you have the scheme selected that will create your application.
  2. From the scheme drop-down, choose Edit Scheme.
  3. Select Build at the top of list on the left. Add a new target by pressing the + on the middle pane.
  4. You should see the static library show up for the library you are trying to link. Choose the iOS static library.
  5. Click both Run and Archive. This tells the scheme to compile the libraries for the static library whenever you build your app.
  6. Drag the static library above your application target. This makes the static libraries compile before your application target.

Start Using the Library

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.

Why does this work?

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.

Shinar answered 1/6, 2012 at 18:35 Comment(9)
You are awesome, man! This is really helpful, and it works as you described.Rattlebox
awesome. Where shall I send flowers :)Headless
After setting this up, some of you might encounter "...] unrecognized selector sent to class 0x...". In case you do, try adding this up in your project's Targets->Project->Build Settings->Linking->Other Linker Flags: -all_loadHarwin
Make sure the User Header Search Paths are in quotes if they have spaces.Slippery
Xcode 4.6.2 is not writing anything to "$(PROJECT_TEMP_DIR)/../UninstalledProducts/include" for me. Any idea what I'm missing? Or has Xcode behaviour changed again?Shekinah
UninstalledProducts has goneBroider
Works for me with Xcode 5.1; build and archive success. Thanks!Harned
This works but my bundle size has increased to 80MB.It includes app and extension as well.Any reasons?Hyposensitize
Worked like a charm, although I got a warning for setting Always Use Search Paths to Yes. After setting it to No, it still works.Cyrilla
K
16

Xcode 4 Project Fails to compile a static library

Related question: “lexical or preprocessor issue file not found ” in Xcode 4

Errors might include; missing header files, "lexical or preprocessor issue"

Solutions:

  1. Check the "user header paths" are correct
  2. Set "Always search user paths" to YES
  3. Create a group call "Indexing headers" in your project and drag the headers to this group, DO NOT add to any targets when prompted.
Kaykaya answered 9/4, 2011 at 19:36 Comment(2)
Another easily overlooked but extremely important step: Ensure that your search paths are wrapped in double quotes to escape any spaces. I always forget to do that.Lallans
Thanks @Brad, this is indeed a very important and helpful remark.Charcuterie
D
15

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.

Discography answered 27/12, 2012 at 21:15 Comment(4)
for those following the above link.. beware: the step that asks you to delete the dummy template files when you create the library project.. DON'T DELETE THE *.pch file.. it will come to haunt you eventually + the above advice doesn't work with categories.. there is a fix for that though (saw it somewhere)Sacrilegious
Thanks for providing a link to an official Apple approach for building static libraries. I started off by building my static library using this approach, but was unable to Archive. @Sacrilegious - What is the problem with deleting the pch file that is generated?Fireworks
if you delete the .pch file.. the project simply won't compile.. (for the purpose of archiving or otherwise)..Sacrilegious
It doesnt work for me.When I try import statement with "" it doesnt work I need <>.Also while archiving it is not able to find headers.Any ideas?Hyposensitize
M
4

http://developer.apple.com/library/ios/#technotes/iOSStaticLibraries/Articles/creating.html

Per Apple documention:

Your library will have one or more header files that clients of that library need to import. To configure which headers are exported to clients, select your library project to open the project editor, select the library target to open the target editor, and select the build phases tab. 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.

Monochrome answered 15/7, 2013 at 15:21 Comment(0)
C
3

Take a look at Jonah Wlliam's solution (mid way down) & GitHub model (in comments) for an insight. http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/

Caseose answered 7/4, 2011 at 20:18 Comment(1)
While this may technically answer the question, it would be preferable for you to include the essential parts of the linked article in your answer, and provide the link for reference. Failing to do that leaves the answer at risk from link rot.Appaloosa
C
2

Add $(OBJROOT)/UninstalledProducts/exactPathToHeaders to the Header Search Paths.

For some reason the recursive checkbox didn't work for me and I had to add the rest of the path to where the headers are located.

Under the Log Navigator in Xcode (the tab to the right of the break points navigator) you can see the build history. If you select the actual build failure you can expand its details to see the setenv PATH and check to make sure the path to your header files is there.

Charlottecharlottenburg answered 15/4, 2012 at 4:24 Comment(3)
Good note on the recursive checkbox, same issue here.Jeopardy
Yep I had to specify a particular sub-folder as well, checking recursive didn't work.Drooff
I ended up using this path however (simply because its shorter) "$(PROJECT_TEMP_DIR)/../UninstalledProducts/SubProjectHeaders"Drooff
M
2

None of the answers above worked for me on Xcode 7 but they gave me a good idea though. For guys struggling on Xcode 7, I got this fixed by adding the following to User Header Search Paths (include quotes)

"$(BUILT_PRODUCTS_DIR)/usr/local/include"

Change the relative URL part usr/local/include according to what's there in 'Public Header Folder Path' setting of static library

Monzon answered 5/11, 2015 at 4:12 Comment(0)
T
2

In my case my workspace had a couple of static library projects and one of them has dependency including header files with the other. The issue was with the order of building . In edit Scheme page under Build section, I deselected parallelize option and arranged the order of the targets as per the dependencies and it solved by problem

Torpor answered 10/2, 2016 at 11:50 Comment(0)
H
1

Add the following path to your User Header Search Paths:

$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts

This is verified!

Harlen answered 30/5, 2012 at 4:38 Comment(0)
T
1

At the risk of showing what an idiot I am... I've been suffering from XCode refusing to find my .h files all afternoon.

Then I realised.

Because I was using "XCode 4", I had "intelligently" decided to put all of my projects in a subfolders of a folder called "XCode 4 projects".

Those spaces in the folder name messed up XCode big-time !

Renaming this folder to "XCode_4_Projects" has brought joy (and less swearing) back into my life.

Remind me again, what year is this ?

Perhaps someone could tell the Apple developers...

Trevar answered 8/5, 2013 at 13:47 Comment(0)
C
1

None of these answers worked for me. Here's what did. Add the following exactly (copy and paste including the double-quotes) to your User Header Search Paths build setting:

"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/include/"

Note the addition of the "/include/" subdirectory as compared to other answers. As other users have pointed out, the "recursive" option doesn't seem to do anything, so you can ignore it.

My project was now able to archive successfully when importing static library header files in the following form:

#import "LibraryName/HeaderFile.h"

You do not need to enable the Always Search User Paths setting unless you are including your static library headers with angle brackets (#import <LibraryName/HeaderFile.h>), but you really shouldn't be doing it that way anyway if it's not a system/framework header.

Criticize answered 30/3, 2015 at 19:11 Comment(0)
C
0

This is a related issue which led me to this question so I'm adding my solution strictly for documentation / it could save another soul hours of sweating

DropboxSDK.h file not found

After days of trying to get VES to compile for iOS I eventually ran into this issue. the DropboxSDK.h was definitely in reach of search headers I even added it to the framework headers search path, included the .h directly and went to all sorts of great lengths to try and get DropboxSDK.h found.

Solution

EXPLICITY drag the DropboxSDK.framework file into Xcode's Project Navigation and make sure Copy Files if needed is checked. Also make sure your target is checked as needed.

Warning

Setting the explicit framework location in build phases did not work for me. I had to drag the .framework into Xcode and make sure the files copied to my project.

#mbp2015 #xcode7 #ios9

Careycarfare answered 14/5, 2016 at 22:35 Comment(0)
E
0

There is various complex ways to do this, and some very smart solutions are proposed in this thread.

The main problem to all these solution is that it seriously decrease your library portability.

  • Each time you need to start a new project using your library and archive it for iTunes, it's a configuration hell.
  • Each time you need to share your project with your team or customers, it can break for any reason ( context, Xcode version, whatever,.. )

My choice has been finally to simply use frameworks - always - as recommended by Apple ( WWDC Videos ).

It is so easier and does the same job at the end !

Another quite elegant solution which seems to work is to use Private Cocoapods. Cocoapods does all the configuration work, header copy and so.

Frameworks rock !

Enthral answered 27/7, 2016 at 15:2 Comment(2)
Where do you set this? simply use frameworks - always -Carpeting
It not set anywhere. It's simply an architectural choice. Frameworks are 'modern libraries' which are much easier to link and manage. At the time of this message, swift still not allows to build binary libraries.Enthral
P
0

Here is what solved the same problem for me.

I have an App Target, and an iMessage Extension Target. Then I had 2 SDKs (my own), which the App Target links against.

The problem was: my iMessage target was also using the 2 SDKs of mine (separate projects), but it wasn't linking against them in Build Phases --> Link Binary With Libraries. I had to add my 2 SDKs to the iMessage Target there, to match my App target, and now it archives.

So the moral of the story is: If you have multiple targets, such as extensions, make sure that all of your targets are linking against the libraries they need. It was able to Build and Deploy to Simulator and Device, but not Archive.

Petree answered 18/8, 2017 at 17:40 Comment(0)
S
0

Update: Xcode 9

The above answers did not work for me using Xcode 9, but this answer worked perfectly for me. I have added $(OBJROOT)/UninstalledProducts/$(PLATFORM_NAME)/include to my "Header Search Paths" and Xcode did link the header of my static library with no problems.

Siracusa answered 7/2, 2018 at 16:38 Comment(0)
D
0

When you create static library .modulemap and umbrella.h is generated additionally to .a library

To use objective-C static library you should

  • Link Library - add library as dependency
  • set Library Search paths
  • set Header Search Paths

[Example]

Dneprodzerzhinsk answered 24/9, 2022 at 7:24 Comment(0)
N
-18

Save yourself the trouble and do this = create new user account on your Mac -- open the project under the new user account-- all problems disappear. Save your time and keep your sanity. all of those nerdy replies don't help!!

Good Luck

Nutmeg answered 2/4, 2013 at 4:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.