(Swift)CLIツールの作り方
はじめに
swiftコマンドを利用してCLIツールを作る方法を説明します。操作はすべてターミナルで行います。
環境
以下の環境で動作確認を行いました。通常はXcodeをインストールするとswiftコマンドが同時にインストールされます。
- macOS
- Monterey 12.7.6
- Sonoma 14.5
- Xcode
- 14.2 (14C18)
- 15.4 (15F31d)
- Apple Swift
- 5.7.2
- 5.10
Step 1. プロジェクトの初期化
例としてmytool
コマンドを作ることにします。ターミナルを開き、次のコマンドを実行してください。
$ mkdir mytool
$ cd mytool
$ swift package init --type executable --name mytool
完了すると、以下のようなメッセージが表示されます。
$ swift package init --type executable --name mytool
Creating executable package: mytool
Creating Package.swift
Creating .gitignore
Creating Sources/
Creating Sources/main.swift
swiftコマンドのバージョンによって作成されるファイル名やディレクトリの構造が少々変化するかもしれません。
Step 2. ビルド
プロジェクトの初期化が完了した時点でビルドが可能な状態になっています。次のコマンドを実行してください。
$ swift build -c release
完了すると、以下のようなメッセージが表示されます。
$ swift build -c release
Building for production...
[5/5] Linking mytool
Build complete! (7.34s)
Step 3. 実行
ビルドが成功すると、実行可能ファイルは.build/release
ディレクトリに作成されます。試してみましょう。
$ ./.build/release/mytool
Hello, World!
Step 4. コードの編集
SwiftコードはSources
ディレクトリに配置します。なお、以下の点に注意してください。
Swift 5.7の注意点
Swift 5.10であれば解消されているため不要な場合は読み飛ばしてください。
注意点として、ファイルの名前がmain.swift
の場合はエントリーポイントとして扱われます。従って、main.swift
コードに@main
属性が設定されているとビルドが失敗します。
まとめると、エントリーポイントを指示する方法として以下のパターンが可能です。
mytool.swift(main.swiftではない任意のSwiftファイル)に@main
属性を設定するパターン
@main
struct MyTool {
static func main() {
print("Hello, world!")
}
}
main.swiftを利用するパターン
print("Hello, world!")
Step 5. パッケージの追加
コマンドライン引数を処理するため、Appleが公式に提供しているArgumentParserパッケージを追加することにします。プロジェクトのルートにあるPackage.swift
を次のように変更してください。
// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "mytool",
platforms: [
.macOS(.v12)
],
dependencies: [
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.0")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.executableTarget(
name: "mytool",
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser")
]),
.testTarget(
name: "mytoolTests",
dependencies: ["mytool"]),
]
)
続いて、Sourcesディレクトリ内のSwiftコードを次のように変更します。
import ArgumentParser
@main
struct MyTool: ParsableCommand {
static var configuration = CommandConfiguration(
commandName: "mytool",
abstract: "Print greeting messages many times!"
)
@Option(name: .long, help: "Number of greetings")
var count: Int = 5
func run() throws {
let count = self.count < 1 ? 1 : self.count
for _ in 0..<count {
print("Hello, World!")
}
}
}
以上で準備は完了です。ビルドするには次のコマンドを実行してください。
$ swift build -c release
通常のビルドと同じコマンドですが、プロジェクトが依存するパッケージのダウンロードを行った後にビルドが開始されます。
Discussion