On Carthage 0.37.0, building Nuke always fails with timeout.
This is because Carthage builds all projects in a repo, and Nuke's repo includes NukeDemo, which in turn has the following four remote Swift Package dependencies:
- Alamofire
- SwiftSVG
- Gifu
- Nuke
Cloning each of those repos requires over 2 minutes on my laptop with gigabit fiber ethernet. Here is the result of those repos getting cloned and then checked out:

Subsequent carthage bootstrap operations result in Carthage building each of the Xcode projects found nested in the Alamofire/, SwiftSVG/, Gifu/, and Nuke/ subdirectories of Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/. Since that Nuke directory also contains a copy of the NukeDemo project, these subsequent carthage bootstrap operations result in an ongoing infinite loop of building NukeDemo and all its dependency projects, punctuated only by timeout errors when Carthage eventually gives up.
Here is a detailed analysis over time of the events that occur during the first carthage bootstrap operation, with timestamps:
- [16:43:42] ran
carthage bootstrap --use-ssh --no-use-binaries --platform iOS --configuration Release --cache-builds --new-resolver
- [16:44:51] Carthage begins cloning Nuke into
Carthage/Checkouts/Nuke
- [16:46:15] Carthage begins building
Carthage/Checkouts/Nuke/Nuke.xcproj
- [16:46:23] Carthage begins building
Carthage/Checkouts/Nuke/Demo/NukeDemo.xcproj
- [16:46:24] SPM begins cloning Nuke into
Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/repositories/Nuke-8db81083
- [16:46:32] SPM begins cloning Gifu into
Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/repositories/Gifu-05fd1ae0
- [16:47:53] SPM begins cloning SwiftSVG into
Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/repositories/SwiftSVG-ae27d62c1
- [16:48:11] SPM begins cloning Alamofire into
Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/repositories/Alamofire-11b78eba
- [16:49:13-14] SPM creates subdirectories and checks out these repos into
Nuke/, Gifu/, SwiftSVG/, and Alamofire/ in Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/
- [16:49:15]
carthage boostrap operation fails with error: xcodebuild timed out while trying to read NukeDemo.xcodeproj 😭
And here is the subsequent carthage bootstrap operation:
- [16:52:01] ran
carthage bootstrap --use-ssh --no-use-binaries --platform iOS --configuration Release --cache-builds --new-resolver
- [16:53:15] Carthage begins trying to build Nuke again, picking up where it left off in step 9. above.
- [16:53:48] Carthage begins building Alamofire in
Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/Alamofire/Alamofire.xcproj
- [16:54:00] Carthage begins building SwiftSVG in
Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/SwiftSVG/SwiftSVG.xcproj
- [16:54:05] Carthage begins building Gifu in
Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/Gifu/Gifu.xcproj
- [16:54:09] Carthage begins building Nuke in
Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/Nuke/Nuke.xcproj
- [16:54:26] Carthage begins building NukeDemo in
Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/Nuke/Demo/NukeDemo.xcproj
- [16:54:30] SPM begins cloning Nuke into
Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/repositories/Nuke-8db81083
- [16:54:38] SPM begins cloning Gifu into
Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/repositories/Gifu-05fd1ae0
- [16:55:51] SPM begins cloning SwiftSVG into
Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/repositories/SwiftSVG-ae27d62c1
- [16:57:21]
carthage boostrap operation fails with error: xcodebuild timed out while trying to read NukeDemo.xcodeproj 😭
If I run carthage boostrap again, guess what happens?
The infinite cycle continues.
Each time carthage bootstrap gets run after this, Carthage adds another nested build of NukeDemo, SPM clones all its SPM dependencies (including Nuke!), and Carthage builds those, which results in the further nested NukeDemo getting built, all its SPM dependencies getting cloned, etc. until timeout and 😭.
I.e., we will end up with:
Carthage/Checkouts/
Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/
Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/
Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/
Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/
...etc. forever.
But why does Carthage build both Nuke.xcproj and NukeDemo.xcproj, in the first place? Shouldn't Carthage ignore other projects that are nested in subfolders?
Well, I looked into this question, and I learned the following information:
- Carthage is designed to build all the .xcproj's in each dependency repo. This is how it is intended to work. (RxSwift issue 34, which was fixed in RxSwift PR 35; Carthage issue 1974, particularly this comment)
- Carthage building NukeDemo is therefore not a bug, and is not due to anything peculiar to my local setup.
- Carthage building the things inside Nuke/Demo/DerivedData/NukeDemo/
This comment from Carthage issue 1974 mentions that "Carthage always prefers to build through a workspace," making it sound like adding an .xcworkspace that only contains Nuke (but not NukeDemo) could be a possible solution. However, I tried this, and the problem still happens. So that's not a workable solution.
Interestingly, I found an older thread from 2014 where someone had made this comment:
Carthage only finds and builds a single project. If that weren't the case, it would erroneously pick up dependency/example/demo projects, which is rarely what one wants.
I think the current behavior is reasonable.
... and this comment:
Carthage finds the root-most project and builds that. So it expects to find one framework project, and ignores all others (some of which might include examples/demos, dependencies, etc.). This results in the best behavior in ≥ 80% of cases.
So, if you have multiple framework projects, the correct solution is to combine them into one, and use targets and schemes to separate builds—not projects.
So.. it seems at some point that Carthage's developers decided "the current behavior is reasonable" was wrong, and that it was better to "erroneously pick up dependency/example/demo projects" than to just build the root project of a repo. Perhaps for some projects that's fine, but obviously for projects like Nuke, which have a nested demo project that depends on the parent project as a remote SPM dependency, that can cause an infinite loop causing Carthage to always fail.
Perhaps the old wisdom of only building the root project was much better, however I doubt Carthage's current maintainers will want to reverse course on this, since it would probably break something else.
The current workaround we're using for our app to pass CI, is to run carthage checkout, then rm -rf Carthage/Checkouts/Nuke/Demo, then carthage build.
But I would humbly ask that, until Carthage gets updated to address this problem, could you please separate out Nuke Demo into its own, separate repository, so that we can just build Nuke without having an infinite loop? Thanks!
On Carthage 0.37.0, building Nuke always fails with timeout.
This is because Carthage builds all projects in a repo, and Nuke's repo includes NukeDemo, which in turn has the following four remote Swift Package dependencies:
Cloning each of those repos requires over 2 minutes on my laptop with gigabit fiber ethernet. Here is the result of those repos getting cloned and then checked out:
Subsequent
carthage bootstrapoperations result in Carthage building each of the Xcode projects found nested in theAlamofire/,SwiftSVG/,Gifu/, andNuke/subdirectories ofCarthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/. Since thatNukedirectory also contains a copy of theNukeDemoproject, these subsequentcarthage bootstrapoperations result in an ongoing infinite loop of building NukeDemo and all its dependency projects, punctuated only by timeout errors when Carthage eventually gives up.Here is a detailed analysis over time of the events that occur during the first
carthage bootstrapoperation, with timestamps:carthage bootstrap --use-ssh --no-use-binaries --platform iOS --configuration Release --cache-builds --new-resolverCarthage/Checkouts/NukeCarthage/Checkouts/Nuke/Nuke.xcprojCarthage/Checkouts/Nuke/Demo/NukeDemo.xcprojCarthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/repositories/Nuke-8db81083Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/repositories/Gifu-05fd1ae0Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/repositories/SwiftSVG-ae27d62c1Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/repositories/Alamofire-11b78ebaNuke/,Gifu/,SwiftSVG/, andAlamofire/inCarthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/carthage boostrapoperation fails with error:xcodebuild timed out while trying to read NukeDemo.xcodeproj 😭And here is the subsequent
carthage bootstrapoperation:carthage bootstrap --use-ssh --no-use-binaries --platform iOS --configuration Release --cache-builds --new-resolverCarthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/Alamofire/Alamofire.xcprojCarthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/SwiftSVG/SwiftSVG.xcprojCarthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/Gifu/Gifu.xcprojCarthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/Nuke/Nuke.xcprojCarthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/Nuke/Demo/NukeDemo.xcprojCarthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/repositories/Nuke-8db81083Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/repositories/Gifu-05fd1ae0Carthage/Checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/Nuke/Demo/DerivedData/NukeDemo/SourcePackages/repositories/SwiftSVG-ae27d62c1carthage boostrapoperation fails with error:xcodebuild timed out while trying to read NukeDemo.xcodeproj 😭If I run
carthage boostrapagain, guess what happens?The infinite cycle continues.
Each time
carthage bootstrapgets run after this, Carthage adds another nested build of NukeDemo, SPM clones all its SPM dependencies (including Nuke!), and Carthage builds those, which results in the further nested NukeDemo getting built, all its SPM dependencies getting cloned, etc. until timeout and😭.I.e., we will end up with:
Carthage/Checkouts/
Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/
Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/
Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/
Nuke/Demo/DerivedData/NukeDemo/SourcePackages/checkouts/
...etc. forever.
But why does Carthage build both Nuke.xcproj and NukeDemo.xcproj, in the first place? Shouldn't Carthage ignore other projects that are nested in subfolders?
Well, I looked into this question, and I learned the following information:
This comment from Carthage issue 1974 mentions that "Carthage always prefers to build through a workspace," making it sound like adding an .xcworkspace that only contains Nuke (but not NukeDemo) could be a possible solution. However, I tried this, and the problem still happens. So that's not a workable solution.
Interestingly, I found an older thread from 2014 where someone had made this comment:
... and this comment:
So.. it seems at some point that Carthage's developers decided "the current behavior is reasonable" was wrong, and that it was better to "erroneously pick up dependency/example/demo projects" than to just build the root project of a repo. Perhaps for some projects that's fine, but obviously for projects like Nuke, which have a nested demo project that depends on the parent project as a remote SPM dependency, that can cause an infinite loop causing Carthage to always fail.
Perhaps the old wisdom of only building the root project was much better, however I doubt Carthage's current maintainers will want to reverse course on this, since it would probably break something else.
The current workaround we're using for our app to pass CI, is to run
carthage checkout, thenrm -rf Carthage/Checkouts/Nuke/Demo, thencarthage build.But I would humbly ask that, until Carthage gets updated to address this problem, could you please separate out Nuke Demo into its own, separate repository, so that we can just build Nuke without having an infinite loop? Thanks!