こんにちは、20日目の投稿になります。
今日はNativeCallを使ったモジュールの作り方を紹介しようと思います。
はじめに
私は今年libgeohashのPerl6用のバインダを作りました。そのときのノウハウを紹介したいと思います。
ただし、公式のドキュメントがまだまだ不十分というのもあり、[要出典]な部分がたくさんあるかもしれません。
geohashとは
緯度、経度をひとつのbase32の符号で表現したものです。
base32の符号を01のビット表現に直すと、左から見たときの偶数位置のビットが経度を、奇数位置のビットが緯度を示しています。
便利モジュール
App::Mi6
mi6を使うと簡単にベースになるファイル群が作れます:
$ mi6 new Geo::Hash
$ mv Geo-Hash p6-Geo-Hash
LibraryMake
- VM(e.g. MoarVM, JVM)をビルドしたときのオプションを流用することで、libgeohashのビルドを行います。
- 上記のプロセスを簡単に行うためのライブラリがLibraryMakeです。
-
process-makefile
でMakefileの処理を、get-vars
でVMのビルド時のオプションを取得することができます。
各ファイルについて
ファイル構成
- mi6で生成されたファイルとは別に追加で下記のファイルが必要です
- ルートにBuild.pm
- src以下にlibgeohash関連ファイル
$ tree .
.
├── Build.pm
├── LICENSE
├── META6.json
├── README.md
├── bin
├── lib
│ └── Geo
│ ├── Hash
│ │ └── Coord.pm6
│ └── Hash.pm6
├── src
│ ├── Makefile.in
│ ├── geohash.c
│ ├── geohash.h
│ └── geohash_test.c
└── t
└── 01-basic.t
6 directories, 11 files
と.travis.yaml
META6.json
- 記述するためのポイントは2点あります
- build-dependsに忘れないようにLibraryMakeを追加しましょう: https://github.com/titsuki/p6-Geo-Hash/blob/0.0.1/META6.json#L5-L7
- resourcesにビルド後のシェアードオブジェクトやダイナミックライブラリ(e.g.
.so
,.dylib
,.dll
なファイル)を入れたいディレクトリへのパスを指定しましょう: https://github.com/titsuki/p6-Geo-Hash/blob/0.0.1/META6.json#L18
Build.pm
-
この
Build.pm
はtravis-CIにおけるzef build .
の実行時に呼び出されます: https://github.com/titsuki/p6-Geo-Hash/blob/0.0.1/.travis.yml#L11 -
記述するためのポイントは2点あります
- 先ほどresourcesで指定したディレクトリを生成するようにしましょう: https://github.com/titsuki/p6-Geo-Hash/blob/0.0.1/Build.pm#L8-L9
-
%vars<geohash>
変数にどの種類のライブラリ(e.g..so
)を生成するのかを代入します: https://github.com/titsuki/p6-Geo-Hash/blob/0.0.1/Build.pm#L7 -
process-makefile
の第二引数にこの%vars
を渡すことで、Makefile.inで使えるようにします(※): https://github.com/titsuki/p6-Geo-Hash/blob/0.0.1/Build.pm#L10
src/Makefile.in
- 記述するためのポイントは2点あります
- LibraryMakeで取得された変数を使うことができます。この変数はVMをビルドしたときのオプションなので自分で環境を判定して分岐を書く(e.g. OSXかLinuxか)必要はありません: https://github.com/titsuki/p6-Geo-Hash/blob/0.0.1/src/Makefile.in#L6-L7
-
%geohash%
でBuild.pmにおいて%vars
に格納しておいた値を参照できます (リンクは同上)
.travis.yaml
- 記述するためのポイントは一つだけです
- scriptのところに
zef build .
を追加しましょう: https://github.com/titsuki/p6-Geo-Hash/blob/0.0.1/.travis.yml#L8- こうすることでビルド時に
Build.pm
が呼び出され、シェアードオブジェクトやダイナミックライブラリを生成する処理が行われるようになります。
- こうすることでビルド時に
- scriptのところに
lib/GeoHash.pm6
-
記述するためのポイントは一つだけです
- META6.jsonで記述した
resources
の内容を%?RESOURCES<libraries/geohash>.Str
を使うことで取得することができます: https://github.com/titsuki/p6-Geo-Hash/blob/0.0.1/lib/Geo/Hash.pm6#L7-
is native
トレイトに対して上記の値を渡すことで、C言語側の関数を呼び出すことができるようになります: https://github.com/titsuki/p6-Geo-Hash/blob/0.0.1/lib/Geo/Hash.pm6#L9
-
- META6.jsonで記述した
-
ちなみにNativeCallの文法それ自体については次のページを参照ください: https://docs.perl6.org/language/nativecall
リリース
PAUSEアカウントを持っている場合、CPANに対してリリースすることができます。
まず、あなたのホームディレクトリで.pause
ファイルを作りましょう。
<USER>
にはPAUSEでのIDを、<PASSWORD>
にはPAUSEでのパスワードを入れてください:
user <USER>
password <PASSWORD>
そして、uploadしましょう。uploadコマンドでtar.gzファイルの生成まで行ってくれます。
(※すでにGeo-Hashの0.0.1はアップロード済みなので'N'でAbortしています。実際に上げるときは'y'を押してください):
$ mi6 upload
Use of Nil in string context
in block at lib/Geo/Hash.pm6 line 7
==> Execute Build.pm
gcc -shared -fPIC geohash.c -o /home/itoyota/Program/p6-Geo-Hash/resources/libraries/libgeohash.so
gcc geohash_test.c geohash.c
./a.out
rm a.out
Created Geo-Hash-0.0.1.tar.gz
Are you sure to upload Geo-Hash-0.0.1.tar.gz to CPAN? (y/N) N
Abort.
以上、20日目の投稿でした。
※ もしかすると%vars<SO>
に同じ内容が格納されているかもしれません[要出典]、SO
というネーミングを使ってしまうと可読性の問題もあるのでこの書き方にしています。