BOOST TEST - 複数ファイルで動的ライブラリを利用2020年05月13日 11時22分13秒

BOOST TEST - 複数ファイルで静的ライブラリを利用では静的ライブラリを使った BOOST TEST の使い方を紹介した。BOOST TEST を大きくし始めるにあたっては手頃なのだが、折角なのでもう一歩勧めて動的ライブラリを使えるようになるまでいきたい。

The shared library variant が元のライブラリの説明がある。

Boost Test の動的ライブラリと静的ライブラリの利用の仕方の相違点は、リンカと動的ライブラリに依る。静的ライブラリの場合は、.a ファイルからオブジェクトコードを抜きだし、プログラムに組み込む。その為、main 関数であっても静的ライブラリから持って来ることが出来る。それに対し、動的ライブラリは、プログラム中にどの関数等が必要かを記録しておいて、実行時に .so ファイルから読み込み、実行する。main 関数が動的ライブラリにあっても、実行ファイルに取り込めないので、スタート地点の無いプログラムになるわけだ。それで、リンクに失敗する。

その為、Boost Test で動的ライブラリを利用するには指定通りの main 関数を再実装する必要がある。そして、静的ライブラリと同様に、boost_unit_test_framework ライブラリをリンクする場合には、一つのファイルのみ BOOST_TEST_MODULE を定義する。

静的ライブラリの時に使った -static リンクオプションが必要無くなるので、循環依存関係の解決にも若干緩くなるようだ。そのため、下準備にちょっと追加で出来る動的ライブラリの方が総合的には使いやすい様だ。

まず、一つ目の特別なファイル。

// c++ -c -o 1.o -I /usr/local/include/ boost_dynamic_unit_test1.cpp

// #define BOOST_TEST_MODULE Verify Std C++
#define BOOST_TEST_DNY_LINK
#define BOOST_TEST_ALTERNATIVE_INIT_API
#include <boost/test/unit_test.hpp>

#ifdef BOOST_TEST_ALTERNATIVE_INIT_API
bool init_unit_test()
{
    return true;
}
#else
extern boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[
] );
boost::unit_test::init_unit_test_func init_unit_test = init_unit_test_suite;
#endif

int main( int argc, char* argv[] )
{
    return boost::unit_test::unit_test_main( init_unit_test, argc, argv );
}
まずは、少し気を付ける事項から。
  1. main 関数を定義する。
  2. BOOST_TEST_DNY_LINKを定義する。 を定義する。
  3. BOOST_TEST_ALTERNATIVE_INIT_API を定義するかしないかで、init_unit_test の型が違う。
  4. それ以外は書かない。
このファイルにテストケースを書くことも可能だが、main 関数の為だけにファイルを準備した方が、特別性を際立たせるのに都合が良い。このファイルはこれ専用にするのを勧める。

これをコンパイルする。今回は、-c オプションを使ってコンパイルのみにする。

% c++ -c -o 1.o -I /usr/local/include/ boost_dynamic_unit_test1.c
-I はどこに boost ライブラリがインストールされているかに依存する。Linux 系だったら /usr/include 以下で特に必要無いだろう。BSD 系だと /usr/local/include が必要になる。

次に実際にテストケースを書くファイルの説明に移る。まず、一番大切な事。こちらにも、 BOOST_TEST_DNY_LINK を定義する。あとは単体の時と同じように BOOST TEST CASE を書く。

 c++ -c -o 1.o -I /usr/local/include/ boost_dynamic__unit_test1.cpp
// c++ -c -o 2.o -I /usr/local/include/ boost__dynamic_unit_test2.cpp
// c++ 1.o 2.o -L /usr/local/lib -l boost_unit_test_framework
// c++ -L /usr/local/lib -l boost_unit_test_framework 1.o 2.o

#include <memory>
#define BOOST_TEST_DNY_LINK
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE( test_shard_ptr )
{
    int one = 1;
    int two = 3;

    BOOST_CHECK( one == 1 );
    BOOST_CHECK( two == 2 );

    BOOST_CHECK_EQUAL( one, 1 );
    BOOST_CHECK_EQUAL( two, 2 );
 
    BOOST_REQUIRE( one == 1 );
    BOOST_REQUIRE( two == 2 );
}

そして、二つ目のファイルをコンパイルし、リンクする。-I オプションと同様に、-L オプションも環境依存。大概のしすてむは動的ライブラリがデフォルトになっているので、暗示的に動的ライブラリを使う。その為、リンクオプションが若干短い。

% c++ -c -o 1.o -I /usr/local/include/ boost_dynamic_unit_test1.cpp
% c++ -c -o 2.o -I /usr/local/include/ boost_dynamic_unit_test2.cpp
% c++ 1.o 2.o -L /usr/local/lib -l boost_unit_test_framework
% ./a.out 
Running 1 test case...
boost_dynamic_unit_test2.cpp(16): error: in "test_shard_ptr": check two == 2 has failed
boost_dynamic_unit_test2.cpp(19): error: in "test_shard_ptr": check two == 2 has failed [3 != 2]
boost_dynamic_unit_test2.cpp(22): fatal error: in "test_shard_ptr": critical check two == 2 has failed

*** 3 failures are detected in the test module "Master Test Suite"
リンク後の実行結果は前回と同じになる。

前回次回