いけむランド

はてダからやってきました

Cygport 入門 (ver.2020)

前回 cygport の入門記事を書いてから、また 5 年以上経ってしまったので、最新版に追従した内容で書き直すことにしました。

使用する版は以下のとおりです。

$  cygport --version
cygport 0.34.0
Copyright (C) 2020 Cygport authors

This program comes with NO WARRANTY, to the extent permitted by law.

You may redistribute copies of this program under the terms of
the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any
later version.

For more information about these matters, see the file named COPYING.

Written for the Cygwin project <https://cygwin.com/>.
$

cygport とは

github.com

cygport は Cygwin のパッケージを作成するツールで Linux ディストリビューションでいうところの rpm の spec みたいなレシピ (bash script 形式) で、ソース取得やビルドなどの処理方法の管理をします。*1

大昔はとても読む気にならない generic-build-script *2 を使用していましたが、今はすべて cygport へ移行済みだと思います。

チュートリアル

まずはパッケージのレシピとなる .cygport ファイルを用意する必要があります。

というわけで適当に作業するディレクトリに移動します。/usr/src が推奨されていますが、別に ${HOME}/src などでも問題ないです。

.cygport ファイルの準備

例として libb2 のパッケージを作成してみます。

github.com

libb2-0.98.1-1bl1.cygport ((パッケージ名は pkg-ver-rel で構成されます。pkg はパッケージ名、ver はバージョン番号、rel はリリース番号をそれぞれ表現します。一般的に元のソースのバージョンが変わらないまま、リビルドなどでパッケージをアップデートする場合はリリース番号を上げるポリシーとなっています。)) というファイルを用意します。(以下、中身。)

HOMEPAGE="https://github.com/BLAKE2/${PN}"
SRC_URI="https://github.com/BLAKE2/${PN}/releases/download/v${PV}/${P}.tar.gz"

CATEGORY="Libs"
SUMMARY="C library providing BLAKE2b, BLAKE2s, BLAKE2bp, BLAKE2sp"
DESCRIPTION="${SUMMARY}"

PKG_NAMES="
  libb2
  libb2_1
  libb2-devel
"
libb2_CONTENTS="
  usr/share
"
libb2_1_CONTENTS="
  usr/bin
"
libb2_devel_CONTENTS="
  usr/include
  usr/lib
"
libb2_SUMMARY="${SUMMARY} (licensing & readmes)"
libb2_1_SUMMARY="${SUMMARY} (runtime)"
libb2_devel_SUMMARY="${SUMMARY} (development)"

定義済み変数についての詳細は公式ドキュメントを参照してください。

cygwin.github.io

ここでは .cygport 内で作成者が最低限セットする必要がある変数について説明します。

他の変数についての詳細も公式ドキュメントを参照してください。

cygwin.github.io

HOMEPAGE

そのソフトウェアの詳細が書いてあるサイトの URI をセットします。

SRC_URI

ソースアーカイブのある URI をセットします。通常は http[s]://ftp:// で始まるものをセットします。

ミラーがあるプロジェクトホスティングサービス (例 : sourceforge, gnome, etc...) で提供されてるソースアーカイブの URI の指定には mirror:// 形式を指定することができます。

サポートしているサービスは /usr/share/cygport/mirrors に定義されています。

cygwin.github.io

配布形式が VCS である場合には cygclass による inherit が必要となります。

cygwin.github.io

たとえば、libb2 を git から取得したい場合は以下のように書きます。

GIT_URI="git://github.com/BLAKE2/libb2.git"
inherit git

PATCH_URI

(上記の例では指定していませんが) パッチがある場合は PATCH_URI で指定可能です。

PATCH_URI="
  http://example.com/1.patch
  http://example.com/2.patch.gz
" # 複数指定可能、圧縮されてても OK

CATEGORY

パッケージのカテゴリをセットします。Cygwin 公式で分類されているカテゴリはパッケージ情報をまとめた setup.ini 生成ツールである calm で定義されています。

github.com

SUMMARY / DESCRIPTION

SUMMARYDESCRIPTION はそれぞれソフトウェアの説明です。SUMMARY は 1 行、DESCRIPTION は複数行を想定しています。

Cygwin のパッケージは単なる tarball であるため、パッケージの情報を内部に保持しておらず、それらはダウンロードサイトのトップに置かれた setup.ini に書かれています。

