Using Crypto++ static library in a QT project - c++

I have built cryptopp statically on my system it passes all tests too. These are the warning though I get during tests
WARNING: CRYPTOPP_NO_UNALIGNED_DATA_ACCESS is not defined in config.h.
WARNING: CRYPTOPP_INIT_PRIORITY is not defined in config.h.
WARNING: CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562 is defined in config.h.
WARNING: You should make these changes in config.h, and not CXXFLAGS.
WARNING: You can 'mv config.recommend config.h', but it breaks versioning.
WARNING: See http://cryptopp.com/wiki/config.h for more details.
I now link this in my QT project file as
TEMPLATE = app
LIBS += -L/usr/lib/libcryptopp.a
#LIBS += -lcryptopp
CONFIG += console c++11
CONFIG += staticlib
SOURCES += main.cpp \
hashdata.cpp
HEADERS += \
hashdata.hpp
But when I compile this I get all undefined errors.
hashdata.o: In function `hashdata::hashfunction(std::string)':
hashdata.cpp:(.text+0x1fb): undefined reference to `CryptoPP::Algorithm::Algorithm(bool)'
hashdata.cpp:(.text+0x270): undefined reference to `CryptoPP::SHA512::InitState(unsigned long long*)'
hashdata.cpp:(.text+0x29a): undefined reference to `CryptoPP::Algorithm::Algorithm(bool)'
hashdata.cpp:(.text+0x2a1): undefined reference to `vtable for CryptoPP::StringSinkTemplate<std::string>'
hashdata.cpp:(.text+0x30b): undefined reference to `CryptoPP::Filter::Filter(CryptoPP::BufferedTransformation*)'
hashdata.cpp:(.text+0x312): undefined reference to `vtable for CryptoPP::Grouper'
hashdata.cpp:(.text+0x35e): undefined reference to `CryptoPP::Filter::Detach(CryptoPP::BufferedTransformation*)'
hashdata.cpp:(.text+0x375): undefined reference to `CryptoPP::Filter::Filter(CryptoPP::BufferedTransformation*)'
hashdata.cpp:(.text+0x37c): undefined reference to `vtable for CryptoPP::BaseN_Encoder'
hashdata.cpp:(.text+0x3d3): undefined reference to `CryptoPP::Filter::Detach(CryptoPP::BufferedTransformation*)'
hashdata.cpp:(.text+0x3e5): undefined reference to `CryptoPP::ProxyFilter::ProxyFilter(CryptoPP::BufferedTransformation*, unsigned long, unsigned long, CryptoPP::BufferedTransformation*)'
hashdata.cpp:(.text+0x3ec): undefined reference to `vtable for CryptoPP::HexEncoder'
hashdata.cpp:(.text+0x452): undefined reference to `vtable for CryptoPP::AlgorithmParametersTemplate<int>'
hashdata.cpp:(.text+0x4af): undefined reference to `vtable for CryptoPP::AlgorithmParametersTemplate<CryptoPP::ConstByteArrayParameter>'
...
I have seen a similar problem previously when I searched in google, but the solution isn't clear. Could it be because of C++11 flags ?

I have built cryptopp statically on my system it passes all tests too.
These are the warning though I get during tests
WARNING: CRYPTOPP_NO_UNALIGNED_DATA_ACCESS is not defined in config.h.
WARNING: CRYPTOPP_INIT_PRIORITY is not defined in config.h. WARNING:
CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562 is defined in config.h.
WARNING: You should make these changes in config.h, and not CXXFLAGS.
WARNING: You can 'mv config.recommend config.h', but it breaks
versioning. WARNING: See http://cryptopp.com/wiki/config.h for more
details.
I can comment on this warning. You should perform the steps it says:
mv config.recommend config.h
config.recommend puts the library is a better configuration by completely avoiding known undefined behavior that could not be removed without breaking versioning. Since you don't appear to have versioning issues (like say, Fedora or Debian), then you can perform the move.
I now link this in my QT project file as
TEMPLATE = app
LIBS += -L/usr/lib/libcryptopp.a
#LIBS += -lcryptopp
CONFIG += console c++11
...
When you build Crypto++, you should use the same compiler and flags for the library and app. I suggest the following.
Crypto++:
# Be sure to 'mv config.recommend config.h'
export CXXFAGS="-DNDEBUG -g2 -O3 -std=c++11"
make static dynamic test
Qt App
# main.pro file
QMAKE_CXXFLAGS += -DNDEBUG -g2 -O3
Also see GNUmakefile | Building the Library on the Crypto++ wiki.
hashdata.o: In function `hashdata::hashfunction(std::string)':
hashdata.cpp:(.text+0x1fb): undefined reference to `CryptoPP::Algorithm::Algorithm(bool)'
hashdata.cpp:(.text+0x270): undefined reference to `CryptoPP::SHA512::InitState(unsigned long long*)'
...
These are coming from source (*.cpp) files. I'm guessing (and its purely a guess) one of two problems:
C++03 vs C++11 is causing missing symbols
QT Creator is not using libcryptopp.a
Use nm to inspect the symbols. Something like the following (the ' T " tells you its defined and in the text section):
$ nm libcryptopp.a 2>/dev/null | c++filt | \
grep 'Algorithm::Algorithm(bool)' | grep ' T '
0000000000000060 T CryptoPP::Algorithm::Algorithm(bool)
0000000000000070 T CryptoPP::Algorithm::Algorithm(bool)
If the symbols are present by QT Creator is not finding the Crypto++ library, then see something like Adding external library into Qt Creator project.
From Comments:
-lcryptopp works, but I don't know why -L/usr/lib/libcryptopp.a doesn't. ... Because if a person had both static and dynamic libraries, I still don't know how to force linking static ones.
An archive, like libcryptopp.a, is a collection of object files. You add it to OBJECTS, not LIBS, so you want something like:
# main.pro file
OBJECTS += /usr/lib/libcryptopp.a
You use -L to specify a library path to a linker. It does not make much sense to -L/usr/lib/libcryptopp.a since its used for paths.
Additional note is that when both the static and dynamic libs were present it was automatically linking the dynamic lib. Do you know how to force static linking ?
On Linux, you can force static linking by either (1) -Bstatic -lcryptopp; or (2) directly specifying /usr/lib/libcryptopp.a. The Crypto++ test program uses method (2):
g++ main.cpp /usr/lib/libcryptopp.a -o main.exe
On OS X, the linker always links to the dynamic object. It even does so on iOS, where userland is usually not allowed to load dynamic objects. To avoid dynamic linking, either (1) move or rename the *.dylib; or (2) directly specifying /usr/lib/libcryptopp.a. The Crypto++ test program uses method (2):
g++ main.cpp /usr/lib/libcryptopp.a -o main.exe

Related

Can't link against static library with Mingw on Linux

I have installed the GMP library and try to cross-compile with mingw-w64-posix.
My Library is in /usr/local/lib.
My compile command looks like the following:
x86_64-w64-mingw32-g++-posix src/factorial.cpp -o bin/factorial.win.o -I/usr/local/include -L/usr/local/lib -lgmp -lgmpxx
It throws an undefined reference error:
(I can remove the whole block from -L...., same error. Seems like the library doesnt link for some reason)
/usr/bin/x86_64-w64-mingw32-ld: /tmp/ccxY03WS.o:factorial.cpp:(.text$_ZN23__gmp_binary_multiplies4evalEP12__mpz_structPKS0_S3_[_ZN23__gmp_binary_multiplies4evalEP12__mpz_structPKS0_S3_]+0x27): undefined reference to `__gmpz_mul'
/usr/bin/x86_64-w64-mingw32-ld: /tmp/ccxY03WS.o:factorial.cpp:(.text$_ZN23__gmp_binary_multiplies4evalEP12__mpz_structPKS0_l[_ZN23__gmp_binary_multiplies4evalEP12__mpz_structPKS0_l]+0x26): undefined reference to `__gmpz_mul_si'
/usr/bin/x86_64-w64-mingw32-ld: /tmp/ccxY03WS.o:factorial.cpp:(.text$_ZN10__gmp_exprIA1_12__mpz_structS1_E7init_siEl[_ZN10__gmp_exprIA1_12__mpz_structS1_E7init_siEl]+0x1a): undefined reference to `__gmpz_init_set_si'
/usr/bin/x86_64-w64-mingw32-ld: /tmp/ccxY03WS.o:factorial.cpp:(.text$_ZN10__gmp_exprIA1_12__mpz_structS1_EC1EOS2_[_ZN10__gmp_exprIA1_12__mpz_structS1_EC1EOS2_]+0x2e): undefined reference to `__gmpz_init'
/usr/bin/x86_64-w64-mingw32-ld: /tmp/ccxY03WS.o:factorial.cpp:(.text$_ZN10__gmp_exprIA1_12__mpz_structS1_ED1Ev[_ZN10__gmp_exprIA1_12__mpz_structS1_ED1Ev]+0x14): undefined reference to `__gmpz_clear'
collect2: error: ld returned 1 exit status
However if i change my compiler to g++ instead everything works fine.
OK -
The link errors (__gmpz_init, __gmpz_clear, etc.) are GMP "internals". They're supposed to come from libgmp, the C-language base library.
The code that's referencing them (.text$ZN23__gmp_binary_multiplies4evalEP12__mpz_structPKS0_S3[ZN23__gmp_binary_multiplies4evalEP12__mpz_structPKS0_S3], etc.) is "name mangled" C++.
I suspect the problem is that your "gmpxx" library was built with a different C++ compiler, that has a different "name mangling" convention than MinGW.
SOLUTION:
Download the complete libGMP source (e.g. from https://gmplib.org/, and rebuild EVERYTHING (including libgmpxx) with your libmingw-w64-posix++ C++ cross-compiler.
ADDENDUM:
I downloaded gmp-6.2.1 source, and found __gmpz_clear here:
gmp-6.2.1\gmp-h.in
#define mpz_clear __gmpz_clear
__GMP_DECLSPEC void mpz_clear (mpz_ptr);
"gmp-h.in" is a template used by the project's "autoconf", to generate the libGMP source files for the specified target environment.
Which, in turn, means:
The project you started out with (in your original question) wasn't configured for MinGW
... and ...
You didn't run "configure" correctly when you tried building from source.
SUGGESTION:
Try building libGMP from source again. DELETE everything, re-extract from the libGMP tarball, and carefully follow the INSTALL instructions:
./configure
make
make check <= VERY IMPORTANT!!
make install
I'm curious about your build environment (Windows? Linux?), compiler (exact MinGW version) and target (if you're building on a Windows workstation, do you want to run your GMP app as a Windows .exe)?

Difference between -static -lxyz and -l:libxyz.a

Sory my english is bad.
I'm using visual code, my project is c++, -L./libs/curl/lib include only libcurl.a, that is static lib
When I build project with this link option, everything is ok:
LDFLAGS = -static -L./libs/curl/lib -lcurl -lssl -lcrypto -lsqlite3 -lpthread -ldl -lz
But when I use this link option:
LDFLAGS = -L./libs/curl/lib -l:libcurl.a -l:libssl.a -l:libcrypto.a -l:libsqlite3.a -l:libpthread.a -l:libdl.a -l:libz.a
I got this error:
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libpthread.a(pthread_create.o): In function `allocate_stack':
/build/glibc-2ORdQG/glibc-2.27/nptl/allocatestack.c:526: undefined reference to `_dl_stack_flags'
/build/glibc-2ORdQG/glibc-2.27/nptl/allocatestack.c:652: undefined reference to `_dl_stack_flags'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libpthread.a(elision-lock.o): In function `do_set_elision_enable':
/build/glibc-2ORdQG/glibc-2.27/nptl/../sysdeps/unix/sysv/linux/x86/elision-conf.c:67: undefined reference to `_dl_x86_cpu_features'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libpthread.a(nptl-init.o): In function `__pthread_initialize_minimal_internal':
/build/glibc-2ORdQG/glibc-2.27/nptl/nptl-init.c:294: undefined reference to `_dl_cpuclock_offset'
/build/glibc-2ORdQG/glibc-2.27/nptl/nptl-init.c:429: undefined reference to `_dl_pagesize'
/build/glibc-2ORdQG/glibc-2.27/nptl/nptl-init.c:438: undefined reference to `_dl_pagesize'
/build/glibc-2ORdQG/glibc-2.27/nptl/nptl-init.c:454: undefined reference to `_dl_init_static_tls'
/build/glibc-2ORdQG/glibc-2.27/nptl/nptl-init.c:456: undefined reference to `_dl_wait_lookup_done'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libpthread.a(nptl-init.o): In function `__pthread_get_minstack':
/build/glibc-2ORdQG/glibc-2.27/nptl/nptl-init.c:475: undefined reference to `_dl_pagesize'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libdl.a(dlopen.o): In function `dlopen':
(.text+0x5): undefined reference to `__dlopen'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libdl.a(dlclose.o): In function `dlclose':
(.text+0x1): undefined reference to `__dlclose'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libdl.a(dlsym.o): In function `dlsym':
(.text+0x5): undefined reference to `__dlsym'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libdl.a(dlerror.o): In function `dlerror':
(.text+0x1): undefined reference to `__dlerror'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libdl.a(dladdr.o): In function `dladdr':
(.text+0x1): undefined reference to `__dladdr'
So my question is:
What difference between -static -lxyz and -l:libxyz.a link option?
does -static have implicit links to add other libs?
By default gcc or g++ will link against some standard libraries. The list of these libraries is architecture dependent, but you find libc libgcc and some others. To see the list of libraries used for the link you can add -v option. You will see the list of libraries passed to collect2. Since you are compiling for x86_64 the list will be probably (libc, libgcc and libgcc_s).
When you use the static option, you force the linker to use the static version of all the libraries, those you give with -l option and the default ones.
In the second case you give the linker the static version of your libraries, but for the other libraries it is the shared version that will be taken. If both static and shared libraries are found, the linker gives preference to linking with the shared library unless the -static option is used. from https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options.
A last thing. The crt files are also different if you use static option. You can see it also with -v option.
In case you want to control exactly which library should be used there is the option nostdlib. when using this option, The compiler Do not use the standard system startup files or libraries when linking. No startup files and only the libraries you specify are passed to the linker, and options specifying linkage of the system libraries, such as -static-libgcc or -shared-libgcc, are ignored.

"Undefined reference to dlopen" when statically linking with gcc

After reading up lots of gcc docomentation and similar questions my problem remains.
Im trying to statically link my libluajit.a into my project but no matter what combination of commands I try, one or another error pops up. Ive successfully compiled my project with dynamic linking though.
Right now Im out of ideas so heres what i got right now:
gcc_options = -std=c++11 -static -pthread
src_dir = LuaHost
src_files = $(src_dir)/*.cpp
src_files += $(src_dir)/*.h
src_files += $(src_dir)/LuaSrc/*.h
src_files += $(src_dir)/LuaSrc/*.hpp
lib_cmd = -Wl,--no-as-needed -ldl -L./$(src_dir)/LuaSrc/ -lluajit
#compile everything and output an executeable
all:
g++ $(gcc_options) $(src_files) $(lib_cmd) -o LuaJITSandbox.o
And heres some of the errors:
./LuaHost/LuaSrc/libluajit.a(lj_clib.o): In function `lj_clib_index':
lj_clib.c:(.text+0x1c0): undefined reference to `dlsym'
./LuaHost/LuaSrc/libluajit.a(lj_clib.o): In function `lj_clib_load':
lj_clib.c:(.text+0x2c8): undefined reference to `dlopen'
lj_clib.c:(.text+0x350): undefined reference to `dlerror'
lj_clib.c:(.text+0x424): undefined reference to `dlopen'
The libluajit.a has been compiled on the same machine, a RaspberryPi.
I think -static is not what you are after. -static will build a static application and does not mean link this static library to the application.
There are a few options here. When you link with -lluajit you could remove the the dynamic .so version of the library. gcc will default to dynamic linking, but will fallback to static linking when the dynamic library is not available or not found.
Instead of -lluajit you could just point to the static library file directly - treating it as an object input file: /usr/lib/libluajit.a.
I think the recommend way is to tell the linker how to link you library. Try using -Wl,-Bstatic -lluajit. You can switch between Bstaticand Bdynamic right in front of the library name in case you link to multiple libraries and want to link them differently.

Libquantum code Understanding Makefile

I tried to run .c file called grover.c in this C application libquantum
www.libquantum.de/files/libquantum-1.1.1.tar.gz
Now I this application already contains a Makefile.in and I can generate the executables called shor and grover using the command
./configure
make
make demos
But when I try to run grover.c using gcc or clan like this
clang grover.c
It gives me error of lots of undefined function reference.
In function oracle':
grover.c:(.text+0x50): undefined reference toquantum_sigma_x'
grover.c:(.text+0x89): undefined reference to quantum_toffoli'
grover.c:(.text+0xc8): undefined reference toquantum_toffoli'
grover.c:(.text+0xf2): undefined reference to quantum_cnot'
grover.c:(.text+0x137): undefined reference toquantum_toffoli'
grover.c:(.text+0x16b): undefined reference to quantum_toffoli'
grover.c:(.text+0x1b0): undefined reference toquantum_sigma_x'
I need to know how can I remove this error and if I can run this c code called grover.c in this application.
Thanks,
It looks like your compiler can not find one or more libraries to link to. My hunch is that the makefile has the appropriate commands to invoke the linker.
If you look at your makefile, you probably will see some commands like -L -l,
when the flag -L add a directory to the default search path for libraries and the flag -l is used to name the library to link.
for example -L/lib/openGL -lglut32 would cause the library libglut32.so.X.Y.Z which is found in the directory /lib/openGL. (not this is for a Linux system, but it should be fairly similar for Mac).
N.B. X.Y.Z are the version number of the library.
Once you work this out, there may be issues with the load finding the libraries, especially if they are in non-standard locations.
------------------------ edit --------------------------
After I posted this, and went to bed I realized that I missed a potential case (and thanks to Paul Griffiths for also noticing my omission.....teach me to do multiple things at once).
Any how, just compiling a simple file, say hello.c, as clang hello.c -o hello works because everything is in one file and clang will automatically link to the C run-time library.
If, in your case the code is spread across multiple files, say grover.c and file1.c you would need to do:
clang -c grover.c -o grover.o
clang -c file1.c -o file1.o
clang grover.o file1.o -o grover
(or alteratively clang grover.c file1.c -o grover)
SO what the first two lines are doing is translating the source-code files (grover.c and file1.c) into object files. THe third line covers the two object files into an executable.
Finally, both these cases can be involved. You could have multiple files as well as missing libraries.

boost test - 'undefined reference' errors

I have two simple files:
runner.cpp:
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Main
#include <boost/test/unit_test.hpp>
and test1.cpp:
#define BOOST_TEST_DYN_LINK
#ifdef STAND_ALONE
# define BOOST_TEST_MODULE Main
#endif
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE( Foo)
BOOST_AUTO_TEST_CASE( TestSomething )
{
BOOST_CHECK( true );
}
BOOST_AUTO_TEST_SUITE_END()
To compile, I'm using:
$ g++ -I/e/code/boost_1_52_0 -o runner -lboost_unit_test_framework runner.cpp test1.cpp
I get the following error:
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text+0x8c): multiple definition of `main'
c:/pdev/mingw/bin/../lib/gcc/i686-pc-mingw32/4.7.2/../../../libboost_unit_test_framework.a(unit_test_main.o):unit_test_main.cpp:(.text.startup+0x0): first defined here
c:/pdev/mingw/bin/../lib/gcc/i686-pc-mingw32/4.7.2/../../../libboost_unit_test_framework.a(unit_test_main.o):unit_test_main.cpp:(.text.startup+0x14): undefined reference to `init_unit_test_suite(int, char**)'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text+0x52): undefined reference to `_imp___ZN5boost9unit_test9framework17master_test_suiteEv'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text+0xb0): undefined reference to `_imp___ZN5boost9unit_test14unit_test_mainEPFbvEiPPc'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text$_ZN5boost9unit_test13test_observerD2Ev[__ZN5boost9unit_test13test_observerD2Ev]+0xe): undefined reference to `_imp___ZTVN5boost9unit_test13test_observerE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text$_ZN5boost9unit_test13test_observerC2Ev[__ZN5boost9unit_test13test_observerC2Ev]+0xe): undefined reference to `_imp___ZTVN5boost9unit_test13test_observerE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text$_ZN5boost9unit_test15unit_test_log_tC1Ev[__ZN5boost9unit_test15unit_test_log_tC1Ev]+0x22): undefined reference to `_imp___ZTVN5boost9unit_test15unit_test_log_tE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x88): undefined reference to `_imp___ZN5boost9unit_test15unit_test_log_t14set_checkpointENS0_13basic_cstringIKcEEjS4_'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x136): undefined reference to `_imp___ZN5boost10test_tools9tt_detail10check_implERKNS0_16predicate_resultERKNS_9unit_test12lazy_ostreamENS5_13basic_cstringIKcEEjNS1_10tool_levelENS1_10check_typeEjz'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x21d): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24auto_test_unit_registrarC1ENS0_13basic_cstringIKcEE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x284): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24auto_test_unit_registrarC1EPNS0_9test_caseEm'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x2a4): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24auto_test_unit_registrarC1Ei'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text$_ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE[__ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE]+0x1d): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24normalize_test_case_nameENS0_13basic_cstringIKcEE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text$_ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE[__ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE]+0x5b): undefined reference to `_imp___ZN5boost9unit_test9test_caseC1ENS0_13basic_cstringIKcEERKNS0_9callback0INS0_9ut_detail6unusedEEE'
collect2.exe: error: ld returned 1 exit status
I'm using g++ 4.7.2 on MinGW, with boost 1.52.0.
I get the same errors when only trying to compile test1.cpp - except the "multiple main definition" one.
I perused the official documentation for quite a while, but its scarce on details regarding linking options. When I compiled the boost libs, besides unit_test_framework, I also got prg_exec_monitor and test_exec_monitor; perhaps I should link these somehow ? I tried many combinations, but all resulted in some kind of undefined reference linker error.
Complete list of boost generated libraries - I have them all in the project root:
libboost_prg_exec_monitor-mgw47-mt-1_52.a
libboost_prg_exec_monitor-mgw47-mt-1_52.dll
libboost_prg_exec_monitor-mgw47-mt-1_52.dll.a
libboost_prg_exec_monitor-mgw47-mt-d-1_52.a
libboost_prg_exec_monitor-mgw47-mt-d-1_52.dll
libboost_prg_exec_monitor-mgw47-mt-d-1_52.dll.a
libboost_test_exec_monitor-mgw47-mt-1_52.a
libboost_test_exec_monitor-mgw47-mt-d-1_52.a
libboost_unit_test_framework-mgw47-mt-1_52.a
libboost_unit_test_framework-mgw47-mt-1_52.dll
libboost_unit_test_framework-mgw47-mt-1_52.dll.a
libboost_unit_test_framework-mgw47-mt-d-1_52.a
libboost_unit_test_framework-mgw47-mt-d-1_52.dll
libboost_unit_test_framework-mgw47-mt-d-1_52.dll.a
With help from #llonesmiz, a number of issues were identified.
1. Libraries need to be specified after objects and sources which use them.
As described here:
The traditional behavior of linkers is to search for external functions from
left to right in the libraries specified on the command line. This means that a
library containing the definition of a function should appear after any source
files or object files which use it. This includes libraries specified with the
short-cut -l option, as shown in the following command:
$ gcc -Wall calc.c -lm -o calc (correct order)
With some linkers the opposite ordering (placing the -lm option before the file
which uses it) would result in an error,
$ cc -Wall -lm calc.c -o calc (incorrect order)
main.o: In function 'main':
main.o(.text+0xf): undefined reference to 'sqrt'
because there is no library or object file containing sqrt after ‘calc.c’. The
option -lm should appear after the file ‘calc.c’
2. Library paths should be explicitly specified.
If no lib paths are specified, the linker might look for the libs in a series
of default folders, thus loading a different library then intended. This is what
happened in my case - I wanted to link boost_unit_test_framework, but did not
specify a path because I assumed the linker would look in the current folder.
That's what happens at runtime, after all - if the dll is in the same folder
with the exe, it will find it.
I found it a little bit strange the linker would find the lib, since it was
named ibboost_unit_test_framework-mgw47-mt-1_52.dll. When I tried to link to
a non-existing lib, the linker complained though, so I assumed this isn't an
issue, and MinGW 's linker ignores those suffixes.
After some more research, I found this article about MinGW library paths.
The folders MinGW searches for libs can be found in the output of gcc -print-search-dirs.
The article also contains some bash magic to make sense of that output:
gcc -print-search-dirs | sed '/^lib/b 1;d;:1;s,/[^/.][^/]*/\.\./,/,;t 1;s,:[^=]*=,:;,;s,;,; ,g' | tr \; \\012 | grep -v '^ */'
This will print a nice list of those folders. gcc will not, by default,
look in the current directory for libs. I looked in each of them, and found the
lib that was being loaded - libboost_unit_test_framework.a, a static lib.
This brings into light another issue worth mentioning:
3. Static versus dynamic linking
I did not specify whether I want boost_unit_test_framework linked statically or dynamically.
In this case, gcc prefers dynamic linking:
Because of these advantages gcc compiles programs to use shared libraries by
default on most systems, if they are available. Whenever a static library
‘libNAME.a’ would be used for linking with the option -lNAME the compiler
first checks for an alternative shared library with the same name and a ‘.so’
extension.
(so is the extension for dynamic libraries on Unix - on Windows, the equivalent is dll.)
So, what happened is that gcc looked for libboost_unit_test_framework.dll
in all it's default folders, but couldn't find it. Then it looked for
libboost_unit_test_framework.a, and statically linked that. This resulted in
linking errors because the sources have #define BOOST_TEST_DYN_LINK, and
therefore expect to have the lib dynamically linked.
To enforce static or dynamic linking, the -Wl,-Bstatic and -Wl,-Bdynamic
linker options come into play, described here.
If I tell the linker that I want dynamic linking:
$ g++ -I/e/code/boost_1_52_0 runner.cpp test1.cpp -o runner -Wl,Bdynamic -lboost_unit_test_framework
This will fail, because the linker will not be able to find the dll.
4.Summary
The issues were:
libraries where specified before the sources which used them
the lib path wasn't specified
the type of linking wasn't specified
the name of the library was not correct
Final, working command:
$ g++ -I/e/code/boost_1_52_0 -o runner runner.cpp test1.cpp -L. -Wl,-Bdynamic -lboost_unit_test_framework-mgw47-mt-1_52