Carthage: [Feature request] Ability to build only one dependency

Created on 12 Jul 2015  Â·  36Comments  Â·  Source: Carthage/Carthage

_Apologies if this is already possible, I couldn't figure out a way._

To add a new dependency I would love to be able to do this:

  • Specify new dependency X/Y in Cartfile.
  • carthage update --no-build.
  • carthage build x/y.

Right now we have no choice but building all the existing dependencies again, which can be time consuming.

Thanks :star:

enhancement help wanted

Most helpful comment

+1 here. As a workaround I ended up creating a script that builds and merges a single dependency. It's far from being the ideal solution, but at least saves us some time. You can find it at https://github.com/ruipfcosta/carthage-workarounds.

All 36 comments

By the way I'd love to tackle this myself if you guys agree this is useful!

+1

+1

Right now we have no choice but building all the existing dependencies again, which can be time consuming.

The builds are taking a long time even though they've already been built at that revision?

Yeah, carthage build rebuilds everything. Is that not supposed to happen?

Yes. Build with no changes:

$ time carthage build
*** xcodebuild output can be found in /var/folders/ct/_03srt6h8xj44m00r6bfmd400000gn/T/carthage-xcodebuild.ocjJ3M.log
*** Building scheme "Alamofire iOS" in Alamofire.xcworkspace
*** Building scheme "Alamofire OSX" in Alamofire.xcworkspace
*** Building scheme "InAppSettingsKitFramework" in InAppSettingsKit.xcworkspace
*** Building scheme "Mixpanel" in Mixpanel.xcodeproj
*** Building scheme "Siesta" in Siesta.xcodeproj

real    0m24.019s
user    0m22.824s
sys 0m3.995s

~5s apiece is pretty painful when iterating on changes to a dependency.

I'd like to look into why this is so slow before adding a workaround.

Is Carthage supposed to completely skip building or are you surprised that Xcode takes that long to recompile when everything is already built?

If it's later, I wouldn't rely on that. Swift incremental compilation is pretty much non-existing.

As to the former: how could Carthage know which revision each of the .frameworks in the Build directory corresponds to?

But I'm down for not adding this feature if it's actually unnecessary, I just don't see how yet :)

are you surprised that Xcode takes that long to recompile when everything is already built?

I'm surprised, but not _that_ surprised.

Here’s a quick view of where the time goes. Copied below is a process dumping a timestamp every 0.5 seconds in the background, interspersed with the output of carthage build --verbose.

Things to note:

  • The time seems to be spread pretty evenly throughout the build process. There’s not one dependency or one build step that’s the obvious culprit.
  • No actual compilation occurring here, I think? The time seems to be spent just launching processes, opening projects, and checking for changes.

Based on that, I’d say it’s going to be pretty hard to get the 5–10x speedup you’d need to make this feature request unnecessary.

•••••••••••• 16:41:09 CDT 2015
•••••••••••• 16:41:09 CDT 2015
•••••••••••• 16:41:10 CDT 2015
*** Building scheme "Alamofire iOS" in Alamofire.xcworkspace
•••••••••••• 16:41:10 CDT 2015
•••••••••••• 16:41:11 CDT 2015
Build settings from command line:

=== BUILD TARGET Alamofire iOS OF PROJECT Alamofire WITH CONFIGURATION Release ===

Check dependencies
•••••••••••• 16:41:11 CDT 2015

Write auxiliary files
write-file /tmp/Xcode/DerivedData/Alamofire-fzkiieikoiedovbolinkjvotziel/Build/Intermediates/Alamofire.build/all-product-headers.yaml

=== BUILD TARGET Alamofire iOS Tests OF PROJECT Alamofire WITH CONFIGURATION Release ===

Check dependencies

** BUILD SUCCEEDED **

•••••••••••• 16:41:12 CDT 2015
•••••••••••• 16:41:13 CDT 2015
Build settings from command line:

=== BUILD TARGET Alamofire iOS OF PROJECT Alamofire WITH CONFIGURATION Release ===

Check dependencies
•••••••••••• 16:41:13 CDT 2015

