How to compile a project with app and library in the same workspace with different configuration names?
Asked Answered
M

3

29

I am developing an app and I am using an open source component.

I have a workspace containing both MyApp.xcodeproj and Component.xcodeproj. My app has three configurations: Debug, App Store and In House but the component has only two: Debug and Release

In the Debug configuration, everything works fine, but I can't compile my app in App Store or In House configuration because the configuration names do not match. I get a file not found error when trying to #import <Component/Component.h>

I need both App Store and In House configurations and I would really like to avoid modifying the component's configurations in order to ease future updates of the component.

I know I could use CocoaPods to solve this issue but I would like to know if there is a simple solution in Xcode

Masticatory answered 17/6, 2015 at 7:19 Comment(1)
I used this question to help me figure out this situation but in reverse. The app has 2 configs but the framework has 3. I'm now having issues with this when trying to switch to a custom config (not debug or release). It doesn't seem to respect the framework's config despite setting the parent project's DEFAULT_CONFIGURATION for each parent configLocke
M
48

You can get your project to compile with some tweaks to your app’s settings.

I suggest you to modify all settings at the project level so that all your targets can inherit these settings.

  1. Add a new DEFAULT_CONFIGURATION user-defined setting and define your configuration mapping. This is how it should look like:

    Default Configuration Screenshot

  2. Set FRAMEWORK_SEARCH_PATHS to $(BUILD_DIR)/$(DEFAULT_CONFIGURATION)-$(PLATFORM_NAME) for all configurations, add Any OS X SDK variants and set the value to $(BUILD_DIR)/$(DEFAULT_CONFIGURATION). Set HEADER_SEARCH_PATHS to $(FRAMEWORK_SEARCH_PATHS)/include and LIBRARY_SEARCH_PATHS to $(FRAMEWORK_SEARCH_PATHS). This is how it should look like:

    Search Paths Screenshot

    This step is quite tedious, it can be automated with the xcproj tool and by running this script in your project directory. Edit your configurations mapping as needed.

    #!/bin/bash
    
    CONFIGURATIONS=( "App Store:Release" "In House:Release" "Debug:Debug" )
    
    for CONFIGURATION in "${CONFIGURATIONS[@]}"; do
        xcproj --configuration "${CONFIGURATION%%:*}" write-build-setting DEFAULT_CONFIGURATION "${CONFIGURATION#*:}"
    done
    
    xcproj write-build-setting 'FRAMEWORK_SEARCH_PATHS' '$(BUILD_DIR)/$(DEFAULT_CONFIGURATION)-$(PLATFORM_NAME)'
    xcproj write-build-setting 'FRAMEWORK_SEARCH_PATHS[sdk=macosx*]' '$(BUILD_DIR)/$(DEFAULT_CONFIGURATION)'
    
    xcproj write-build-setting 'HEADER_SEARCH_PATHS' '$(FRAMEWORK_SEARCH_PATHS)/include'
    xcproj write-build-setting 'LIBRARY_SEARCH_PATHS' '$(FRAMEWORK_SEARCH_PATHS)'
    
  3. If the component is distributed as a static library, you are done here. If the component comes as a framework you have to update its path reference by editing your project.pbxproj file in a text editor. In the PBXFileReference section (under /* Begin PBXFileReference section */) find Component.framework and update its path like this:

    name = Component.framework; path = "../$(DEFAULT_CONFIGURATION)/Component.framework"; sourceTree = BUILT_PRODUCTS_DIR; };
    

    Also make sure that the sourceTree is set to BUILT_PRODUCTS_DIR, i.e. relative to built products. Once you edited the project file, this should look like:

    Location Screenshot

Your project should now build as expected.

