8
votes

I'm having problems trying to realize the following dependency setup between two frameworks and an app, all developed by me:

enter image description here

  1. Util containts a bunch of low-level utilities and extensions to Foundation types such as String, Date, etc.

  2. UI contains a bunch of custom UIView and UIViewController subclasses, class extensions for UIColor, UIImage, etc..

The app and each framework has its own repository on GitHub.


The UI framework is set up to depend on the Util framework, using Carthage:

  1. The project's Cartfile contains a reference to the Util repo:

    github "MyOrganization/Util.git"

  2. Util is listed in "Linked Frameworks and Libraries", but not embedded (because UI is a framework project, not an app).

  3. The Framework Search Paths build setting contains $(PROJECT_DIR)/Carthage/Build/iOS in addition to $(inherited)

  4. The .gitignore file is configured to ignore the whole Carthage directory (not just /Build)

  5. I am not using git submodules, and I don't intend to (I have enough headaches already).


If I clone the UI framework and run carthage update, Carthage fetches/builds Util and I can embed it manually to build the UI framework.

So far so good.


But if I clone the App framework and run carthage update, Carthage fetches the UI repo, but it fails to build:

  1. The directory App/Carthage/Checkouts contains the checked-out copy of the UI project, as expected. However, there is no further Carthage directory for the nested framework (I assume it should be App/Carthage/Checkouts/UI/Carhage/Checkout/Util).

  2. Navigating to App/Carthage/Checkouts/UI opening the workspace there with Xcode and building it also fails, obviously. The reference to Util.framework is broken.

From what I've read, Carthage should fetch the recursive dependency; What am I missing here?

I tried adding both framework URLs the the App Cartfile, but xcode still fails to build the UI framework.

The bottom part of the log pointed to by the carthage output says:

/Users/me/Projects/App/code/App/Carthage/Checkouts/UI/code/UI/UI/MyClass.swift:10:8: error: no such module 'Util'

import Util
       ^

** ARCHIVE FAILED **


The following build commands failed:
    CompileSwift normal arm64
    CompileSwiftSources normal arm64 com.apple.xcode.tools.swift.compiler
(2 failures)

Update

I put together a minimal reproducible example on GitHub. The app and frameworks make up this dependency graph:

A -> B -> C
// (and also A -> C, but that's not relevant now)

(C is the app, B and C are frameworks).

When running carthage update on the A project, it fetches both framework repos, checks out both, starts to build B first and fails, just as above (import directive).

The checked out copy of B has the right Cartfile, along with all the source files, but there is no nested Carthage/ directory, let alone the necessary copy of C within it.

I guess I need to somehow make the build process refer to A/Carthage/Builds/C.framework instead of A/Carthage/Checkouts/B/Carthage/Builds/C.framework, but don't know how to set up the B project for that to work out...

1

1 Answers

10
votes

TL, DR: My UI framework didn't have its Cartfile at the root of the repository, so carthage could not "see" it during the build (even though the file itself was fetched, and stored several directories deeper).


As Github user Sho Ikeda (@ikesyo) kindly pointed out on this thread/issue of the Carthage repository, my intermediate framework (UI, in this case) didn't have its Cartfile at the root. Instead, it was more like this:

.git
.gitignore
docs/
code/
    UI.workspace
    UI/
        UI.xcodeproj
        Cartfile
        Carthage/
            Build/
            Checkouts/

etc., when it needs to be more like this:

.git
.gitignore
Cartfile
docs/
code/
    UI.workspace
    UI/
        UI.xcodeproj

Carthage/
    Build/
    Checkouts/

I was under the assumption that the Cartfile had to be at the same level as the Xcode project; that is not the case. After moving the Cartfile to the root, and changing my framework project's Build Setting "Framework Search Paths" from:

$(PROJECT_DIR)/Carthage/Build/iOS

to:

$(PROJECT_DIR)/../../Carthage/Build/iOS

...in order to account for the move, so that linking against Util when building UI.framework from its workspace doesn't fail.

Lastly, I ran carthage update form my App directory, linked the frameworks, etc. as explained in the Carthage GitHub page, and it worked like a charm. I can successfully instantiate classes defined in my Util (innermost) framework from my App's source code (outermost).