Xcode custom build configuration causes "library/file not found" for static libraries
Asked Answered
P

7

45

I have a workspace with a project which links with the static libraries in another project (which is also in the workspace). It's a problem in Kobold2D I haven't been able to resolve, even though I understand the cause, and I suppose it's similar to this question.

The project targets and the static library targets all have the Debug and Release build configurations. All is well.

Now someone adds a new build configuration in the project and names it Ad-Hoc for example. Now the project's target builds the Ad-Hoc configuration, however the static libraries have no such configuration. Apparently they then default to building the Release configuration.

At the end, when the linker is supposed to bring everything together, it fails:

ld: library not found for -lbox2d-ios
Command /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang++ failed with exit code 1

For forcibly loaded libraries via -force_load $(BUILT_PRODUCTS_DIR)/libSomeLib.a the error is similar but says "file not found". I should note that the library "libbox2d-ios.a" is in the "link binary with libraries" build phase list.

Obviously the problem is that the linker is assuming that the libraries are in the Ad-Hoc-iphoneos folder in the BUILT_PRODUCTS_DIR while they are actually in the Release-iphoneos folder because they have no Ad-Hoc build configuration.

How can I slap the linker in the face and tell him to get the libraries where they are? Preferably I'm looking for a solution that works for both cases, ie libraries added the standard way (link binary with libraries build phase) and libraries that need an additional -force_load to work.

I'm hoping that there's some way to:

  • force libraries to be placed in the build configuration folder of the app's target
  • run a post-compile & pre-link script that copies each library to the build configuration folder
  • specify a relative path to the libraries
  • use a different macro other than $BUILT_PRODUCTS_DIR for -force_load
  • a linker flag like -WTFmake-all-problems-go-away

Excuse me, but I have to say this … ARGH! :)

Portmanteau answered 15/12, 2011 at 16:52 Comment(1)
ARGH!!! indeed (rageguy)Upwards
H
8

I have not found a way to do this, unfortunately. The best workaround I can find is to add new targets rather than new build configurations. So for example in one of my projects I have only Release and Debug configurations, but I have extra targets called "MyProject - app store" and "MyProject - ad hoc". This will only be possible if you have control of the project file, of course.

Having duplicated targets sitting around is annoying in the extreme because you can add files to one target and forget to add them to the others, and you won't know until you try and build it. But it does build, which is a win (with xcode anyhow).

A similar question I asked a while ago: What is the correct way to set build configurations in an ios project using static libraries for creating an archive in xcode 4?

Hardden answered 4/1, 2012 at 3:6 Comment(0)
V
33

As said in similar question iOS Static Library as a Subproject of a Project That Has Custom Build Configurations?, the fix is to add this line

$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)

to your target's Framework Search Paths, Header Search Paths and/or Library Search Paths

Viguerie answered 5/2, 2014 at 14:24 Comment(2)
Brilliant! Works great for iOS imported project/frameworks in Xcode 7!Forced
I should have added, add this to any Build Configuration other than Release and Debug - don't add the line for all configurations.Forced
C
21

Here's something that works for me.

In the project with the Adhoc build configuration, override the "Per-configuration Build Products Path" (CONFIGURATION_BUILD_DIR) and "Per-configuration Intermediate Build Files Path" (CONFIGURATION_TEMP_DIR) for the Adhoc build configuration to use the same folder as the release configuration.

Adhoc: CONFIGURATION_BUILD_DIR = $(SYMROOT)/Release$(EFFECTIVE_PLATFORM_NAME)
Adhoc: CONFIGURATION_TEMP_DIR = $(PROJECT_TEMP_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)

Now when you do an Adhoc build, Xcode will put libFoo.a and Bar.app in the Release-iphoneos folder. The linker will be happy and you can use -force_load $(BUILT_PRODUCTS_DIR)/libFoo.a as usual.

Alternatively, you can add the Release-iphoneos folder to the library search paths for the Adhoc build configuration:

Adhoc: LIBRARY_SEARCH_PATHS = $(inherited) $(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)

But then you'll have to set a different -force_load for each build configuration:

Debug: OTHER_LINKER_FLAGS = $(inherited) -force_load $(BUILT_PRODUCTS_DIR)/libFoo.a
Adhoc: OTHER_LINKER_FLAGS = $(inherited) -force_load $(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)
Release: OTHER_LINKER_FLAGS = $(inherited) -force_load $(BUILT_PRODUCTS_DIR)/libFoo.a
Catania answered 14/6, 2012 at 20:37 Comment(3)
About sharing the same build dir between Release and Adhoc, it could lead to issues because Xcode will not recompile and regen the libs in the proper configuration when you will switch between Release and Adhoc. Don't you think guys?Contour
I think you're right, MonsieurDart. Very annoying. I get around this by using this technique only in schemes used by automated build tools which perform a clean before each build.Flaw
1st suggestion work perfect. 2nd one I couldn't get to work. ThanksGripsack
C
9

