SwiftPM ライブラリとシステムモジュールを作る方法

SwiftPMでは2種類のパッケージを作れます。

* ライブラリ
  一般的なライブラリを作成します。
  例えば[Alamofire](https://github.com/Alamofire/Alamofire)や[Kingfisher](https://github.com/onevcat/Kingfisher)などのようなライブラリを作りたい場合はこちらになります。

* システムモジュール
  外部ライブラリなどをモジュール化できます。
  libxml2やCommonCryptoなどをモジュール化する場合はこちらになります。
  
## ライブラリを作る

### 作業ディレクトリ作成

```
$ mkdir SamplePackage
$ cd $_
$ swift package init --type library    // swift package init でもOK
```
```
Creating library package: SamplePackage
Creating Package.swift
Creating .gitignore
Creating Sources/
Creating Sources/SamplePackage.swift
Creating Tests/
Creating Tests/LinuxMain.swift
Creating Tests/SamplePackageTests/
Creating Tests/SamplePackageTests/SamplePackageTests.swift
```

### 依存パッケージ設定
ライブラリは依存パッケージを持つことができます。
これにより例えばAlamofireを内部で利用するライブラリなどが作れます。

`Package.swift`に依存関係を指定します。

```Package.swift
import PackageDescription

let package = Package(
    name: "SamplePackage",
    dependencies: [
        .Package(url: "git@github.com:Alamofire/Alamofire.git", majorVersion: 4)
    ]
)
```

依存パッケージがなければ何も指定しません。

### 除外設定
ディレクトリに関係のないファイルやディレクトリ(ドキュメントなど)があるとビルドに失敗することがあります。
その場合、関係のないものをパッケージから除外するよう `exclude` で指定する必要があります。

```
import PackageDescription

let package = Package(
    name: "SamplePackage",
    exclude: ["Docs"]
)
```

### コーディング
`Sources/SamplePackage.swift` にコードを記述します。
公開したいプロトコル・クラス・構造体・関数などはアクセス修飾子`public`または`open`を指定してください。

テストコードは`Tests/SamplePackageTests/SamplePackageTests.swift`に記述します。

### ビルド
```
$ swift build
```

### テスト
```
$ swift test
```

### 公開
SwiftPMのパッケージとして公開するにはGitHubにリポジトリを作成し、タグを作ります。

```
$ git init
$ git add .
$ git remote add origin [GitHub URL]
$ git commit -m "Initial commit"
$ git tag 1.0.0
$ git push origin master --tags
```

タグ名は下記フォーマットに従う必要があります。
このフォーマットに従っていないとSwiftPMでは利用できません。

```
"major.minor.patch[-prereleaseIdentifiers][+buildMetadata]"
```

### 補足
#### 複数モジュールを含むライブラリを作る
`Sources`ディレクトリ内にサブディレクトリを作ると別モジュールになります。

```
Sources/Foo/Widget.swift
Sources/Bar/Bazzer.swift
```

このディレクトリ構成ではモジュール`Foo`と`Bar`が作成されるのでパッケージを使う側は、
`Widget.swift`の内容にアクセスするには`import Foo`する必要があり、
`Bazzer.swift`の内容にアクセスするには`import Bar`する必要があります。

#### Objective-Cでコードを書く
ディレクトリ構成に制限がありますが、SwiftだけでなくC言語やObjective-Cなども使えます。
(対応言語：C / C++ / Objective-C / Objective-C++)
基本的な構成の例は下記の通りです。

```
Sources/Baz/m.c
Sources/Baz/include/m.h
```

この例ではモジュール`Baz`が作成され、`import Baz`することでC言語で書いた関数などにアクセスできるようになります。

詳細はドキュメント["C language targets"](https://github.com/apple/swift-package-manager/blob/master/Documentation/Reference.md#c-language-targets)で確認してください。



## システムモジュールを作る

libxml2をモジュール化する方法を紹介します。

### 作業ディレクトリ作成
```
$ mkdir SwiftClibxml2
$ cd $_
$ swift package init --type system-module
```

```output
Creating system-module package: SwiftClibxml2
Creating Package.swift
Creating .gitignore
Creating module.modulemap
```

### コーディング
```Package.swift
import PackageDescription

let package = Package(
    name: "SwiftClibxml2",
    pkgConfig: "libxml-2.0",
    providers: [
        .Brew("libxml2"),
        .Apt("libxml2-dev")
    ]
)
```

```module.modulemap
module SwiftClibxml2 [system] {
    header "libxml2.h"
    link "xml2"
    export *
}
```

```libxml2.h
#import <libxml2/libxml/tree.h>
#import <libxml2/libxml/parser.h>
#import <libxml2/libxml/HTMLtree.h>
#import <libxml2/libxml/HTMLparser.h>
#import <libxml2/libxml/xpath.h>
#import <libxml2/libxml/xpathInternals.h>
```

### Providers
libxml2を使うにはシステムにlibxml2がインストールされている必要があります。
これは`Package`の引数`providers`に指定することでユーザーに教えることができます。

```
providers: [
    .Brew("libxml2"),    // homebrew
    .Apt("libxml2-dev")  // apt-get
]
```

インストールされていないときは下記のようなメッセージが表示されます。

```
note: you may be able to install libxml-2.0 using your system-packager:

    brew install libxml2
    
```

### 公開する
ライブラリと同じ方法で公開します。

## 参考
[Swift Package Manager Documentation](https://github.com/apple/swift-package-manager/tree/master/Documentation)