Write auxiliary files
write-file /tmp/Xcode/DerivedData/Alamofire-fzkiieikoiedovbolinkjvotziel/Build/Intermediates/Alamofire.build/all-product-headers.yaml

=== BUILD TARGET Alamofire iOS Tests OF PROJECT Alamofire WITH CONFIGURATION Release ===

Check dependencies

** BUILD SUCCEEDED **

•••••••••••• 16:41:14 CDT 2015
•••••••••••• 16:41:14 CDT 2015
*** Building scheme "Alamofire OSX" in Alamofire.xcworkspace
•••••••••••• 16:41:15 CDT 2015
•••••••••••• 16:41:15 CDT 2015
=== BUILD TARGET Alamofire OSX OF PROJECT Alamofire WITH CONFIGURATION Release ===

Check dependencies

Write auxiliary files
write-file /tmp/Xcode/DerivedData/Alamofire-fzkiieikoiedovbolinkjvotziel/Build/Intermediates/Alamofire.build/all-product-headers.yaml

=== BUILD TARGET Alamofire OSX Tests OF PROJECT Alamofire WITH CONFIGURATION Release ===

Check dependencies

** BUILD SUCCEEDED **

•••••••••••• 16:41:16 CDT 2015
•••••••••••• 16:41:16 CDT 2015
•••••••••••• 16:41:17 CDT 2015
•••••••••••• 16:41:17 CDT 2015
•••••••••••• 16:41:18 CDT 2015
•••••••••••• 16:41:18 CDT 2015
*** Building scheme "InAppSettingsKitFramework" in InAppSettingsKit.xcworkspace
•••••••••••• 16:41:19 CDT 2015
•••••••••••• 16:41:19 CDT 2015
Build settings from command line:

=== BUILD TARGET InAppSettingsKitFramework OF PROJECT InAppSettingsKit WITH CONFIGURATION Release ===

Check dependencies
•••••••••••• 16:41:20 CDT 2015

Write auxiliary files
write-file /tmp/Xcode/DerivedData/InAppSettingsKit-gtmydjrabyygvyfjcgblsjrvuute/Build/Intermediates/InAppSettingsKit.build/all-product-headers.yaml

** BUILD SUCCEEDED **

•••••••••••• 16:41:20 CDT 2015
•••••••••••• 16:41:21 CDT 2015
Build settings from command line:

=== BUILD TARGET InAppSettingsKitFramework OF PROJECT InAppSettingsKit WITH CONFIGURATION Release ===

Check dependencies
•••••••••••• 16:41:21 CDT 2015

Write auxiliary files
write-file /tmp/Xcode/DerivedData/InAppSettingsKit-gtmydjrabyygvyfjcgblsjrvuute/Build/Intermediates/InAppSettingsKit.build/all-product-headers.yaml

** BUILD SUCCEEDED **

•••••••••••• 16:41:22 CDT 2015
•••••••••••• 16:41:22 CDT 2015
•••••••••••• 16:41:23 CDT 2015
•••••••••••• 16:41:23 CDT 2015
*** Building scheme "Mixpanel" in Mixpanel.xcodeproj
•••••••••••• 16:41:24 CDT 2015
•••••••••••• 16:41:24 CDT 2015
Build settings from command line:

=== BUILD TARGET Mixpanel OF PROJECT Mixpanel WITH CONFIGURATION Release ===

Check dependencies
•••••••••••• 16:41:25 CDT 2015

Write auxiliary files
write-file /tmp/Xcode/DerivedData/Mixpanel-dgkihzehyzzvxjepeccrpnmubuil/Build/Intermediates/Mixpanel.build/all-product-headers.yaml

** BUILD SUCCEEDED **

•••••••••••• 16:41:25 CDT 2015
•••••••••••• 16:41:26 CDT 2015
Build settings from command line:

•••••••••••• 16:41:26 CDT 2015
=== BUILD TARGET Mixpanel OF PROJECT Mixpanel WITH CONFIGURATION Release ===

Check dependencies

