Carthage


My notes on Carthage

First Impression:

Carthage doesn’t really do anything magic; You manually add dependencies to your Xcode project and Carthage fetches and builds them, or rather Carthage downloads .framework files if these are added to github releases. Which to me makes carthage more of a Git client than a dependency manager.

Second Impression:

Carthage supports building .frameworks from source .swift files. but it’s difficult to figure out how to do this at first. The Carthage project doesn’t have wiki sections or tutorials so you are left digging in old github issues / stackoverlfow questions / forums. If you are lucky enough to have the luxury of time to figure it all out the process isn’t elegant.

Workflows:

Creating a carthage compatible framework:

  1. make a framework project in xcode
  2. share your scheme in xcode
  3. in terminal: (cd to the root of the framework project)
  4. in terminal: build .framework and .dynlib via the command: carthage build --no-skip-current
  5. Make the entire framework project available in your github repo. (use .gitignore to exclude necessary files such as:)

gitignore items:

# Carthage
Carthage

# xcode 
*.xccheckout
*.moved-aside
*.xcuserstate
*.xcscmblueprint
*.xcuserdatad
*.xcbkptlist

Commands:

carthage help build <– information about your build options
carthage help update <– info about update options etc
carthage update --no-build skips downloading .framework binaries, and just downloads the source .swift files
carthage build --no-skip-current tries to build the child dependencies before parents (or so it claims)

Using carthage:

github "Alamofire/Alamofire" == 2.0
github "SwiftyJSON/SwiftyJSON" ~> 2.3.0

These two lines tell Carthage that your project requires Alamofire version 2.0, and the latest version of SwiftyJSON that’s compatible with version 2.3.0.

Dependency Versioning:

Dependency Version: This is how you tell Carthage which version of a dependency you’d like to use. There are a number of options at your disposal, depending on how specific you want to be:

  1. == 1.0 means “Use exactly version 1.0”
  2. >= 1.0 means “Use version 1.0 or higher”
  3. ~> 1.0 means “Use any version that’s compatible with 1.0″, essentially meaning any version up until the next major release.
  4. == 0.0.0-alpha.3 means get exactly this version
  5. "branch-name" means use the latest commit from this branch 🔑
  6. q4k049 means use this commit
    If you specify ~> 1.7.5, then any version from 1.7.5 up to, but not including 2.0, is considered compatible.
    Likewise, if you specify ~> 2.0 then Carthage will use a version 2.0 or later, but less than 3.0. .
    Compatibility is based on Semantic Versioning – for more information check out our tutorial on Using CocoaPods with Swift. If you don’t specify a version, then Carthage will just use the latest version that’s compatible with your other dependencies

Flags:

The –platform iOS option ensures that frameworks are only built for iOS. If you don’t specify a platform, then by default Carthage will build frameworks for all platforms (often both Mac and iOS) supported by the library.

Uninstalling Carthage

sudo rm -rf /Library/Frameworks/CarthageKit.framework
rm -f /usr/local/bin/carthage

Installing Carthage:

Installing carthage 0.18.1 was a bit tricky. It worked flawlessly on my mac mini server but not so much on my macbook pro. After installing Carthage from the .pkg file. Terminal would not find carthage. So in order to make it work i had to hunt down the path where Carthage resided: ```` and then figure out how to make an Alias in terminal.

  1. In terminal type: nano .bash_profile
  2. Then add this alias carthage="sudo /usr/local/bin/carthage"
  3. ctrl + o and then enter and then ctrl x` Restart terminal
  4. type carthage version in terminal and you will be promted to type in your password.
  5. The drawback is that you have to type your password every time you want to use carthage.

Drawbacks:

  1. There is next to no information about how to use Carthage available on the net. You have to spend lots of time fumbling in the dark. I get that you figure it out in the end, but this time could be spent on more important things. More effort could be made to make it more approachable. Workflow tutorials, videos etc. Answering people on Stackoverflow. Most carthage questions are unanswered at present time 2017-Feb

  2. Hard to make projects carthage compatible. it requires the framework author to share a .xcodeproject file which has a deeply nested .xcscheme file inside. This is only possible through creating a complex set of rules in a .gitignore file. Which is not future proof, since apple may add new files to .xcodeproject at anytime, which you in-turn will need to add ignore cases in the .gitignore file. Carthage argues that its better to reuse information xcode already have. As apposed to cocoapod which creates a .podspec file in root. If only this information was easier to add to projects. It would be great if carthage could make this process a bit smoother. By either extracting the info on build and adding this info in a .carthage file in root or at least providing updated .gitignore information on each carthage update and and making sure .gitignore conformed to this standard.

  3. Close to impossible to nest frameworks. Which is the nr.1 reason why we need dependency managers in the first place, no? Modularity and all that? There are solutions for nesting frameworks but it requires scripts in obscure settings in xcode. “build phase” !?!? The phrase “XCode already have the information you need” seems not to fit anymore. Abstracting this information into a separate file would be 👌 There is also some talk about using git submodules to get nested frameworks working. But wasn’t that one of the arguments to use carthage in the first place. Avoiding git submodules and git subtrees. Lots of contradictories here.

  4. Clutters up your github repos. Carthage files, obscure XCode project files in obscure sub folders that makes no sense.

Gotchas:

Adding binaries (.framework and .dSYM) to releases section of github speeds up the process of adding frameworks to your project. A drawback is that binaries leak personal information and information about your computer file system. Which can be a security risk. An option is to build binaries off-site on a remote computer.

Carthage further reading:

https://realm.io/news/swift-dependency-management-with-carthage/
https://www.raywenderlich.com/109330/carthage-tutorial-getting-started
http://blog.mat.tc/how-to-make-a-carthage-compatible-framework/
http://basememara.com/creating-cross-platform-swift-frameworks-ios-watchos-tvos-via-carthage-cocoapods/

Side-notes:

  • Add this to your search path: $(SRCROOT)/Carthage/Build relative paths for build phase 🔑 (Carthage adds aliases in this folder)

  • If you are using @testable import then search for testability in the build settings of your xcode project set this to yes 🔑

  • carthage bootstrap -> could possibly support nested frameworks

  • You can comment out lines in Cartfile via the # char

  • github "eonist/Element" "master" will default to the latest commit (as opposed to HEAD which will not)

  • Don’t forget to set your xcode framework project scheme to shared.

Tasks:

  • [] Figure out how you can order build process.