xcrun: execute XCode tasks from the command line

Posted by Grego on February 3, 2015

I’ve been extremely frustrated in the past with XCode, but now with the new Swift language out by apple I’m not sure I can handle it anymore. I’ve decided to try and replace XCode with vim. The first step was syntax highlighting, which I mentioned in my Fresh Start with MacVim by adding

Plugin 'Keithbsmiley/swift.vim'

In my .vimrc, the next step is compiling from the command line.

This is still a work in progress, but I’ll post my findings in hopes that someone will be able to elaborate on it. If you do happen to improve on this, please do tell by commenting below.

Using :make from vim

On Tuesday, Jan 20 I found a tip online about using vim’s :make to compile Swift by doing:

:set makeprg=xcrun\ swift\ %

This was a start, but it failed when importing UIKit. Here’s the ridiculous sample code I wrote to test compiling:

import UIKit

class HomeDog : NSObject {
    let name: String

    init(name: String) {
        println("There's a new homedog in town: \(name)")
        self.name = name
    }
}

let hd = HomeDog(name: "Barry")

The compiler comes back with:

test.swift:1:8: error: no such module 'UIKit'
import UIKit
       ^

By removing the import UIKit and NSObject super class reference, the code does in fact compile and run with this command.

There's a new homedog in town: Barry

Achieving iOS/UIKit support

Since I’m currently using swift for iOS this is a problem. I really needed UIKit.

On Friday, Jan 30 I found some helpful information online. Firstly, there’s actually a man page for xcrun. I question why I didn’t think of this in the first place. Try it out man xcrun:

DESCRIPTION
       xcrun  provides  a means to locate or invoke developer tools from the command-line, without requiring users to modify Makefiles or
       otherwise take inconvenient measures to support multiple Xcode tool chains.

Hey, that’s what we’re trying to do!

So I spent some long hours trying to figure out what flags to pass to xcrun, when I realized there was an easier way to find out. So I cheated.

You can find these flags easily by creating a new project in Xcode. Then compile it. Check the icon that looks like a speech bubble, it should in the leftmost panel of Xcode’s shoddy ui, this should show you the compiler logs.

Scan the logs for a section that says Compiling Swift source files and expand it by clicking the icon on the right side of it. (There is also an option in the context menu to expand). Now we’ve got every option being sent to the swift compiler.

Here’s what I found that worked for me:

    xcrun -sdk iphoneos \
        swiftc \
        -target armv7-apple-ios8.0 \
        filename.swift

I broke it into multiple lines for easier reading.

You can copy/paste that into your terminal and it should allow you to edit the file name right there. After doing this, you’ll notice it compiles without a problem. However, if you try to run it:

➜  ~  ./test
zsh: bad CPU type in executable: ./test

You’ll run into some technical issues. Now we need to figure out how to start it.

Starting apps from the command line

I know this is possible with the xcrun simctl command, but unfortunately I still have some more experimenting to do before figuring out how to actually load the app. Here are some brief notes on that:

xcrun simctl list #show details
xcrun simctl boot <id> #boots a device with given id
xcrun simctl install <id> <app_path> #installs the app to specified device id
xcrun simctl launch <id> <app> #launches app

You can substitute <id> for booted to let xcrun select from one of the already-booted devices. Valid values for <id> come from xcrun simctl list, for example:

iPhone 6 Plus (123-456-789) (Shutdown)

To boot this iPhone 6 Plus you would use:

xcrun simctl boot 123-456-789

Closing

I’ve figured out how to compile a single Swift file from the command line, but that leaves more questions to be answered:

  1. How do I compile multiple files with complex dependencies?
  2. How do I build a .app bundle that can be deployed to the device?
  3. How do I maintain my xcode projects when adding new files?

I might explore some options next including rake as a possible build system. I’m hoping to find a way to integrate with Xcode project and workspace files to make things transition more smoothly for those who still use xcode