LoginSignup
75
65

More than 5 years have passed since last update.

Swiftでコマンドラインツールを作る

Last updated at Posted at 2016-02-12

やること

  • Swiftでコマンドラインツールを作る
  • プロジェクト構成などがCarthageとだいたい同じものを作る
  • 依存管理にCarthageを使用する

やらないこと

  • 自分で作ったコマンドをbrew install出来るようにする

Github

大体同じ手順で作業してcommitしたので、多少参考になるかもしれない。

XcodeでProjectを作る

名称未設定.png

最初に作るのはCocoa Applicationです。

名称未設定.png

今回は凄いツールを作ります。適宜自分が作るプロジェクトに置き換えて下さい。

Cocoa FrameworkのTargetを追加する

名称未設定.png

Frameworkの名前はプロジェクト名にKitを付けたやつにします。適宜変更したりいろいろして下さい。

作ったTargetのschemeを共有設定にする

方法は適宜ぐぐって下さい。

全てをまとめるWorkspaceを作る

さっき作ったxcodeprojを一旦閉じてSugoiTool.xcworkspaceを作り、SugoiTool.xcodeprojを追加します。

ここからはWorkspaceを見て作業します。

Carthage

Cartfile
github "Carthage/Commandant"
$ carthage update --use-submodules --platform mac

carthage updateしてCheckoutされたプロジェクトをSugoiTool.xcworkspaceに追加します。

SugoiToolKitにFrameworkを追加する

Carthage/Build/Macの中の*.frameworkSugoiToolKitGeneral -> Linked Frameworks and Librariesにドラッグアンドドロップする。

Build PhasesCopy Filesを追加してFrameworkがコピーされるようにする。

スクリーンショット 2016-02-12 16.59.33.png

SugoiToolのファイルを一通り消す

プロジェクトをここまで手順通りにやっていればInfo.plistを残して全て消す。

main.swiftを追加する

SugoiToolmain.swiftを追加する。

main.swiftprint("Hello")とか書いて、Cmd+RでHelloって出力されるはず。

コマンドを実装する

プロジェクトの構成的に、SugoiToolKitにコマンドの実装とテストを置いて、SugoiToolの方からそれを使うというような感じにする。

SugoiToolKitにコマンドの中身を実装する

Sugoi.swift
public struct Sugoi {
  public let isSugoi: Bool
  public init(isSugoi: Bool) {
    self.isSugoi = isSugoi
  }

  public func command() -> String {
    if isSugoi {
      return "凄い"
    }
    return "普通"
  }
}

適宜テストを書いて下さい。

テストを実行する

SugoiTests.swift
import XCTest
@testable import SugoiToolKit

class SugoiTests: XCTestCase {
  func testSugoi() {
    let sugoi = Sugoi(isSugoi: true)
    XCTAssertEqual(sugoi.command(), "凄い")
  }

  func testSugokunai() {
    let sugoi = Sugoi(isSugoi: false)
    XCTAssertEqual(sugoi.command(), "普通")
  }
}

SugoiToolKitTestsGeneral -> Host ApplicationNoneにするとテスト実行できるようになる

SugoiToolにコマンドを実装する

SugoiCommand.swift
import Commandant
import SugoiToolKit
import Result

public struct SugoiCommand: CommandType {
  public let verb = "sugoiCommand"
  public let function = "このコマンドが凄いかどうかを表示する"

  let sugoi = Sugoi(isSugoi: true)

  public func run(options: NoOptions<NSError>) -> Result<(), NSError> {
    print(sugoi.command())
    return .Success(())
  }
}

main.swiftでコマンドを登録する

main.swift
import Commandant

let registry = CommandRegistry<NSError>()
registry.register(SugoiCommand())

let helpCommand = HelpCommand(registry: registry)
registry.register(helpCommand)

registry.main(defaultVerb: "help") { error in
  fputs("\(error)\n", stderr)
}

ここまで来たら、ビルドは通るけど実行するとUnrecognized commandとか表示される状態になってると思います。

コマンドラインから実行できるようにする

Makefileを追加する

これを追加します。

SugoiToolComponents.plistを追加する

Components.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
    <dict>
        <key>BundleIsVersionChecked</key>
        <false/>
        <key>BundleOverwriteAction</key>
        <string>upgrade</string>
        <key>ChildBundles</key>
        <array>
            <dict>
                <key>BundleOverwriteAction</key>
                <string></string>
                <key>RootRelativeBundlePath</key>
                <string>Library/Frameworks/SugoiToolKit.framework/Versions/A/Frameworks/Commandant.framework</string>
            </dict>
            <dict>
                <key>BundleOverwriteAction</key>
                <string></string>
                <key>RootRelativeBundlePath</key>
                <string>Library/Frameworks/SugoiToolKit.framework/Versions/A/Frameworks/Result.framework</string>
            </dict>
        </array>
        <key>RootRelativeBundlePath</key>
        <string>Library/Frameworks/SugoiToolKit.framework</string>
    </dict>
</array>
</plist>

XcodeからComponents.plistを追加して、↑これと同じ状態になるようにして下さい。

ChildBundlesは適宜変更して下さい。

make installしてみる

$ make install
$ /usr/local/bin/SugoiTool 
dyld: Library not loaded: @rpath/Commandant.framework/Commandant
  Referenced from: /usr/local/bin/SugoiTool
  Reason: image not found
[1]    55628 trace trap  /usr/local/bin/SugoiTool

😵

SugoiTool, SugoiToolKitの設定を変える

SugoiToolKit

Build Settings -> Embedded Content Contains Swift Code

Yesにする

Build Settings -> Runpath Search Paths

  • $(inherited)
  • @executable_path/../Frameworks
  • @loader_path/../Frameworks

の3つを設定する

SugoiTool

Build Settings -> Runpath Search Paths

  • @executable_path/.
  • @executable_path/SugoiToolKit.framework/Versions/Current/Frameworks
  • /Library/Frameworks
  • /Library/Frameworks/SugoiToolKit.framework/Versions/Current/Frameworks
  • $(inherited)

の5つを設定する。SugoiToolKitの部分は適宜変更する

make installしてみる

$ make install
$ /usr/local/bin/SugoiTool 
Available commands:

   help           Display general or command-specific help
   sugoiCommand   このコマンドが凄いかどうかを表示する
$ /usr/local/bin/SugoiTool sugoiCommand
凄い

すごい!!!!!!!!!!!!!!!!!!!!!!!!!!

参考

  • https://github.com/Carthage/Carthage
    • Runpathはまるっとそのままコピペしたので、不要な設定もあるかもしれない
    • Makefileを編集して使った
    • Components.plistを編集して使った
75
65
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
75
65