Boost Test with CMake - undefined main - boost

I'm having trouble building a little program that uses Boost.Test on my Mac with a Boost installed by MacPorts at /opt/local/lib/
Here's my minimal source file, test.cpp:
#define BOOST_TEST_MODULE MyTest
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE(test1) {
}
and my CMakeLists.txt:
cmake_minimum_required(VERSION 2.6)
project (test)
find_package(Boost COMPONENTS unit_test_framework REQUIRED)
add_executable(test test.cpp)
and an excerpt of from make VERBOSE=1:
[100%] Building CXX object CMakeFiles/test.dir/test.cpp.o
g++ -o CMakeFiles/test.dir/test.cpp.o -c /Users/exclipy/Code/cpp/inline_variant/question/test.cpp
Linking CXX executable test
"/Applications/CMake 2.8-5.app/Contents/bin/cmake" -E cmake_link_script CMakeFiles/test.dir/link.txt --verbose=1
g++ -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/test.dir/test.cpp.o-o test
Undefined symbols for architecture x86_64:
"_main", referenced from:
start in crt1.10.6.o
"vtable for boost::unit_test::unit_test_log_t", referenced from:
boost::unit_test::unit_test_log_t::unit_test_log_t() in test.cpp.o
boost::unit_test::unit_test_log_t::~unit_test_log_t() in test.cpp.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
As you can see, it doesn't know how to link to Boost library. So I try adding to CMakeLists.txt:
target_link_libraries(test boost_unit_test_framework)
But I just get:
g++ -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/test.dir/test.cpp.o-o test -lboost_unit_test_framework
ld: library not found for -lboost_unit_test_framework
From lots of trial and error, I've found that manually running this works:
$ g++ test.cpp -L/opt/local/lib -lboost_unit_test_framework -DBOOST_TEST_DYN_LINK
But after hours of fiddling, I can't get it to build from CMake. I don't care whether it links dynamically or statically, I just want it to work.

