リンク無しでテスト用のソースファイルが複数ある状況でビルドしようとしたら嵌ったお話。
先日、ユニットテストについての講義をする際に「取りあえず Boost.Test を使ってみましょう」と言うことで、リンク(≒ Boost をビルド)しなくても良い boost/test/included/unit_test.hpp を使おうとしたのですが、以下のようなリンクエラーが出力されました(Visual C++ 2012)。
error LNK2005: "public: __thiscall boost::unit_test::ut_detail::auto_test_unit_registrar::auto_test_unit_registrar(class boost::unit_test::test_unit_generator const &)" (?? 0auto_test_unit_registrar@ut_detail@unit_test@boost@@QAE@ABVtest_unit_generator@23@@Z) は既に gp2-test.obj で定義されています。 …(後略)…
ビルドを通すのにやや苦労しましたが、結論としては「リンク無しで Boost.Test フレームワークを複数のソースファイルが存在する状況で使用する場合」は以下の点を注意する必要があるようです。
- #include <boost/test/included/unit_test.hpp> を記述するのは 1 箇所のみ(2 箇所以上でインクルードすると、前述したリンクエラーが発生)。main.cpp 的なファイルを作成して、そこでインクルードするのが良いか。
- それ以外のファイル(各テストを記述したファイル)については、リンクしない場合であっても
#include <boost/test/unit_test.hpp> と記述する。 - このままだと Boost.Test 用のライブラリをリンクしようとしてエラーになるので、コンパイル時に BOOST_TEST_NO_LIB または BOOST_ALL_NO_LIB を定義してリンクしないようにする。
ソースファイルの構成例
1. main.cpp
#define BOOST_TEST_MAIN // or #define BOOST_TEST_MODULE test_module_name #include <boost/test/included/unit_test.hpp>
2. test1.cpp
#include <boost/test/unit_test.hpp> BOOST_AUTO_TEST_CASE(test_case1) { BOOST_CHECK(true); }
3. test2.cpp(以下、必要なファイル数だけ同様に)
#include <boost/test/unit_test.hpp> BOOST_AUTO_TEST_CASE(test_case2) { BOOST_CHECK(true); }
コンパイル時に BOOST_TEST_NO_LIB 指定を忘れずに。気を付けないと嵌りますが、リンク有無に関わらずメインファイル以外のインクルード記述は変わらないので、どちらにも移行しやすいと言うのは利点かもしれません。