Masticatory answered 17/6, 2015 at 7:19 Comment(13)
This fails to work for me when I have any non-Debug one set to Debug. Xcode will implicitly build the Release one, which lines up with your example. If I set InHouse to Debug I get compile failures.Apocrine
Further to @BrentleyJones's comment: Is it possible that this solution only works for the specific case presented? Note that 'Debug' maps to 'Debug', and non-'Debug' maps to 'Release'. What if the library doesn't use 'Debug' and 'Release', but uses 'Blue' and 'Red' instead - does it still work?Leucoma
It would also work with Blue and Red. The example was given with Debug and Release since this is what most library are using.Masticatory
This does not work when you have more than just two configurations on the framework. For example, I have Debug, InHouse, and Release on the framework. I map my app's Debug -> Debug, InHouse -> InHouse, AppStore -> Release. Debug and AppStore work, per your example, but InHouse does not, because Xcode builds the Release version instead. This is because Xcode will build whatever is listed as the "command line configuration" when it can't match the configuration perfectly, even when correctly setting the location of the framework.Apocrine
This worked for me, albeit I left out the variants and just used $(BUILD_DIR)/$(DEFAULT_CONFIGURATION)-$(PLATFORM_NAME) to finally achieve success. Xcode 7.2.1.Locke
> path = "../$(DEFAULT_CONFIGURATION)/Component.framework"; Unfortunately, Xcode seems to override this custom path value back to a default Component.framework when arbitrary build settings are altered.Klutz
@BrentleyJones I experience the same in Xcode 8.1. Where is this command line configuration listed?Stortz
OK, I found it. Look in Project -> Info -> Configuration. It's directly under the list of configurations of your project.Stortz
@Stortz What I've now done instead is add a new Run Script step that copies the frameworks over from where they end up (Release for example): gist.github.com/brentleyjones/57c6945a193cef70b2f8eec720527ed1Apocrine
This worked on Xcode. when i build project on CI, use this configuration, it's same error tips. static lib file not found. Had a best way do configuration?Farthingale
I have a problem executing tests as Xcode somehow takes the Release version of my framework which (obviously) has not been compiled for testing. Has anybody experienced a similar issue?Septal
This sort of works. If Xcode can't find a config it will fallback to Release. So, if your framework has Debug & Release then the app can have Debug, ReleaseStaging & ReleaseProd. It can't have DebugStaging because DebugStaging would fallback to release.Barm
The problem with it defaulting to building with Release is that if you have any code with #if DEBUG that you want, it wont be included in the compiled product... I haven't found a way to yet to do it. Does anybody know a way to tell Xcode "build this dependency with this configuration"?Ximenes
P
7

I had this same problem, but I had multiple configurations (Debug, TestFlight, Release, Enterprise) in my app, and the bolded configurations would always fail to build cause it couldn't find the frameworks. I really didn't want to mess with the project settings of my sub projects in order to make updating them easy.

The answer I found was to just update the framework search path to account for the fact that the frameworks would be dropped in Release (or whatever the default configuration is set to) of the sub projects.

Specifically I set it to: $(BUILD_DIR)/Release-$(PLATFORM_NAME)

I set it to be recursive too. This works both for Simulator and Device, building in Xcode and command line.

Pangermanism answered 19/3, 2017 at 5:57 Comment(0)
I
1

I solved it in the following way,

In my dependency project, Project -> Target -> Build Phases, added new Run Script

TARGET_DIR="Build"
TARGET_FILE="${TARGET_DIR}/${FULL_PRODUCT_NAME}"
mkdir -p ${TARGET_DIR}
rm -rf ${TARGET_FILE}
cp -rf "${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}" ${TARGET_DIR}

After the every build, I copy the build to my Build directory inside the project. And from the main project, Project -> Target -> General, I drag and dropped the dependency Framework (which is inside dependency project's Build folder) then, Project -> Target -> Build Settings -> Framework Search Paths, under my custom Build Configuration, I added the following

$(PROJECT_DIR)/../DependencyProject/Build

The folder is relative to my main project, and this should be relative to your project. Then in my all the schemes, I added a Pre-actions script for Build with

rm -Rf "${PROJECT_DIR}/../DependencyProject/Build"

Also you need to select the app against Provide build settings from drop down.

Insignificance answered 29/8, 2020 at 14:30 Comment(2)
This works for me. But, Is there a way we can use the BUILD_DIR itself rather than having them to our source folder?Parget
I didn't find a way to get the BUILD_DIR, you can add your Build directory to the .gitignore like I did.Insignificance

© 2022 - 2024 — McMap. All rights reserved.