You need to tell CMake where to find the boost libraries (the -L/opt/local/lib in your g++ line). You can accomplish this by adding the following line (if you had no problem with find_package):
link_directories ( ${Boost_LIBRARY_DIRS} )
before add_executable.
Another alternative is using the single-header variant of the UTF. This variant is really simple (you only need to include <boost/test/included/unit_test.hpp> but it has a major drawback in its considerable increase in build time.

The find_package(Boost COMPONENTS ...) call collects the required link libraries for the searched Boost components (e.g.,unit_test_framework) in the CMake variable Boost_LIBRARIES.
To get rid of the link error, add:
target_link_libraries(test ${Boost_LIBRARIES})

EDIT 2020-02
The details of building a Boost.Test module are on the documentation here and covered with many examples on the documentation. Usually if main is not found, this might be due to:
mixing static and shared library versions of Boost.Test (the linker prefers shared libraries)
improper definitions of the BOOST_TEST_MODULE and/or BOOST_TEST_DYN_LINK macros: depending on those, the Boost.Test framework will define (correctly) a main or not.
Previous (wrong) answer
Well here, the problem is not that cmake does not find the boost_unit_test_framework library, but rather that this specific library does not contain the main entry point for running the binary.
In fact, you should link against ${Boost_TEST_EXEC_MONITOR_LIBRARY} since it contains the proper definitions. You should also avoid defining the macro BOOST_TEST_DYN_LINK.

Related

Why is the dynamic library not selected despite -Wl,-Bdynamic?

I am using 3rd party libraries to build my executable. More specifically I have in ./extern/bin/win64
libfoo.dll
libfoo.dll.a
libbar.dll
Despite its name, it looks like libfoo.dll.a isn't really an import library, but rather an archive (static library). After scratching my head for some time, I came to this conclusion by looking at the output of lib /list libfoo.dll.a (from here) which gives me a bunch of .o files.
The command line I'm using to build my executable is always the same:
g++ -std=c++14 test.cpp -I./extern/include -L./extern/bin/win64 -lbaz -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic -lfoo -lbar -s -o test.exe
My understanding is that the final -Wl,-Bdynamic gives preference to dynamic linkage but doesn't insist on dynamic linkage. The linker should still be happy if only the static version of a library exist, but it should pick the dynamic version when both the static and the dynamic version exist. Correct ?
Now here is the part that puzzles me a little bit. If, in ./extern/bin/win64, I only keep libbar.dll and:
libfoo.dll then the executable has dependencies on libfoo.dll and libbar.dll (expected: dynamic linkage to libfoo is the only option)
libfoo.dll.a then the executable has a dependency on libbar.dll only (expected: static linkage to libfoo is the only option)
Both libfoo.dll and libfoo.dll.a then the executable has a dependency on libbar.dll only (surprising: static linkage seems to have been used but dynamic linkage was supposed to be preferred)
Does anyone have a theory to explain #3 ? Are my expectations incorrect ?
[Edit] As an extension to #3, I have also found that if I separate libfoo.dll and libfoo.dll.a into different folders, then the first folder to appear on the command line following -L determines which version of the library is selected. Again -Wl,-Bdynamic does not seem to have the expected effect....
PS: if anyone wants to have a detailed inspection of the libraries, they're distributed with Matlab, located in extern\bin\win64 as discussed. For completeness, the source code for my example can be found here but is this probably not relevant. Also using gcc 6.3 from here.

undefined reference to `cudaFree' and many other errors when compileing program [duplicate]

I'm attempting to do a release of some software and am currently working through a script for the build process. I'm stuck on something I never thought I would be, statically linking LAPACK on x86_64 linux. During configuration AC_SEARCH_LIB([main],[lapack]) works, but compilation of the lapack units do not work, for example undefiend reference to 'dsyev_' --no lapack/blas routine goes unnoticed.
I've confirmed I have the libraries installed and even compiled them myself with the appropriate options to make them static with the same results.
Here is an example I had used in my first experience with LAPACK a few years ago that works dynamically, but not statically: http://pastebin.com/cMm3wcwF
The two methods I'm using to compile are the following,
gcc -llapack -o eigen eigen.c
gcc -static -llapack -o eigen eigen.c
Your linking order is wrong. Link libraries after the code that requires them, not before. Like this:
gcc -o eigen eigen.c -llapack
gcc -static -o eigen eigen.c -llapack
That should resolve the linkage problems.
To answer the subsequent question why this works, the GNU ld documentation say this:
It makes a difference where in the command you write this option; the
linker searches and processes libraries and object files in the order
they are specified. Thus, foo.o -lz bar.o' searches libraryz' after
file foo.o but before bar.o. If bar.o refers to functions in `z',
those functions may not be loaded.
........
Normally the files found this way are library files—archive files
whose members are object files. The linker handles an archive file by
scanning through it for members which define symbols that have so far
been referenced but not defined. But if the file that is found is an
ordinary object file, it is linked in the usual fashion.
ie. the linker is going to make one pass through a file looking for unresolved symbols, and it follows files in the order you provide them (ie. "left to right"). If you have not yet specified a dependency when a file is read, the linker will not be able to satisfy the dependency. Every object in the link list is parsed only once.
Note also that GNU ld can do reordering in cases where circular dependencies are detected when linking shared libraries or object files. But static libraries are only parsed for unknown symbols once.

Statically linking any library causes libc to fail to be linked against

My system is an older NAS running 2.6.32. I have found that when using -static for any subsequent library, it will also try to statically link any other library that I might need.
When I add the -Wl,-Bdynamic flag first and then explicitly name those libraries using -lc, such as "-Wl,-Bdynamic -lc -lstdc++" then it works. So what happens is that libc and others fail to be statically linked.
The static libc on the system is called /opt/lib/libc_nonshared.a.
The contents of /opt/lib/libc.so is this:
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( /lib/libc.so.6 /opt/lib/libc_nonshared.a )
The gcc version is 4.2.3. The current build command I am facing adds -dynamic at the end but this doesn't help much. When I add some static library directly using its .a name, and not using a -l flag, then there is no issue.
The problem seems to be that the dynamic library of libc came with the NAS, but the static version sits in /opt/lib.
I run:
gcc hamming.c -static -L. -L/opt/lib -l:matrix.a -o hamming
I get:
/opt/lib/gcc/arm-none-linux-gnueabi/4.2.3/../../../../arm-none-linux-gnueabi/bin/ld: cannot find -lc
collect2: ld returned 1 exit status
make: *** [hamming] Error 1
when I try to use static libc as is. Were I to perform a 'hack' to link libc_nonshared.a to libc.a, it suddenly does find it. But complains:
hamming.c:54: undefined reference to `malloc'
hamming.c:54: undefined reference to `memset'
And a zillion other errors of course. As mentioned above, /opt/libc.so contains the reference to both files (dynamic and static).
For libstdc++ only a .la file exists.
The -static linker flag does not take any argument. It is a boolean
flag that simply directs the linker to link no shared libraries, as
documented
-static
Do not link against shared libraries...
There is no need to explicitly direct the linker to link shared (dynamic)
libraries when it has a choice because that is the default bevaiour. If
you simply link, e.g.
gcc -o prog ... -lfoo ...
then the linker will link the first of libfoo.so (shared) or libfoo.a
(static) that it finds in any of the specified (-Ldir) or default
search directories, searched in commandline sequence. If it finds both
libfoo.so and libfoo.a in the same directory then it will choose
libfoo.so. Thus shared and static libraries may be freely intermixed
without any special options.
Specify -static only if you wish to link only static libraries.
If you wish to insist on linking a particular libfoo.a even when
libfoo.so is in the same directory and would be chosen by default,
use the explicit form of the -l option: -l:libfoo.a
Later
gcc hamming.c -static -L. -L/opt/lib -l:matrix.a -o hamming
This command is failing with:
ld: cannot find -lc
because the linker (ld) cannot find a static library libc.a in
any of the specified linker search directories (-L. -L/opt/lib) or
the default linker search directories. If you wish instead to link
/opt/lib/libc_nonshared.a then your command should be:
>gcc hamming.c -static -L. -L/opt/lib -l:matrix.a -lc_nonshared -o hamming
However, you have not explained why you want to link this program statically
(-static) in the first place, which is not the usual way and will require you to have installed
static versions of all libraries required for the linkage - both those
you explicitly link and the default libraries that gcc will add for C language
linkage (Standard C library, GCC runtime library).
Supposing you have a static library called (oddly) matrix.a (rather
than normally, libmatrix.a) that is located in /some/dir/, then the
normal way to compile and link your program would be:
gcc hamming.c -L/some/dir -l:matrix.a -o hamming
I suggest you start with that and deviate only as problems compel
you to.
The discovery of an /opt/lib/libc.so containing:
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( /lib/libc.so.6 /opt/lib/libc_nonshared.a )
is misleading you. This is not your shared libc. A shared library
is a binary. This is a linker script, and it says that your shared libc
is in fact /lib/libc.so.6. The linker will almost certainly find and use it by default.

Why is -L needed when -rpath is used?

I find that the -L flag must be given when using -rpath. For instance:
gcc -o test test.o -L. -lmylib -Wl,-rpath=.
Why is the -L flag needed? What information more than the information from the h-files are needed at compile time?
If I remove -L. I get the following message:
gcc -o test test.o -lmylib -Wl,-rpath=.
/usr/bin/ld: cannot find -lmyLib
It's perfectly ok to remove both flags, though. Like this:
gcc -o test test.o -lmylib
Provided that libmyLib can be found in /usr/lib, that is. Why isn't -L needed now?
This is a follow-up question to https://stackoverflow.com/a/8482308/1091780.
Even dynamic libraries required a degree of static linkage; the linker needs to know what symbols should be supplied by the dynamic library. The key difference is that the dynamic library provides the definition at runtime, whilst with fully static library provides the definition at link time.
For this reason, -L is needed to specify where the file to link against is, just as -l specifies the specific library. The . indicates the current directory.
-rpath comes into play at runtime, when the application tries to load the dynamic library. It informs the program of an additional location to search in when trying to load a dynamic library.
The reason -L/usr/lib doesn't need to be specified is because the linker is looking there by default (as this is a very common place to put libraries).
A clarification of OMGtechy's answer.
If the linker does not check which symbols are provided by a library, it can never tell you if any symbols are missing at compile time. They might be in one of the libraries loaded at run-time. You could never know. There is no connection at compile time between the header files of a library and the .so file.

GCC link order changed?

I am trying to link a C++ module using GCC, essentially like this:
gcc -c hello.c
g++ -c world.cpp
gcc -ohello -lstdc++ hello.o world.o
Note that I use -lstdc++ to link the C++ module in, so that I can use gcc instead of g++. The problem is that I'm getting the error:
undefined reference to `operator new(unsigned long)'
(Assuming that world.cpp contains at least one call to new.)
This error is fixed if I put -lstdc++ at the end of the linker line, like this:
gcc -ohello hello.o world.o -lstdc++
I am aware that this question has been asked many times here, but I have a special requirement. I am not directly calling GCC. I am using a build system for a different programming language (Mercury) which is calling GCC on my behalf, and I can't easily modify the way it calls GCC (though I can specify additional libraries using the LDFLAGS environment variable). So I have two additional requirements:
I cannot use g++ to link (only gcc) -- that is why I am doing the -lstdc++ trick above rather than simply linking with g++).
I don't think that I can control the order of the linker commands -- Mercury will put the .o files on the command-line after any libraries.
I understand the basic reason why the order is important, but what is baffling me is why did this break now? I just updated to Ubuntu 11.10 / GCC 4.6.1. I have been successfully compiling this program for years using precisely the above technique (putting -lstdc++ first). Only now has this error come up. An unrelated program of mine links against OpenGL using -lgl and that too broke when I upgraded and I had to move -lgl to the end of the command-line. I'm probably going to discover that dozens of my programs no longer compile. Why did this change? Is there something wrong with my new system or is that the way it is now? Note that these are ordinary shared libraries, not statically linked.
Is there anything I can do to make GCC go back to the old way, where the order of libraries doesn't matter? Is there any other way I can convince GCC to link libstdc++ properly without moving it after the .o files on the command-line?
If Mercury puts object files after libraries, Mercury is broken. Libraries belong after object files - always. You may sometimes get away with the reverse order, but not reliably. (Static libraries must go after the object files that reference symbols in the static library. Sometimes, a linker will note the symbols defined by a shared library even when none of the symbols are used; sometimes, the linker will only note the shared library symbols if the shared library provides at least one symbol.)

Resources