josch
josch

Reputation: 7174

How to compile boost unit test module with clang++?

I'm trying to compile a boost unit test module with cmake and clang but ran into a linker error. I was able to produce the following minimal test case:

$ cat boost_test_test.cc
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE scanio
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE(foo) { BOOST_CHECK(1); }

This compiles fine with g++:

$ g++ boost_test_test.cc -lboost_unit_test_framework
$ echo $?
0

But it does not with clang++:

$ /usr/bin/clang++-3.7 boost_test_test.cc -lboost_unit_test_framework
/tmp/boost_test_test-7e4892.o: In function `boost::unit_test::make_test_case(boost::unit_test::callback0<boost::unit_test::ut_detail::unused> const&, boost::unit_test::basic_cstring<char const>)':
boost_test_test.cc:(.text._ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE[_ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE]+0x58): undefined reference to `boost::unit_test::ut_detail::normalize_test_case_name(boost::unit_test::basic_cstring<char const>)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

So during the linker stage I get an undefined reference error and this problem persists no matter the order of arguments to clang++.

Since it works fine with g++ I suppose there is something clang++ specific going on here?

This is with g++ 5.2.1, clang++ 3.7 and boost 1.58 on Debian Sid.

Upvotes: 3

Views: 1114

Answers (1)

Maciek D.
Maciek D.

Reputation: 2864

In Ubuntu Willy, Boost 1.58 Unit Test library is compiled with GCC 5.0. The library file libboost_unit_test_framework.a contains the mangled function _ZN5boost9unit_test9ut_detail24normalize_test_case_nameB5cxx11ENS0_13basic_cstringIKcEE that resolves to boost::unit_test::ut_detail::normalize_test_case_name[abi:cxx11](boost::unit_test::basic_cstring<char const>)

However, CLang does not seem to use the new ABI, so it searches for _ZN5boost9unit_test9ut_detail24normalize_test_case_nameENS0_13basic_cstringIKcEE, which is boost::unit_test::ut_detail::normalize_test_case_name(boost::unit_test::basic_cstring<char const>).

In order to overcome this, define your own function in the test file:

namespace boost { namespace unit_test { namespace ut_detail {
    std::string normalize_test_case_name(const_string name) {
        return ( name[0] == '&' ? std::string(name.begin()+1, name.size()-1) : std::string(name.begin(), name.size() ));
    }
}}}

This should resolve the issue. If compiled with the same version of the compiler as Boost, it should be no problem, as the linker will simply ignore the library version of the function.

Upvotes: 3

Related Questions