We can build and run Swift code/projects from the command line via multiple commands without using Xcode. I have heard of xcodebuild
, xcrun
and swift
used for Xcode development. I do use fastlane
but I don't really understand the tools powering it under the hood.
I am an iOS developer who uses a Mac. I develop using Xcode so I haven't used these command-line tools before.
What are the differences between each command? Are there any cases where I'd be better off using one over the other?
xcodebuild
and xcrun
help build Xcode projects in a headless context, for example in CI setups. swift
is the Swift REPL and is largely used for Swift on Server apps. As such, we can build apps without knowing about or using the tools regularly in mobile app development. We use xcodebuild
and xcrun
under the hood interacting with Xcode even though we don't realise it because they're bundled in Xcode's Command Line tools (documentation archive, but still relevant).
fastlane
is an example CI tool that automates the build process, certificate signing, and interfacing with App Store Connect, using these tools.
xcodebuild
is part of Xcode's bundled command-line tools package. From the manpages:
build Xcode projects and workspaces
xcodebuild builds one or more targets contained in an Xcode project, or builds a scheme contained in an Xcode workspace or Xcode project.
xcodebuild
has lots of options and use cases. The options are equivalent to certain user actions within the Xcode IDE. Example usage:
xcodebuild -workspace MyWorkspace.xcworkspace -scheme MyScheme
Builds the scheme MyScheme in the Xcode workspace MyWorkspace.xcworkspace.
In the command above, we build the workspace without Xcode, using what Xcode runs internally for compilation. Xcode can only be installed on macOS and we have the same limitations for using its command-line tools, including xcodebuild
and xcrun
.
xcrun
is another Xcode command-line tool part of Xcode's CLI tools. From the manpages:
run or locate development tools
xcrun
provides a means to locate or invoke coexistence- and platform-aware developer tools from the command-line, without requiring users to modify makefiles or otherwise take inconvenient measures to support multiple Xcode toolchains.
xcrun [-sdk SDK] -find <tool_name>
xcrun
is also commonly used with Xcode-select
to manage multiple Xcode versions on the same machine. Every version of Xcode comes bundled with its own development tools, and we can use xcrun
to get the current path to them:
xcrun xcode-select --print-path
swift
is the Swift REPL. swift
is a command-line tool that includes the Swift toolchain but can also be installed outside of the Xcode bundled tools. swift
is different from xcodebuild
and xcrun
because it is compiled Swift rather than C. swift
is not well documented in the MacOS manpages documentation, however, Apple has documented these tools on its blog:
Xcode 6.1 introduces yet another way to experiment with Swift in the form of an interactive Read Eval Print Loop, or REPL.
A REPL is essentially an interactive compilation environment or shell. First, the REPL reads code, then evaluates it, prints, and repeats the process. As you can imagine, there is much less we can develop using a REPL compared to an IDE. However, there are other use cases for Swift than iOS, watchOS, and macOS development.
swift
includes the standard library and doesn't include libraries such as Foundation
and UIKit
. These Swift libraries are almost certainly needed for iOS or macOS development, so we can't develop apps using the swift
REPL alone. However, Swift on Server projects regularly use swift
to run Swift code on Linux and even Windows machines.
For wider adoption, Apple has made swift
available on different Operating Systems where Xcode is not readily available. Swift now also has Docker support and Windows. Docker enables us to run swift
on any machine regardless of the underlying OS. swift
in these applications serves as a scripting language.
swift
is used largely for Swift on Server. Swift on Server has great performance for server applications, with a lower memory footprint, fast startup time, and deterministic performance. Although it is not quite as fast as .NET core for some tasks, this is because Swift is much safer with a rigorous type system, garbage collection with ARC, and fewer optimisations for server-specific apps. Many early adopters praise the improved language type system, memory efficiency, and algorithmic performance. In fact, Swift vapor is comparable to Python and Ruby in efficiency for JSON Serialization tasks. Swift is comparable to Java in very few tasks, but this is likely to change as the language and ecosystem grow.
Think of xcrun
as a convenience prefix to invoke various command line tools in the currently active Xcode toolchain.
Multiple Xcode toolchains can be installed on the same machine (e.g. latest release, beta release and/or legacy releases). Use xcode-select
to set which Xcode toolchain path is used. Alternately, the active developer toolchain can be specified by setting the environment variables SDKROOT
and DEVELOPER_DIR
### open 'bin' directory for the currently active Xcode toolchain
open `xcode-select --print-path`/usr/bin
Tools which can be invoked with xcrun
include:
xcrun simctl <subcommand>
~ iOS Simulator Controlxcrun xcodebuild …
~ build/test Xcode projects and workspacesxcrun xctrack <commands> [options]
~ record, import and export Instruments .trace filesxcrun not_a_tool help
# xcrun: error:
# sh -c '/Applications/Xcode.app/…/bin/xcodebuild
# -sdk /Applications/Xcode.app/…/MacOSX.sdk
# -find not_a_tool 2> /dev/null'
# failed with exit code 17664: (null) (errno=Invalid argument)
Think of xcodebuild
as single command line tool specialized to harnesses multiple other tools to manage an overall project build process. An invocation of xcodebuild
will execute many tasks just like Build
or Test
in the Xcode GUI menus do when creating and/or testing a project.
xcodebuild -help
Note: xcodebuild
can be invoked without a proceeding xcrun
.
xcrun xcodebuild -version
# Xcode 13.2.1
# Build version 13C100
xcodebuild -version
# Xcode 13.2.1
# Build version 13C100
Think of swift
(by itself) as the interpreted, interactive, scriptable, "REPL" version of the swiftc
compiler.
Then, expand the scope to think of swift
as a basis for a extended ecosystem which does not require the presence of Xcode (unless when an AppleOS SDK is needed to target Apple hardware).
swift --help
# SUBCOMMANDS (swift <subcommand> [arguments]):
# build: SwiftPM - Build sources into binary products
# package: SwiftPM - Perform operations on Swift packages
# run: SwiftPM - Build and run an executable product
# test: SwiftPM - Build and run tests
Command Line Example
> swift
Welcome to Swift version 5.5.2-dev.
Type :help for assistance.
1> 8 + 9
$R0: Int = 17
2> :quit
Note: Swift REPL works in conjuction with the LLDB debugger, thus
:
preceeds commands likehelp
andquit
during the REPL session.
Swift Script Example
Script example_script.swift
File:
#!/usr/bin/swift
// File: example_script.swift
// reminder: chmod to executable before invoking the script
import Foundation
func printHelp() {
print("Please add an argument to the command line. Thanks.")
}
// --- main ---
if CommandLine.argc < 2 {
printHelp()
} else {
for i: Int in 1 ..< Int(CommandLine.argc) {
print( CommandLine.arguments[i] )
}
}
Interpretated and Compiled Script Execution:
ls -l example_script.swift
# -rwxr--r--@ 1 user staff 321 Dec 30 16:56 example_script.swift
./example_script.swift
# Please add an argument to the command line. Thanks.
./example_script.swift a bcd
# a
# bcd
## Let's compile the script...
swiftc example_script.swift
ls -l ex*
# -rwxr-xr-x 1 user staff 55136 Dec 30 16:57 example_script
# -rwxr--r-- 1 user staff 321 Dec 30 16:56 example_script.swift
./example_script
# Please add an argument to the command line. Thanks.
./example_script xyx
# xyz
REPL: Read Evaluate Print Loop
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With