Boost logo

Boost Users :

Subject: Re: [Boost-users] Boost.Test multiple linkage question
From: Richard (legalize+jeeves_at_[hidden])
Date: 2014-09-21 23:39:57


[Please do not mail me a copy of your followup]

Rob Harris <rob.harris_at_[hidden]> spake the secret code
<541B24F9.8050009_at_[hidden]> thusly:

>Can I link _multiple_ boost unit test dynamic libraries into a single
>binary and have all of them detected?

Having all of them detected is the tricky part because "detection"
relies on static constructors registering the test cases.

That means that you need the static constructors in the shared objects
to execute properly w.r.t. the test framework's static constructors.

>For instance...
>
>src
> lib
> liba
> foo.cpp
> liba_unittests.cpp
> libb
> bar.cpp
> libb_unittests.cpp
> libd
> baz.cpp
> libd_unittests.cpp
>lib
> liba.so
> liba_ut.so
> libb.so
> libb_ut.so
> libd.so
> libd_ut.so
>bin
> ut
> unittest_driver
>
>When I build this infrastructure out, everything compiles. I've checked
>the compilation command and it looks like everything is on the command
>line, but there's explicit indication that unittest_driver actually read
>or linked any of the lib*_ut.so files.
>
>If I make individual unit test drivers in, say, liba, the driver works
>fine.
>
>If I link everything into a single unittest_driver binary, I keep
>getting the dreaded empty test tree.

This implies that when you run the test driver, the constructors for
global static objects in your shared objects haven't run and the test
cases haven't been registered.

>Any help (or a definitive, "no you idiot, you can't do that!") would be
>greatly appreciated. Thanks.

I don't think it's a case of "you can't do that", so much as
orchestrating the machinery properly.

For instance, if each shared library had an exported function that
manually registered the test cases/suites in each shared library, and
that exported function were called explicitly from the driver
executable before the tests were run, then everything would probably
work fine. (I haven't tried this.) However, this means writing a bunch
of manual registration code. This code is boring to write and tedious
to maintain.

Otherwise you have to orchestrate the machinery in the right order for
things to work with automatic registration. When all the tests are
compiled into the test executable staticly, this works just fine. The
dynamic linking support was so that you didn't need to relink against
the test framework every time you relinked your test executable.

The simplest thing that's going to get everything right is to leave
production code in the shared objects (liba.so:foo.cpp, libb.so:bar.cpp,
libd.so:baz.cpp) and leave all the test code staticly linked to the
executable (libtesta.a: liba_unittests.cpp, etc.). You can still use
dynamic linking for the unit test framework, but this way all your
test case registration happens properly before main since all the
static constructors will already have run.

-- 
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
     The Computer Graphics Museum <http://computergraphicsmuseum.org>
         The Terminals Wiki <http://terminals.classiccmp.org>
  Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net