RustのソフトウェアをSnapcraftのパッケージにする

# はじめに
[Snapcraft](https://snapcraft.io)とはCanonicalが開発しているパッケージマネージャです。（昔はSnappyだったと思うんですが変わったんですかね？公式サイトがSnapcraftになっているのでここではそれに従います）
最近のUbuntuにはデフォルトで入っていたり、いろいろなlinuxディストリビューションに対応したりしているようです。

Rustのソフトウェアを配布する際に、Rustの開発者前提なら`cargo install`でいいのですが、一般には敷居が高いです。
そうすると「`yum`や`apt`といった普通のパッケージマネージャで入れたい」となるのですが、こちらは公式リポジトリに入れるのはすごく大変ですし、野良リポジトリというのも（開発者にとっても利用者にとっても）手間がかかります。

というわけで第三の選択肢として、Snapcraftのようなクロスプラットフォームのパッケージマネージャがあります。同様のパッケージマネージャはいくつかありますが、Snapcraftは

- Ubuntuにデフォルトで入っている
- 公開までのフローが自動化されている

という2点から、手早く一般向けに配布する方法として良さそうな感じです。他のパッケージマネージャ（例えばHomebrewなど）はGitHubのプルリクエストベースで追加や更新を受けていることが多いですが、レビューを受けてマージされるのに１ヶ月以上かかることもあります。SnapcraftはRustにおけるcrates.ioと同じくユーザ操作だけで公開まで行くので、慣れればすぐです。

また、Snapcraftは公式にRust製ソフトウェアのパッケージ化に対応していたり、GitHubと連携できるCI環境があったりと、かなり便利に出来ています。

今回は

[procs：新しいプロセス表示・検索ツール](https://qiita.com/dalance/items/388d98c99ae2857d73e6)
http://github.com/dalance/procs

をSnapcraftのパッケージにしてみました。

# 手順

## アカウント作成
https://snapcraft.io の右上にある "Developer account" から進んでアカウント作成～ログインします。
正直全部GitHubアカウントがいいのですが、そうもいかないのでubuntu oneのアカウントを作成することになります。

## GitHubとの連携
ドキュメントの手順と違いますが、最初に連携してしまうのが簡単だと思います。
ログインしたら右上のアカウントメニューから "Build with GitHub" を選んで指示に従います。
進めていって、リポジトリまで選んだらこんな感じです。

![repo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84296/680778ba-5bf6-6606-043a-2642abc1c859.png)

ここで "Not registered" となっている部分をクリックして、公開する時のパッケージ名を登録できます。
"Not configured" はこの後の`snapcraft.yaml`をコミットすれば自動で変わります。

## `snapcraft.yaml`の作成

Rustっぽい部分はここだけですね。GitHubリポジトリのルートに`snapcraft.yaml`を置きます。

```snapcraft.yaml
name: procs
version: &version v0.8.5
summary: A modern replacement for ps written in Rust
description: |
  procs is a tool to display process information.
base: core18
license: MIT

confinement: strict

architectures:
  - build-on: amd64
  - build-on: i386
  - build-on: ppc64el
  - build-on: arm64
  - build-on: armhf

apps:
  procs:
    command: procs

parts:
  procs:
    source: https://github.com/dalance/procs.git
    source-tag: *version
    plugin: rust
    stage-packages:
      - libc6
      - libgcc1
      - libstdc++6
      - zlib1g
```

それぞれの細かい意味は飛ばします。[公式ドキュメント](https://docs.snapcraft.io/snapcraft-yaml-reference)を見てください。
Rustに関係するところだけ補足すると、`base: core18`は公式のRust環境では必須です。
あとは`plugin: rust`と指定するくらいで勝手に`cargo build --release`してできたバイナリをパッケージしてくれます。

このファイルをコミットしてしばらく待つと以下のようにConfiguredにチェックが付いて、勝手にビルドされます。

![repo2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84296/f43f2072-7b36-b771-ea26-02dea56d96b9.png)

## リリース作業

あとは説明用のページを作ったり、ビルドに成功したパッケージをstableに指定したり、といった作業があります。
Web UI上の操作なので雰囲気で分かると思います。

## インストールを試す

ここまでくればUbuntu環境から以下のようにインストールできます。

```console
$ sudo snap install procs
```

# （補足）ターゲットアーキテクチャについて

Snapscaftはデフォルトでは amd64/i386/ppc64el/arm64/armhf/s390xの6つのアーキテクチャ向けにビルドされます。
このうちs390xはSnapcraftのRust環境が未対応でビルドできません。
`snapscaft.yaml`の`architecutures`を書かないと毎回ビルドを試みて失敗することになるので、明示的に除外しましょう。
残りの5つはビルドできていいはずですが、32bit系のi386/armhfはうまくいきませんでした。
i386はリンカが見つからないエラー、armhfはrustupに失敗する、という状態です。
一応この2つはビルドできるようにしたいと思っていて現在調査中です。

# (2019/6/13追記) i386ビルド
i386でビルドが失敗する問題は、SnapcraftのRustプラグインが生成する`.cargo/config`内のリンカ指定が間違っていたためでした。これを修正した[PR](https://github.com/snapcore/snapcraft/pull/2580)を取り込んでもらったところ、i386でもビルドが成功するようになりました。

# (2020/7/9追記) armhfビルド
ずっとrustupに失敗していたarmhfですが、Snapcraftのビルドサーバ側でなんらかの対応があったようで、ビルドできるようになりました。
（7/5頃から全アーキテクチャでrustupが失敗するようになっており、その問題を解消したところarmhfも直ったようです）