Cygwin のインストーラーである setup.exesetup.ini を読んで、インストール時にパッケージの情報を表示しています。

setup.ini はパッケージ毎の .hint ファイルから生成されますが、その .hint ファイルは生成時に CATEGORY, SUMMARY, DESCRIPTION を参照します。

PKG_NAMES

複数のバイナリパッケージを作成する場合には PKG_NAMES にパッケージ名を列挙します。今回の場合は以下のパッケージが作成されます。

  • libb2-0.98.1-1bl1.tar.xz
  • libb2_1-0.98.1-1bl1.tar.xz
  • libb2-devel-0.98.1-1bl1.tar.xz

基本的にパッケージ分割の方針としては

  • ツールなどの .exe や基本的なドキュメントを含むソース名と同名のもの (${PN})
  • 他の .exe の実行時に必要となる DLL (lib${PN} + ABI バージョン番号)
  • 開発に必要な header や library (lib${PN}-devel)

が主流ですが、doc や別言語 binding を分けているパッケージもあります。

これらとは別にソースパッケージとデバッグパッケージも作成されます。

  • libb2-0.98.1-1bl1-src.tar.xz
  • libb2-debuginfo-0.98.1-1bl1.tar.xz

前者は .cygport を使用してバイナリパッケージを再生成できるようにソースアーカイブやパッチなどの一式が固められています。

後者はデバッガが参照するソースコードやデバッグシンボルだけを集めたものです。

CONTENTS

${pkgname}_CONTENTS にそのバイナリパッケージが格納するファイルのリストをセットします。

パッケージの作成

.cygport の準備ができたため、パッケージの作成を開始します。

fetch

まずは fetch コマンドでソースアーカイブを取得します。

$ cygport libb2-0.98.1-1bl1.cygport fetch
--2020-10-31 10:52:22--  https://github.com/BLAKE2/libb2/releases/download/v0.98.1/libb2-0.98.1.tar.gz
Resolving github.com (github.com)... 13.114.40.48
Connecting to github.com (github.com)|13.114.40.48|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://github-production-release-asset-2e65be.s3.amazonaws.com/44247193/9fd9c200-434a-11e9-8414-fcba3dcd6f36?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20201031%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20201031T015223Z&X-Amz-Expires=300&X-Amz-Signature=e260635cf872833878bd4bd6421e7c36394d2683604dc94e39f43ebe89637eda&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=44247193&response-content-disposition=attachment%3B%20filename%3Dlibb2-0.98.1.tar.gz&response-content-type=application%2Foctet-stream [following]
--2020-10-31 10:52:23--  https://github-production-release-asset-2e65be.s3.amazonaws.com/44247193/9fd9c200-434a-11e9-8414-fcba3dcd6f36?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20201031%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20201031T015223Z&X-Amz-Expires=300&X-Amz-Signature=e260635cf872833878bd4bd6421e7c36394d2683604dc94e39f43ebe89637eda&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=44247193&response-content-disposition=attachment%3B%20filename%3Dlibb2-0.98.1.tar.gz&response-content-type=application%2Foctet-stream
Resolving github-production-release-asset-2e65be.s3.amazonaws.com (github-production-release-asset-2e65be.s3.amazonaws.com)... 52.217.0.172
Connecting to github-production-release-asset-2e65be.s3.amazonaws.com (github-production-release-asset-2e65be.s3.amazonaws.com)|52.217.0.172|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 534928 (522K) [application/octet-stream]
Saving to: 'libb2-0.98.1.tar.gz.tmp'

libb2-0.98.1.tar.gz 100%[===================>] 522.39K   314KB/s    in 1.7s

2020-10-31 10:52:26 (314 KB/s) - 'libb2-0.98.1.tar.gz.tmp' saved [534928/534928]

$

VCS から取得した場合は一時ディレクトリにチェックアウトしたものを再度固めることでソースアーカイブをダウンロードしてきたように振る舞います。

prep

ソースアーカイブの取得ができたら、prep コマンドで作成の準備します。

$ cygport libb2-0.98.1-1bl1.cygport prep
>>> Preparing libb2-0.98.1-1bl1.x86_64
>>> Unpacking source libb2-0.98.1.tar.gz
>>> Preparing working source directory
$

