9

I am fighting with Xcode 4 workspaces. Currently Xcode 4 wins. Thus, my situation:

I have the workspace with the iOS app project. There is also static library project iOS app depends on in the this workspace.


Solution #1

I try to configure like this:

  • the app project:
    • add to target's Build Phases > Link Binary With Library a product (libmystaticlib.a);
    • set USER_HEADER_SEARCH_PATHS to $(TARGET_BUILD_DIR)/usr/local/include $(DSTROOT)/usr/local/include;
  • the static library project:
    • add some header files to target's Build Phases > Copy Headers > Public;
    • set SKIP_INSTALL to YES.

And important thing: both projects must have configurations named the same. Otherwise, if I have, e.g., configuration named Distribution (Ad Hoc) for the app and Release for the static library, Xcode can't link the app with the library.

With this configuration archiving results to an archive with the application and public headers from static library projects. Of course, I am not able to share *.ipa in this case. :(


Solution #2

I have also tried another configuration:

  • Xcode preferences:
    • set source tree for the static library, e.g, ADDITIONS_PROJECT;
  • the app project:
    • add to target's Build Phases > Link Binary With Library a product (libmystaticlib.a);
    • set USER_HEADER_SEARCH_PATHS to $(ADDITIONS_PROJECT)/**;
  • the static library project:
    • don't add any header files to Public!;
    • set SKIP_INSTALL to YES.

I still need to care about configuration names for both projects. But in result I can build and archive successfully. In the result I get archive and I can share *.ipa.


I don't like the second solutions, because in this case I don't get any real advantage of the Xcode 4 workspace. The same effect I can add get, if I add the static lib project inside the app project. Therefore, I think something is wrong with my solution. Any suggestion how better to link a static libraries?

Joshua Nozzi
  • 60,946
  • 14
  • 140
  • 135
Aleksejs Mjaliks
  • 8,647
  • 6
  • 38
  • 44
  • Take a look of my solution note. http://stackoverflow.com/questions/6400800/managing-static-library-project-as-a-module-like-framework-on-ios-project-in-xcod/6400872#6400872 I solved this problem by making fake framework structure. Similar approach with your solution #1, but slightly more simpler. No need to modify on app-side project setting. – eonil Jun 19 '11 at 06:28
  • I don't like framework solution, because it is little bit hacky, because it isn't officially supported by Apple for iOS. – Aleksejs Mjaliks Jul 01 '11 at 22:11

7 Answers7

10

I also found a solution that works with build and with archive.
In your static library set the Public Headers Folder Path to ../../Headers/YourLib
In your app config set the Header Search Paths to $(BUILT_PRODUCTS_DIR)/../../Headers

In your app you will be able to code #import <YourLib/YourFile.h>

Don't forget the Skip Install = YES option in your static lib.

Dov
  • 15,530
  • 13
  • 76
  • 177
morel sebastien
  • 146
  • 1
  • 2
  • Solution #1 mentioned in the question worked for me but didn't allow me to Archive. This solution does allow me to archive – codecaffeine Sep 12 '11 at 15:59
  • 1
    Are private headers not meant to be referenced by public headers within the static library? I ask as once I change the Public Headers Folder Path, they can no longer find the Private Headers. – Fostah Feb 22 '12 at 13:32
2

I was not real happy with any of the other solutions that were provided, so I found another solution that I prefer. Rather than having to use relevant paths to put the /usr/local/include folder outside of the installation directory, I added a pre-action to the Archive step in my scheme. In the pre-action I provided a script that removed the usr directory prior to archiving.

rm -r "$OBJROOT/ArchiveIntermediates/MyAppName/InstallationBuildProductsLocation/usr"

This removes the usr directory before archiving so that it does not end up in the bundle and cause Xcode to think it has multiple modules.

Nate
  • 183
  • 3
  • 10
  • We copy our static lib .a files to $(BUILT_PRODUCTS_DIR) and their includes to $(BUILT_PRODUCTS_DIR)/include/. So I changed your command to be: `rm -fr "${DSTROOT}/include/"` which sorts the problem for me. (Using Xcode 6.3) – PatchyFog Apr 29 '15 at 19:20
2

We've found an answer, finally. Well, kind of. The problem occurred because Xcode 4 places public headers into InstallationBuildProductsLocation folder during build for archive. Apparently, when archiving it sees the headers and tries to put them into archive as well. Changing Public Headers Folder Path of the lib to somewhere outside of InstallationBuildProductsLocation, for example, to $(DSTROOT)/../public_folders and adding this path to Header Search Path solve the problem. This solution doesn't look very elegant, but for us it seems to be the only option. May be you'll find this useful.

mike
  • 141
  • 4
  • Looks like a good solution. At least I don't need to define source tree for every need project add to workspace as dependency for a main project. – Aleksejs Mjaliks Mar 24 '11 at 09:54
  • This "works" in that it builds and compiles but after closing and opening the project (this is in XCode4) I lose code sense navigation. – Duane Fields Jun 07 '11 at 16:53
  • 1
    If you lose code sense, especially when you're using a "backtrack" in your path like $(SOURCE_ROOT)/../otherlib then make sure you do not use recursive search paths. Instead of $(SOURCE_ROOT)/../otherlib/** add each individual folder: $(SOURCE_ROOT)/../otherlib/system $(SOURCE_ROOT)/../otherlib/system/subsystem $(SOURCE_ROOT)/../otherlib/system/platform-ios It's not ideal and creates long search paths but it fixed all my code sense issues. – CodeSmile Jun 17 '11 at 12:27
2

Here is a solution a get from Apple DTS. I don't like it, because it is suggests to use absolute path. But I still publish it here, maybe someone feels it is right for him.


How to set up the static library:

  • Add a build configuration named "Archive" by copying the Release Configuration.
  • Move your headers to the Project group of the Copy Headers build phase.
  • Set the Per-configuration Build Products Path of the "Archive" configuration to $(BUILD_DIR)/MyLibBuildDir. Xcode will create the MyLibBuildDir folder inside the BuildProductsPath, then add your static library into that folder. You can use "MyLibBuildDir" or provide another name for the above folder.
  • Set Skip Install to YES for all configurations.
  • Set Installation Directory of "Archive" to $(TARGET_TEMP_DIR)/UninstalledProducts.
  • Edit its scheme, set the Build Configuration of its Archive action to "Archive."

How to set up the project linking against the library:

  • Add a build configuration named "Archive" by copying the Release Configuration.
  • Set the Library Search Paths of "Archive" to $(BUILD_DIR)/MyLibBuildDir.
  • Set the User Header Search Paths to the recursive absolute path of your root of your workspace directory for all configurations.
  • Set Always Search User Paths of "Archive" to YES.
  • Set Skip_Install to NO for all configurations.
  • Edit its scheme, set the Build Configuration of its Archive action to "Archive."
Aleksejs Mjaliks
  • 8,647
  • 6
  • 38
  • 44
1

so far I also struggled with the same problem, but did come to a solution with a minimal tradeoff:

This requires Dervied Data to be your Build Location. I set the Public Headers Folder path to ../usr/local/include This will ensure, that the headers will not be placed into the archive.

For the app, I set the Header Search Path to: $(OBJROOT)/usr/local/include $(SYMROOT)/usr/local/include

There are 2 entries necessary since the paths slightly change when building an archive and I haven't figured out how to describe it with only one variable.

The nice thing here is, that it doesn't break code sense. So except for having 2 entries rather than one, this works perfectly fine.

Daniel
  • 11
  • 1
0

I'm struggling with the same problem at the moment. I didn't progress much farther than you. I can only add that in the second solution you can drag headers you need to use from the library to the app project, instead of setting ADDITIONS_PROJECT and USER_HEADER_SEARCH_PATH. This will make them visible in app project. Value of SKIP_INSTALL flag doesn't matter in this case. Still, this solution isn't going to work for me, because I'm moving rather big project, with dozens of libraries, from Xcode 3 to Xcode 4, and it means really a lot of drag and drop to make my project build and archive correctly. Please let us know if you find any better way out of this situation.

mike
  • 141
  • 4
  • Dragging headers into a main project isn't a good option, because this ADDITIONS_PROJECT points to our own commons lib, thus, new features (and new headers) in this project appears very often. – Aleksejs Mjaliks Mar 24 '11 at 09:32
0

I could use Core Plot as a static library and workspace sibling, with two build configurations:

Release:

  • in project, Header Search Path: "$(BUILT_PRODUCTS_DIR)"
  • in CorePlot-CocoaTouch, Public Headers Folder Path: /usr/local/include

AdHoc (build configuration for "Archive" step in Scheme, produces a shareable .ipa):

  • in project, Header Search Path: "$(BUILT_PRODUCTS_DIR)"/../../public_folders/**
  • in CorePlot-CocoaTouch, Public Headers Folder Path: ../../public_folders

Hope it will help someone to not waste a day on this.