Qt用のパッケージマネージャのqtpm

* [Qt(C++)用のパッケージマネージャ(qtpm)作ってます](http://qiita.com/shibukawa/items/857f5cb796060802368f)

作り始めたのは1年以上前で、しばらく中断していたのですが、また作り始めました。大幅に方針を変更し、シンプルな実装にしました。

方針転換
===========

しばらくGoをやっていて、Goのシンプルなパッケージ管理で十分だなと思ったのでその方向にかじを切りました。ついでにいままでの実装(Qtで書いている)はすべて捨ててGoに書き換えました。

バージョン管理はやめる
--------------------------

Semverを使ったバージョン管理をしようと思っていました。Gitではタグを打てるので、タグにバージョンを入れて情報を取得・・・というのは誰しも考えることで、SwiftのSPMもそうなっています。

でも、動的になんとかするわけじゃなくてコンパイルしちゃうんだし、ビルドできたらそれでOKでほとんど問題はでないかなぁと思っています。少なくとも動的言語ほど人の手でバージョンとか後方互換性を維持する努力はしなくてもOK。

QMakeはやめてCMakeにする
-----------------------------

Qtの世界でも、4系の後半からQMakeに加えてCMakeのサポートが始まっています。ただQMakeもサポートが終わったわけではないのですが、配布用のライブラリではCMakeを使うケースも増えています。このツールでもえいやでCMakeに一本化しました。ただし、ユーザがCMakeLists.txtを書く、というのは辞めました。自分で使おうと思って調べてもなかなか情報がまとまってなくて、さまざまなページをはしごしながらQtで使う方法とかCMakeの使い方とかを学ぶ必要があり、「CMakeLists.txt書いてね！実行はこっちでやるよ！」というスタイルだと、なかなかコードをかくところまでたどり着かない。

フォルダの構成とか、命名規則を決めておいて、動的にファイルのリストを取得してきてCMakeLists.txtを生成するようにしました。ほとんどCMakeの存在は意識しなくてもいいかと思います。Qt用に必要な設定はツール側で埋め込んだCMakeLists.txtを作るので、Qt用の設定を自分でわざわざする必要はありません。まあQt以外用に使っても問題はないと思いますが、mocコマンドとかを実行しているのでQtのインストールは必要です。

設定よりも規約
---------------------

設定をなるべく減らして簡単に使えるのを目標にしました。C++11をデフォルトでオンしたりとかもしてます。CMakeLists.txtを自動生成するにあたって、以下の様なファイル配置のルールを決めました。

```
+- qtpackage.toml    : パッケージ情報のファイル
+- src/              : ソースファイル(*.cpp/*.h)
+- test/             : テストコード(*_test.cpp)
+- resources/        : リソースファイル
|  +- icon.png       : アイコン画像(1024x1024がベスト)
|  +- translations/  : 翻訳ファイル(.qm)
+- examples/         : サンプルプログラム(*.cpp)
+- translations/     : そのパッケージの翻訳ファイル(*.ts)
+- doc/              : qdocの設定ファイル　
+- html/             : qdocの生成したファイルが入る(予定)
+- vendor/           : 外部のライブラリ
|  +- release/       : リリース版
|     +- include/    : 依存ライブラリのヘッダ
|     +- lib/        : 依存ライブラリ
|  +- debug/         : デバッグ版
|     +- include/    : 依存ライブラリのヘッダ
|     +- lib/        : 依存ライブラリ
|  +- github.com/    : 依存ライブラリのソース
+- build-release/    : ビルド作業フォルダ(リリースビルド用)
+- build-debug/      : ビルド作業フォルダ(デバッグビルド用)
```

このうち、プログラマが触るのはsrcからdocまでで、他のフォルダはツールが勝手に作ったり作業したりする場所です。

ソースフォルダ(src)の直下にmain.cppがあれば、ビルド対象は実行ファイル、そうでなければ共有ライブラリと判断します。ライブラリモードの場合、src直下の.hファイルは外部か参照されるヘッダファイルで、それ以外の.hファイルはvendor/includeにはインストールしない、と割りきりました。

リソースも、フォルダをパースして自動生成するようにしました。リソース置き場のパス内のファイルのパスがすべて(icon.png、*.qrc, Thumbs.db, .DS_Storeを除き)、resource.qrcという自動生成されるファイルに入ります。翻訳ファイルの置き場もこれで決め打ちになります。

テストは各*_test.cppが単独の実行ファイルになり、CMakeのテスト機構を使って実行します。_test.cppが付いてない.cppは、テスト間で共有で使われるユーティリティコードだとみなして、各テストのビルド時にリンクします。

サンプルプログラムはそれぞれ単独の実行ファイルとみなしてビルドします。ただし、テストモードの時しかビルドはしません。

また、npmのnode_modulesと同じように、システムフォルダには何も追加で書き込んだりはしません。すべてローカルの作業しているプロジェクトフォルダのvendor以下に入ります。

Golangのような条件ビルドもサポートしました。 ``sample_windows.cpp`` のような名前の場合、Windows上でのみビルドされます。まだコメントによる分岐はできません。

  * ``_windows``: Windows (Cygwinは除く)
  * ``_darwin``: MacOS X
  * ``_unix``: UnixライクOS(MacOS XとCygwinも含む)
  * ``_linux``: UnixライクOS(MacOS XとCygwinは除く)
  * ``_mingw``: MinGW
  * ``_cygwin``: Cygwin
  * ``_msvc``: Microsoft Visual C++

[CMakeのマニュアル](https://cmake.org/cmake/help/v3.4/manual/cmake-variables.7.html#variables-that-describe-the-system)によると、VC++の細かいバージョンとか、Windows StoreとかWindows Phoneとか、Borlandとかもありますが、そこまでは対応していません。あと、Mac OS X以外のUNIXというのは指定できたほうが嬉しいかな、と思ってlinuxを追加しましたが、CMakeには本来このような変数はありません。内部では``"UNIX AND NOT APPLE AND NOT CYGWIN"`` という条件式でエミュレートしています。LinuxといいつつFreeBSDとかもこれに含まれると思います。MacOS以外のUnix系OSみたいなのを簡潔に表せる単語があれば・・・

もうできること
=====================

実行にはQt5系と、CMakeが必要です。Qtは標準パス(apt-getとかport installしたら入る場所)でも対応しますが、Qtのバイナリパッケージでインストールするパスでも大丈夫なようにしています。また、明示的にQTDIR環境変数に入れれば、Windowsでmingwがいい/VC++2013がいい/VC++2015がいいみたいなケースにも対応できるはず。

あと、今はインストールにGoも必要ですが、安定したらバイナリをアップロードします。

```bash
# パッケージマネージャのインストール
$ go get github.com/qtpm/qtpm

# アプリケーションモードで初期化
$ qtpm init app

# ライブラリモードで初期化
$ qtpm init lib

# ビルド
$ qtpm build

# インストーラ作成 (まだMacのみ)
$ qtpm pack

# ファイルフォーマット修正(プロジェクト内の全ソースに対してclang-formatを実行)
$ qtpm fmt

# テスト実行
$ qtpm test

# (qtpackage.tomlに依存ライブラリが設定されている場合)必要なファイルを一括取得
$ qtpm get

# 依存ライブラリのダウンロード(qtpackage.tomlがあれば必要なモジュールとして追加)
$ qtpm get github.com/qtpm/QtCBOR

# 作業フォルダのクリア
$ qtpm clear

# 翻訳ソースファイルを追加
$ qtpm i18n add ja

# 翻訳ソースファイルを更新
$ qtpm i18n update

# 翻訳ソースファイルを編集(linguist起動)
$ qtpm i18n edit
```

getは今のところgithubを念頭に置いています。試してないですがgithub:eとかでも問題ないはず。bitbucketもいけるかな？今丁度Cocoapodの実行時のgithubのパフォーマンス問題で揺れているところですが、デフォルトでは.zipでダウンロードを使ってファイルを取ってきます。--gitを付けるとgit cloneします。またすでにフォルダがあればそのパッケージの取得はしません。-uを付けた時に更新します。

あとは、規約のところでも触れましたが、条件ビルドもできますし、 ``qtpm build release``、 ``qtpm build debug``でリリースビルド、デバッグの切り替えもできます。

あと、``qtpm pack``で、Macの.dmgファイルを一発で生成できます。必要なQtのフレームワークを集めてくるところ(``macdeployqt``の実行)も裏でやっていますので、他の人に配布可能なはず。Windowsはこれから。時間があったら.debの生成もやりたいですね。Qt Installer Frameworkを使うことも考えたのですが、Macは.dmgで問題ないし、WindowsはInno Setupでいいかなぁ、と思ってます。

まだできないこと
=====================

コマンドとしては後以下のコマンドを追加しようかと思っています。

```bash
# ドキュメントのビルド
$ qtpm doc
```

ドキュメントはSphinxでcppdomainを使う方向でもいいかなぁと思っています。qdocはフレームワークがいくつも分かれるような大規模なドキュメントを前提としていて、クラス数個のちょっとしたライブラリとかは逆に不便です。qdocのマークアップも書きにくいし。Doxygenで生成したXMLを使って自動ドキュメントを行うbreatheの動かし方が分かったらやりたいです。

今後
=============

まだ多少がんばらなければならないのですが、だいぶ便利にできるようになったかなぁと思います。ユニットテストを書き始めて実行するまでの時間がすごい短くなっただけでも価値があると思います。

同じCMakeをバックエンドに使ったCPMパッケージも取り込めるようにしたり、clibのファイルの取得もサポートしてもいいかなぁとは思っていますが、Qt自身がかなりリッチなのであまりいらない気もしています。

後はぼちぼち自分で使いたいライブラリを作っていこうかなぁと思っているところです。ちなみに、1年以上前に勢いで下記のOrganizationは取得してしまったので、こちらに置いていく予定です。もしここに入りたい方がいたらぜひ。

* https://github.com/qtpm

あと、僕がやろうとしていることとほぼ同じことをやろうとしている人もいました。後で見てみる予定。

http://www.qpm.io/