prep コマンドの実行後にカレントディレクトリに libb2-0.98.1-1bl1.x86_64 という作業ディレクトリができているはずです。((ただし VCS からソースを取得した場合は fetch の時点で作成されます。))

$ ls libb2-0.98.1-1bl1.x86_64
CYGWIN-PATCHES  build  config  dist  inst  log  origsrc  patch  spkg  src  temp
$

配下の各ディレクトリについて、以下に示します。

ディレクトリ名 用途
build ビルド用作業場所
config cygport 設定ファイル置場
dist パッケージツリー置場
inst インストール先となるダミーディレクトリルート
log 作業ログ置場
origsrc オリジナルソースディレクトリ
patch パッチファイル置場
spkg パッケージ置場
src 作業用ソースディレクトリ
temp 一時ディレクトリ (前述の VCS チェックアウトで使用)

ちなみに prep は以下の作業をします。

  • 作業ディレクトリ群の作成
  • origsrc 配下にソースアーカイブの展開
  • origsrc に必要なパッチの適用
  • origsrcsrc にコピー (rsync)
  • src/${SRC_DIR}/CYGWIN-PATCHES の作成 & CYGWIN-PATCHES からシンボリックリンク

compile

展開したら、いよいよビルドです。

$ cygport libb2-0.98.1-1bl1.cygport compile
>>> Compiling libb2-0.98.1-1bl1.x86_64
:
:

デフォルトではビルドツールとして GNU Autotools を使用する設定になっているため、それを使っている libb2 では特に追加の設定はなしで compile できます。

他のビルドツール (例 : cmake, meson, etc...) を使用する場合は VCS を使用する場合にように適切な cygclass を inherit します。

また、単純な Makefile のみが提供されているような場合は inherit は使わずに関数 src_compile を再定義します。

src_compile()
{
  cd ${B} # ビルド用ディレクトリ (上述の build) に移動
  lndirs  # 作業用ソースディレクトリから再帰的にシンボリックリンクを作成
  cygmake # cygport 用のデフォルトオプションつきで make を起動
}

コンソールに流れるログは log/${PF}-compile.log にも残っているため、遡る場合はそちらを参照できます。

ソースコードの修正

ソースコードの修正なしで問題なくビルドできることは稀で、ほとんどの場合は何かしらのソースコードの修正が必要となります。

今回は以下の修正をしました。

--- origsrc/libb2-0.98.1/src/Makefile.am        2019-03-11 00:36:24.000000000 +0900
+++ src/libb2-0.98.1/src/Makefile.am    2020-10-31 11:02:58.611632400 +0900
@@ -13,7 +13,7 @@ EXTRA_DIST =

 CPPFLAGS += $(LTDLINCL) $(OPENMP_CFLAGS)
 CFLAGS += $(OPENMP_CFLAGS)
-LDFLAGS += -version-info $(B2_LIBRARY_VERSION)
+LDFLAGS += -no-undefined -version-info $(B2_LIBRARY_VERSION)

 lib_LTLIBRARIES = libb2.la
 libb2_la_LIBADD = # -lgomp -lpthread

ソースコードの修正をする場合は src 配下のものを触ります。origsrc にオリジナルを置いてあるため、これとの差分で簡単にパッチを生成できるようになっています。

check

ビルドできたら、テストをします。

$ cygport libb2-0.98.1-1bl1.cygport check
>>> Testing libb2-0.98.1-1bl1.x86_64
:
:

ソースアーカイブに含まれているテスト (GNU Autotools では make check) を実行するため、テストが含まれていない場合は何もしません。

必要な場合は関数 src_test を再定義することで独自のテストをさせることができます。

また、こちらもコンソールに流れるログは log/${PF}-check.log にも残っています。

install

テストも合格したため、install コマンドで生成物をインストールします。*3

$ cygport libb2-0.98.1-1bl1.cygport install
>>> Installing libb2-0.98.1-1bl1.x86_64
:
:

インストール先はシステムではなくて、inst 配下になります。デフォルトでは make install DESTDIR=${D} を実行します。

独自のインストール処理をしたい場合は関数 src_install を再定義します。

