はじめに
システムコールやライブラリのバインディングを書くときに,
実際にシステム上でそのシステムコールやライブラリ関数の呼び出しが
行えることを確認したいことがあります.
一般的にはシステムコールにしてもライブラリ関数にしても, ヘッダファイルの
特定のマクロを読み出したり, バージョンを調べたりということである程度回避
できます. しかしすべてのシステム, ライブラリがそのようなものを提供しているわけでは
ないですし, ときには間違っていることもあります.
確実な方法は実際にその関数を呼び出すファイルがコンパイル・リンク
できることを確認することです. configure
が行っていることですね.
この目的を実現するためのモジュールがDevel::CheckCompiler
です.
(この機能のためだけのモジュールではなく, 他にも便利な機能もあります.
全容が気になる方はドキュメントを確認してみてください)
##リポジトリ
https://github.com/tokuhirom/Devel-CheckCompiler
##サンプルコード
以下は Linux::Socket::Accept4で実際に使われている例です. accept4
システムコールは古いシステムには備わっていないのでそのチェックをします.
check_compile
関数は実際にコンパイルを行う関数ですが, executable
を 1
に
設定することでリンクまで行います. リンクまで行えて実行ファイルが作れたら 1
,
失敗の場合はそれ以外が返ります. これにより, 目的のシステムコール, ライブラリ関数が
実際に使えるかどうかを確認することができます.
package builder::MyBuilder;
use strict;
use warnings;
use utf8;
use 5.010_001;
use parent qw(Module::Build);
use Devel::CheckCompiler 0.04;
sub new {
my $self = shift;
if ($^O ne 'linux') {
print "This module only supports linux.\n";
exit 0;
}
if (check_compile(<<'...', executable => 1) != 1) {
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <sys/socket.h>
int main(void)
{
return accept4(0, (void*)0, (void*)0, 0);
}
...
print "This module only supports linux 2.6.28+ and glibc 2.10+.\n";
exit 0;
}
$self->SUPER::new(@_);
}
1;
###リンクオプションを渡す必要がある場合
リンク時ライブラリオプションが必要な場合は, check_compile
関数の extra_linker_flags
に
文字列 or 文字列のリストを渡してください.
#!/usr/bin/env perl
use strict;
use warnings;
use Devel::CheckCompiler;
if (check_compile(<<'...', executable => 1, extra_linker_flags => '-laa') != 1) {
#include <aalib.h>
int main(void)
{
aa_flush((void*)0);
return 0;
}
...
print "NG\n";
exit 0;
}
print "OK\n";
##おわりに
Devel::CheckCompiler
を用いて, システムで実際にライブラリ関数 or システムコールが
使えるかどうかを確認する方法について示しました.
問題等ありましたら githubの issuesまでお願いします. (tokuhiromさんのリポジトリですが, 私もメンテナです)
明日は @yak_ex さんです. お楽しみに.