Boost logo

Boost Users :

Subject: Re: [Boost-users] [Boost.Test] Linker chooses “wrong” main function
From: Adi Shavit (adishavit_at_[hidden])
Date: 2012-08-29 14:43:51


Hi Richard,

Richard <legalize+jeeves <at> mail.xmission.com> writes:
>
> [Please do not mail me a copy of your followup]
>
> boost-users <at> lists.boost.org spake the secret code
> <CAEWUs4gQjT2KxEb90t=u3jRdT352n0KWYnfPpeYk38VwcMEBWA <at> mail.gmail.com>
thusly:
>
> >Since my project did not have a main() function, [...]
>
> Well, obviously your project has a main function, otherwise you would
> get a link error.

Exactly. Imagine my surprise when my app suddenly started running this
particular main()!

>
> What boost.test does is define a main() function depending on how it
> is compiled. In my projects, I have a main.cpp that looks like this:
>
> #define BOOST_TEST_MAIN
> #include <boost/test/unit_test.hpp>
>
> and this provides the canned implementation of main().

I didn't know/use this macro, but my code has BOOST_TEST_MODULE, which
apparently achieves the same thing.

>
> >The linker chose that one
> >as my "test" application. Thus, non of my tests run.
>
> You don't say how you are linking with Boost.Test, but if you are
> linking with a static library then what you need to do is make sure
> Boost.Test is listed in the linker search order before the png
> library.

Actually, I did say that I am using static linking, I guess I was not clear
enough.
As I said, I just recently switched to static linking, and rebuilt.
I didn't actually specify *any *boost libs, as these are (somehow) linked
automatically (on VS2010, probably with some #pragma calls).
Perhaps this gets done *after* the rest of the explicitly stated libs.

When I manually specified

   - *libboost_unit_test_framework-vc100-mt-s-1_51.lib* for Release
   - *libboost_unit_test_framework-vc100-mt-sgd-1_51.lib* for Debug

The appropriate main was found and all the tests ran as expected.

Is there a way to get the correct libs to properly and automatically link
before any other libs?
Is there some MACRO or other way to get the name of the correct libraries
so that I don't need to explicitly state it for each boost version?

>
> However, libpng doesn't include a main():
>
> shell 47> nm .libs/libpng15.a | fgrep -i main
> shell 48> nm .libs/libpng15.so | fgrep -i main
>
> So, wherever you're getting your implementation of main(), doesn't
> come from libpng. If you're on unix, use nm to find out who is
> supplying main. If you're on Windows, use dumpbin to find out who is
> supplying main.

I'm actually using OpenCV which builds/requires libpng as part of it.
Seems like they inadvertently pulled in the test (with *.c) file into the
.lib .
Here's the begining CMakeLists.txt file:

project(${PNG_LIBRARY})
# List of C++ files:
ocv_include_directories("${CMAKE_CURRENT_SOURCE_DIR}" ${ZLIB_INCLUDE_DIR})
file(GLOB lib_srcs *.c)
file(GLOB lib_hdrs *.h)

and, indeed, when running 'dumpbin libpng.lib /symbols | grep -i main' I
get:
 0D2 00000000 SECT29 notype () External | _main

(No surprise)

>
> The key to understanding how to resolve unexpected linker errors is to
> understand that the linker is really not a complicated program and
> only does things in response to the command line arguments given to
> it.
>
> The linker only does two things:
> i) identify unresolved symbols
> ii) resolve unresolved symbols
>
> If you don't supply a definition of a referenced symbol, then i)
> issues an undefined symbol error.
>
> If you violate the one definition rule, then ii) issues a multiply
> defined symbol error. That you *don't* get a multiple undefined
> symbol error, but instead get "the wrong main", tells me that however
> you're linking against Boost.Test you aren't getting a main from it.
>
> When linking against libraries, you need to understand how step ii)
> works:
> The linker examines each supplied link input, in the order supplied,
> and looks for an object defining the desired symbol.
>
> So when the linker looks for a definition of main (which it always
> will when you are linking a final executable and not a library), it
> starts examining the inputs you've given it, one by one, starting at
> the first and proceeding towards the last until it finds a definition.
>
> Since your link succeeded, it found one. Look at the command-line for
> your linker step (the WHOLE command line, not some simplified view of
> it) and use nm/dumpbin to examine the inputs one-by-one until you find
> the one that is supplying main.

Yes, I understand this :-).

Thanks!
Adi

On Tue, Aug 28, 2012 at 9:20 PM, Adi Shavit <adishavit_at_[hidden]> wrote:
>
> Hi,
>
> I have a really strange problem.
>
> When using Boost.Test, there is generally no need to define a main()
> function, since Boost.Test provides one itself.
> I recently had to convert my project to use static linking of 3rd party
> libraries (on VS2010). Naturally, I had to link to multiple .libs so that
> the build succeeds, and my build ran just fine.
>
> However, when I ran my test project, something really strange happened. It
> seems that one of the 3rd party .libs (libpng), required by one of my
> dependent libraries, contained a test file with a main() function defined
> within (pngtest.c).
> Since my project did not have a main() function, The linker chose that one
> as my "test" application. Thus, non of my tests run.
>
> Does anyone know how I prevent this from happening?
> How can I tell the linker/compiler to use the Boost.Test main()?
>
> Thanks,
> Adi
>
>



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