install の内部では postinst という別のコマンドも実行されます。postinst の処理の一部を以下に示します。

  • README や COPYING などの一般的な文書ファイルのインストール (/usr/share/doc/${PN}/ 配下)
  • /etc/{postinst,preremove} の生成
  • man や info の圧縮 (gzip)
  • PE バイナリの strip
  • 空ディレクトリや obsolete なファイルの削除

ログは log/${PF}-install.log に書き出されます。

list

list コマンドでインストールしたファイル一覧を確認できます。

$ cygport libb2-0.98.1-1bl1.cygport list
/usr/bin/cygb2-1.dll
/usr/include/blake2.h
/usr/lib/libb2.dll.a
/usr/lib/pkgconfig/libb2.pc
/usr/share/doc/libb2/COPYING
$

package

package コマンドでインストールしたファイル群を CONTENTS 毎にまとめます。

$ cygport libb2-0.98.1-1bl1.cygport package
>>> Packaging libb2-0.98.1-1bl1.x86_64
>>> Creating binary package(s)
:
:

ちなみに package は以下の作業をします。

  • inst 配下のファイルのうち *_CONTENTS で指定したものを tar + xz
  • パッケージに含まれないファイルやパッケージ間で重複しているファイルがないか確認 → あればエラー終了
  • ビルドするためのパッチの生成 (cygport diff で単体実行可能)
  • *.hint の生成

ログは log/${PF}-pkg.log に書き出されます。

配布

package コマンドの実行後には dist 配下に配布用の構成でパッケージが配置されます。

$ tree libb2-0.98.1-1bl1.x86_64/dist
libb2-0.98.1-1bl1.x86_64/dist
└── libb2
    ├── libb2-0.98.1-1bl1-src.hint
    ├── libb2-0.98.1-1bl1-src.tar.xz
    ├── libb2-0.98.1-1bl1.hint
    ├── libb2-0.98.1-1bl1.tar.xz
    ├── libb2-devel
    │   ├── libb2-devel-0.98.1-1bl1.hint
    │   └── libb2-devel-0.98.1-1bl1.tar.xz
    └── libb2_1
        ├── libb2_1-0.98.1-1bl1.hint
        └── libb2_1-0.98.1-1bl1.tar.xz

3 directories, 8 files
$

これをインストールできるようにするために HTTP でアクセスできる場所へコピーし、calm (に含まれる mksetupini) で setup.exe が読むための setup.ini を生成します。*4

# 使用する httpd の設定によって DocumentRoot は変更する
$ cp -R libb2 /var/www/dist/x86_64/release/
$ cd /var/www/dist
$ mksetupini -v --arch x86_64 --inifile ./x86_64/setup --okmissing required-package --releasearea .

calm のインストールについては以下の記事を参照してください。

fd0.hatenablog.jp

インストール

いよいよ setup.exe で自作のパッケージをインストールするのですが、setup.exe はセキュリティの面からデフォルトで signature を要求します。公式のダウンロードサイトでは提供されていますが、ローカルでは用意することが面倒なため、-X オプションで signature 要求機能を off にしておきます。

f:id:fd0:20201031235116p:plain

起動後にダウンロードサイトの選択画面に遷移したら、パッケージを置いている URL を指定します。具体的にはフォームに URL を入力して Add します。

f:id:fd0:20201031235342p:plain

先ほど作成したパッケージを選択します。New のカラムをクリックすると、インストールするバージョン番号に変わります。

f:id:fd0:20201031235438p:plain

あとは Next を押して進んでいけば、インストール完了となります。

インストールができているかは cygcheck で確認できます。

$ cygcheck -cd | grep libb2
libb2                                  0.98.1-1bl1
libb2-devel                            0.98.1-1bl1
libb2_1                                0.98.1-1bl1
$

まとめ

cygport を使った自作パッケージの作成からインストールまでの手順をまとめました。

cygclass やそれらで使用するオプションについても今後、紹介する予定です。

*1:作者曰く Gentoo の Portage に inspire されたらしいです。

*2:ソースの管理をしていた viewvc がもう稼働していないため、リンク切れになりました

*3:テストがこけても、以降の処理はできますが、配布する場合はその旨を記載しておくことが望ましいでしょう。

*4:HTTP デーモンとして Cygwin で動く Apache や Lighttpd を使用することはできますが、その場合は windows は起動中の executable の書き換えができないため、それら自身の更新ができなくなることに注意してください。