I have a similar problem using CocoaPods and trying to have more than one Adhoc (or Enterprise, or Beta) configurations.

Here is what seems to work (let's say that both projects are lying in the same xcworkspace):

  • Add the subproject generated lib to the mainproject Link Binary with Libraries.

  • As the configuration Adhoc is not known by the subproject, Xcode will use the Release config as a fallback (or maybe the first config of the list) when building it.

  • The linker will complain because it cannot find the lib… ok, let's handle this one.

  • Add a Run Script build phase to the mainproject, right after the Target Dependencies phase. Enter this script:

if [ "$CONFIGURATION" = "Adhoc" ]; then
    echo "====================================="
    echo "Copying libPods Release into the Adhoc product build dir!"
    echo "====================================="
    cp "$BUILT_PRODUCTS_DIR/../Release-$PLATFORM_NAME/libPods.a" "$BUILT_PRODUCTS_DIR"
else
    echo "No manual lib copy."
fi

This will copy the lib generated by the subproject Release build (which will happen when mainproject is built) in the Adhoc build directory, so that the linker will find the lib. And we should be good to go! Yeah!

Contour answered 15/2, 2013 at 10:34 Comment(1)
I just had the same problem with a new Configuration "Testing" and I was able to resolve it by adding "Testing" to the Pods project too and do a full clean and rebuild.Yeti
H
8

I have not found a way to do this, unfortunately. The best workaround I can find is to add new targets rather than new build configurations. So for example in one of my projects I have only Release and Debug configurations, but I have extra targets called "MyProject - app store" and "MyProject - ad hoc". This will only be possible if you have control of the project file, of course.

Having duplicated targets sitting around is annoying in the extreme because you can add files to one target and forget to add them to the others, and you won't know until you try and build it. But it does build, which is a win (with xcode anyhow).

A similar question I asked a while ago: What is the correct way to set build configurations in an ios project using static libraries for creating an archive in xcode 4?

Hardden answered 4/1, 2012 at 3:6 Comment(0)
U
5

My framework is built using another SDK project inside my app project. First I have a "Debug" and "Release", then I add a new "TestFlight" configuration. I can't archive with that new one. I ended up adding a new build configuration with the same name in the SDK project. In other words, I ended up adding "TestFlight" configuration to BOTH my app and SDK projects. Now Archive works.

I'm not sure if it's the best way to do it. But it looks clean enough to me for now. :)

Oh, and for Cocoapods, after you duplicate the configuration, if you run pod install right away you will get this yellow warning:

[!] CocoaPods did not set the base configuration of your project because your project already has a custom config set. In order for CocoaPods integration to work at all, please either set the base configurations of the target ...

You have to go to the Project, "Info" tab, "Configurations" section, select the new configuration you just created, and set "Pods.release" of all targets to "None" first. After that, you can run pod install safely.

Upwards answered 23/1, 2015 at 11:47 Comment(2)
Thanks! You were spot on! You should make another thread asking this question and then post your answer so you can get proper credit (if you care).I guess for embedded libraries you need to make sure that they also have all of the build configurations options your project has i.e. if you project has debug, beta, and release each embedded library project you have must include the same.Bontebok
Creating Build Configurations in my library project with the same names as those in my app project is the only thing that did it for me (@Viguerie answer worked for regular builds, but not for archiving). Thanks!Krauss
L
0

You could add CONFIGURATION_BUILD_DIR=/Some/Shared/Dir before running xcodebuild. For example:

cd SOURCE_DIR
xcodebuild  -workspace YourProject.xcworkspace -scheme YourScheme -configuration AdHoc -sdk iphoneos clean build CONFIGURATION_BUILD_DIR="`pwd`"/build
Lemcke answered 25/5, 2012 at 4:42 Comment(0)
M
0

Usually I have an AppStore scheme (mapped to my AppStore config).

One thing that happened to me, was this case sensitive issue that was making Cocoapods to generate a build folder for Pods.build inside Release-iphonesimulator (as a fallback) instead of AppStore-iphonesimulator.

I guess I miss-clicked when I linked the scheme and config and only removing it and re-adding made me understand what went wrong. Check the diff.

sensitive issue

I was using cocoapods 0.38.2, so this was clearly a user mis-configuration and not a Cocoapods issue that was resolved on 0.34

Morgan answered 18/10, 2015 at 18:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.