Write auxiliary files
write-file /tmp/Xcode/DerivedData/Mixpanel-dgkihzehyzzvxjepeccrpnmubuil/Build/Intermediates/Mixpanel.build/all-product-headers.yaml

•••••••••••• 16:41:27 CDT 2015
** BUILD SUCCEEDED **

•••••••••••• 16:41:27 CDT 2015
•••••••••••• 16:41:28 CDT 2015
•••••••••••• 16:41:28 CDT 2015

@pcantrell that's a great example, thank you!

How often are you rebuilding dependencies and why? We usually update them at _most_ once a week. So an occasional 30 seconds isn't a big deal. (And it usually pales in comparison to the actual build time of any changed dependencies.)

Like @pcantrell mentioned, building several times is pretty common when iterating on a particular dependency. Maybe because you're adding commits, or because you're testing different branches, etc.
Compiling all N dependencies every time you want to test a change in 1 is very much a waste of time.

Agree with @NachoSoto, this build time is insanely slow when iterating dependencies. I just migrated away to CocoaPods+Frameworks because it was so unbearable.

Is including the dependency using submodules and iterating that way an option? Seems like that is the purpose of submodule support in Carthage. Not that I wouldn't like this feature, but that's how I iterate on dependencies that are being worked on alongside the main application.

@MichaelMcGuire _That_ feature would need to be configurable on a per-dependency basis to be a suitable substitute. I don’t think it is … right?

Is including the dependency using submodules and iterating that way an option? Seems like that is the purpose of submodule support in Carthage. Not that I wouldn't like this feature, but that's how I iterate on dependencies that are being worked on alongside the main application.

Yup, that supports my example. But what do you do while you're iterating on them? You need to build the framework to test them inside of the containing application.

Submodules aren't configurable on a per-dependency basis. But they should help in this case, which is a nice benefit. But you kinda have to commit and add their projects to your Xcode project. And I don't know that it won't also be slow.

I'm :+1: to letting carthage build take a list of dependencies to build. But carthage update should also get this treatment (a la #218).

@mdiep :+1:

But what do you do while you're iterating on them?

I was lead to this thread tracking down a discrepancy between how a framework project was building itself in Xcode and how Carthage was building it.

(Short version: not a Carthage issue. Long version: turned out it wasn’t building for a particular architecture, but problem wasn’t manifesting in the usual ways b/c apparently when a Framework Swift class has an Obj-C counterpart in SomeFramework-Swift.h but is missing the arch-appropriate Swift binary, Swift code in the client project will see that Obj-C version, try to use it, and give weird build errors.)

@pcantrell Sorry, you're right. On this specific project that is not an issue. And as @mdiep mentions, you basically end up needing to add the projects to your Xcode workspace (again not an issue for how I'm using carthage, but understand this isn't necessary how everyone wants to do this)

It this issue related to #218?

It this issue related to #218?

Yes, it is, as I mentioned here. :smile:

+1

:+1:

Yes please. Common scenarios for me are:

  • Adding a new dependency
  • Forking a dependency I was using to fix a bug and iterating on those fixes
  • Updating the version of a dependency

I almost never want to rebuild all the dependencies again, which with Swift frameworks seems to happen every time.

Forking a dependency I was using to fix a bug and iterating on those fixes

This!

The fact is that you never need Carthage builds to be fast … until you do.

What is the current status of this feature?

What is the current status of this feature?

It's currently unimplemented. See #618.

You're welcome to take a crack at it if you like. :smile:

+1 here. As a workaround I ended up creating a script that builds and merges a single dependency. It's far from being the ideal solution, but at least saves us some time. You can find it at https://github.com/ruipfcosta/carthage-workarounds.

+1 For this.

The commit https://github.com/NachoSoto/Carthage/commit/305451cb2470240fc7b285bc20a1f88eba475466 looks like a reasonable solution

Yeah, anybody's welcome to finish up #886 :)

@NachoSoto I could give it a shot, what WIP remains on the commit?

@mpurland it's listed on the PR :)

+1 For this.

Am I waking up a dead thread? Is this solved already?

Was this page helpful?
0 / 5 - 0 ratings