Boost unit test dynamic link on Ubuntu

I am trying to create a unit test using Boost unit test. I would like to dynamically link test suite libraries with an auto-generated test unit that Boost provides. Here's the basic construction I used:

test_main.cpp:

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN

#include <boost/test/unit_test.hpp>

      

lib_case.cpp:

#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>


BOOST_AUTO_TEST_SUITE( test_lib )

BOOST_AUTO_TEST_CASE( test_lib_case ) {
    BOOST_ASSERT(true);
}
BOOST_AUTO_TEST_SUITE_END()

      

Makefile:

    all: unittest unittest2 unittest3

    lib_case.o: lib_case.cpp
        g++ -g -c -Wall -fPIC lib_case.cpp -o lib_case.o

    libcase.so: lib_case.o
        g++ -shared -Wl,-soname,libcase.so -o libcase.so lib_case.o

    unittest: libcase.so
        g++ -o unittest test_main.cpp -L. -lcase -lboost_unit_test_framework

    unittest2: test_main.cpp lib_case.cpp
        g++ -o unittest2 test_main.cpp lib_case.cpp -lboost_unit_test_framework

    unittest3: lib_case.o
        g++ -o unittest3 test_main.cpp lib_case.o -lboost_unit_test_framework

      

Testing on Ubuntu 14.04, all binaries compile and link without error.

'unittest' fails to execute package 'test_lib', claiming that the installation failed, but 'unittest2' and 'unittest3' will succeed:

$./unittest
Test setup error: test tree is empty
$./unittest2
Running 1 test case...
*** No errors detected
$./unittest3
Running 1 test case...
*** No errors detected

      

Now for the headache: all unittest * are running the test suite on Fedora 20.

When looking through the dependency lists for "unittest" I see that "libcase.so" is not listed in Ubuntu version but is in Fedora 20 version. I have been playing around with re-ordering dependencies using absolute paths for SO and modifying Boost versions (1.54 and 1.55 ). Nothing succeeded.

Any ideas on what might be preventing libbra.so from linking from Ubuntu 14.04 but not Fedora 20? Am I missing some magic compiler / linker flag?

Update:

The comment and answer helped narrow down the problem a little more. If I understand correctly the dynamic linked UTF implementation of Boost (since at least 1.54 / 55) then the framework provides a singleton test case dispatcher. Each test will be automatically registered with the construction manager.

I think the problem is that for some reason the Ubuntu linking "optimizes" the static global used for the singleton manager instance when linking the library to the binary. Basically, it does not bind two singleton instances, despite using the same global static variable. He views them as two separate instances.

I followed the steps outlined in Multiple Singleton Instances in Shared Libraries on Linux to check out the library and binaries. Unlike my case, the -rdynamic parameter does not solve my problem.

I did some more tests and found it interesting. If you preload the libcase.so object, unittest works on Ubuntu. Although libcase.so doesn't show up in ldd. I feel like this was expected because the singleton for the manager was "preloaded", when unittest runs it will bind to it.

$ LD_PRELOAD=/absolute/path/to/libcase.so ./unittest
Running 1 test case ...

      

Still not sure why Ubuntu doesn't want to bundle as expected / intended where Fedora is doing. Reading this tutorial (specifically the Comparison to Microsoft DLL section) makes me think Ubuntu follows the Windows binding pattern.

+3


source to share


2 answers


Got it!

Ubuntu seems to use the --as-needed

default linker option where Fedora might not work. If you disable it, add the libcase.so library to the desired list for unittest. After deploying the library (or using LD_LIBRARY_PATH) the unittest works now.



unittest: libcase.so
        g++ -o unittest test_main.cpp -Wl,--no-as-needed -L. -lcase -lboost_unit_test_framework

      

The numbers were something simple ...

+6


source


The problem is that it is lib_case.o

optimized because there are no references to anything in there.

If all references refer to the test case definition in the unittest framework (for self-registration), but do not return, compile and link the main test axes to the "unused" library.

I could reproduce this on my system (Ubuntu 14). Here's a simple hack to show how you could fix this by forcing a reference (in this case, a global variable called force_reference_this_object_file

.

Notes

  • Of course, you usually declare that global in your header file
  • you find that you either need to expand libcase.so

    or use LD_LIBRARY_PATH to include ./

    in the library path

lib_case.cpp



#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>

int force_reference_this_object_file = 42;

BOOST_AUTO_TEST_SUITE( test_lib )

BOOST_AUTO_TEST_CASE( test_lib_case ) {
    BOOST_ASSERT(true);
}
BOOST_AUTO_TEST_SUITE_END()

      

test_main.cpp

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN

#include <boost/test/unit_test.hpp>

extern int force_reference_this_object_file;

namespace {
    struct Local
    {
        int& ref_;
        Local() : ref_(force_reference_this_object_file) {}
    };

    static Local hack_;
}

      

Makefile

all: unittest unittest3

CPPFLAGS=-Wall -fPIC
LDFLAGS+=-L ~/WORK/pocpp/3rdparty/boost_1_58_0/stage/lib/

%.o: %.cpp
    g++ -c $(CPPFLAGS) $^ -o $@

libcase.so: lib_case.o
    g++ $(CPPFLAGS) -shared -Wl,-soname,$@ -o $@ $^

unittest: test_main.o | libcase.so
    #g++ $(CPPFLAGS) -o $@ $< $(LDFLAGS) -L. -lcase -lboost_unit_test_framework
    g++ $(CPPFLAGS) -o $@ $< $(LDFLAGS) ./libcase.so -lboost_unit_test_framework

unittest3: test_main.o lib_case.o
    g++ $(CPPFLAGS) -o $@ $^ $(LDFLAGS) -lboost_unit_test_framework

      

0


source







All Articles