Debugging a C++ linker error - c++

First I'll give specific details about the problem I'm having, then I'll go into the interesting results I'm getting from nm when I try to debug the issue. Hopefully an nm guru will be able to interpret those results.
I've statically compiled the Casablanca C++ REST SDK to the library libcpprest.a. That works fine, but when I link against my code using the command:
/usr/bin/c++ CMakeFiles/dcodr_service.dir/dcodr_service.cc.o
CMakeFiles/dcodr_service.dir/viterbi.cc.o CMakeFiles/dcodr_service.dir/utils.cc.o
CMakeFiles/dcodr_service.dir/hmm.cc.o CMakeFiles/dcodr_service.dir/grammar.cc.o
-o dcodr_service -L/home/user/casablanca/Release/Binaries -rdynamic -lfftw3f
-lcpprest -lcommon_utilities -lboost_program_options -lboost_regex -lboost_system
-lboost_filesystem -lboost_iostreams /opt/OpenBLAS/lib/libopenblas.a -Wl,
-rpath,/home/user/casablanca/Release/Binaries
I get the error:
CMakeFiles/dcodr_service.dir/dcodr_service.cc.o: In function
`web::http::http_request::extract_json(bool)
const::{lambda(unsigned long)#1}::operator()(unsigned long) const':
/home/user/casablanca/Release/include/cpprest/http_msg.h:829:
undefined reference to `web::http::details::http_msg_base::_extract_json(bool)'
It appears that _extract_json(bool) is defined in http_msg.cpp, which also appears to be compiled when I look at the verbose output of making libcpprest.a. Now, running nm -e --demangle libcpprest.a I get the following two lines (separated by thousands of others):
00000000000015ee T web::http::details::http_msg_base::_extract_json(bool)
U web::http::details::http_msg_base::_extract_json(bool)
I'm new to using nm, but it appears to me that _extract_json(bool) is both in the code section and in the list of undefined symbols. Is there a better way of interpreting the nm results?
As an aside, when I compile cpprest as a dynamic library and link against it everything works fine, but for various reasons I have to create a static binary of dcodr_service.
EDIT:
Following up on a comment from πάντα ῥεῖ, _extract_json(bool) is used in the following context:
return pplx::create_task(_m_impl->_get_data_available())
.then([impl, force](utility::size64_t) { return impl->_extract_json(force); });
That is, it is used inside a lambda function. Could that cause a linker error?

Related

g++ undefined reference although symbol is present in *.so file

I found a number of similar questions (e.g. this, that or this), but none of them helped me solve my problem. I have a *.so file (from the core of gnss-sdr) that, as indicated by:
$nm libgnss_system_parameters_dyn.so | c++filt |grep Gps_Eph
contains the symbol Gps_Ephemeris::Gps_Ephemeris(), which is supposed to be a constructor.
I've written some minimal code:
#include <iostream>
#include <core/system_parameters/gps_ephemeris.h>
int main(int argc,const char* argv[])
{
Gps_Ephemeris ge;
return 0;
}
which I compile with:
g++ main.cpp -std=c++0x -I some_include_path -L some_lib_path -l gnss_system_parameters_dyn`
The linker then complains:
/tmp/ccHCvldG.o: In function `main':
main.cpp:(.text+0x33): undefined reference to `Gps_Ephemeris::Gps_Ephemeris()'
collect2: error: ld returned 1 exit status
I also tried cmake, but the line it generated was similar to that (it just added -rdynamic before linking), and it still generated the exact same linker error.
Note that both the library and my minimal code are being compiled with the same compiler (g++-5), with the exact same flags and the same c++0x standard.
Addressing the answer by Maxim Egorushkin, the line:
nm --demangle --defined-only --extern-only libgnss_system_parameters.so |grep Gps_Eph
doesn't output anything. However, the symbol is defined in the static library (i.e. the *.a library):
00000000000006b0 T Gps_Ephemeris::Gps_Ephemeris()
00000000000006b0 T Gps_Ephemeris::Gps_Ephemeris()
Knowing that both are generated by cmake, in the following way:
add_library(lib_name SHARED ${sources_etc}) #for the *.so
add_library(lib_name_2 ${sources_etc}) #for the *.a
there should be no difference in symbols contained/defined in those libraries, right? I didn't notice anything in cmake's documentation on add_library. Am I missing something obvious?
The pedantically correct way to check that a .so exports a symbol is nm --demangle --dynamic --defined-only --extern-only <lib.so> | grep <symbol>.
Without --defined-only your command also shows undefined symbols.
Without --extern-only it also shows symbols with internal linkage which are unavailable for linking.
It looks like you need to link another library because Gps_Ephemeris::Gps_Ephermeris() is not resolved by linking libgnss_system_parameters_dyn.so. A good way to start is that library's documentation and examples.
I have found in the past that this type of error is caused by the lack of proper extern "C" { ... } bracketing in an include file.

Compiling program using gfortran and the HDF-EOS2 library

I have the problem of linking the HDF-EOS library to a Fortran90 program. I have compiled the library from source to a directory specified in $prefix. My simple compile command is:
gfortran -I$prefix/include -L$prefix/lib -Wl,-rpath -Wl,$prefix/lib -lhdfeos -lGctp -lmfhdf -ldf -lz -lsz -ljpeg tst.f90
When compiling, I get the following error:
undefined reference to `gdopen_'
In the program, which I am not supposed to change, the HDF-EOS library is used via the external keyword, e.g.
integer(kind=4), external :: gdopen
In the library, nm $prefix/lib/libhdfeos.a | grep gdopen gives me:
00000000000120c0 T gdopen
When compiling with -fno-underscoring, I get just a different error:
gfortran -fno-underscoring -I$prefix/include -L$prefix/lib -Wl,-rpath -Wl,$prefix/lib -lhdfeos -lGctp -lmfhdf -ldf -lz -lsz -ljpeg tst.f90
the error is then:
undefined reference to `gdopen'
Also, gfortran finds the libraries, otherwise it would complain. Is the error related to the underscore? What else can I try? I work on Fedora and gfortran version 4.7.2.
Yes, very likely to be caused by the underscore.
Try compiling with -fno-underscoring (https://gcc.gnu.org/onlinedocs/gfortran/Code-Gen-Options.html), but fixing it by a proper bind(C) interface would be better.
This tutorial (Did you read it before going here? Very easy to find even for a complete novice in the library, like me.) also states you should use -fno-underscoring.
Continue by implementing the rest what the tutorial recommends, including compiling with FC=$(HDF4_DIR)/bin/h4fc.

Position of compiler flag -l

I'm currently learning OpenCL. Now, when I want to compile my program, I get an error with this command:
g++ -Wall -l OpenCL main.cpp -o main
The errors are mostly undefined references, because the library is not linked, I think (nevertheless I will post the error code at the end).
But with this command everything works fine:
g++ -Wall main.cpp -o main -l OpenCL
So my question is, what do I have to do, to use the -l Flag in front of the command?
(The Background is: I want to use Netbeans to compile my programm and when i add the flag under -> properties -> build -> C++ Compiler -> additional options, it will put in in the Position, shown in the first command)
Thanks in advance for your help
Here's the error code:
/tmp/ccmKP4oI.o: In function `cl::detail::ReferenceHandler<_cl_context*>::release(_cl_context*)':
main.cpp:(.text._ZN2cl6detail16ReferenceHandlerIP11_cl_contextE7releaseES3_[_ZN2cl6detail16ReferenceHandlerIP11_cl_contextE7releaseES3_]+0x14): undefined reference to `clReleaseContext'
/tmp/ccmKP4oI.o: In function `cl::detail::ReferenceHandler<_cl_command_queue*>::release(_cl_command_queue*)':
main.cpp:(.text._ZN2cl6detail16ReferenceHandlerIP17_cl_command_queueE7releaseES3_[_ZN2cl6detail16ReferenceHandlerIP17_cl_command_queueE7releaseES3_]+0x14): undefined reference to `clReleaseCommandQueue'
/tmp/ccmKP4oI.o: In function `cl::Platform::getInfo(unsigned int, std::string*) const':
main.cpp:(.text._ZNK2cl8Platform7getInfoEjPSs[_ZNK2cl8Platform7getInfoEjPSs]+0x22): undefined reference to `clGetPlatformInfo'
/tmp/ccmKP4oI.o: In function `cl::Platform::get(std::vector<cl::Platform, std::allocator<cl::Platform> >*)':
main.cpp:(.text._ZN2cl8Platform3getEPSt6vectorIS0_SaIS0_EE[_ZN2cl8Platform3getEPSt6vectorIS0_SaIS0_EE]+0x41): undefined reference to `clGetPlatformIDs'
main.cpp:(.text._ZN2cl8Platform3getEPSt6vectorIS0_SaIS0_EE[_ZN2cl8Platform3getEPSt6vectorIS0_SaIS0_EE]+0xb4): undefined reference to `clGetPlatformIDs'
collect2: error: ld returned 1 exit status
Order of [most] arguments to g++ is very important.
Libraries should go last (at least after source and object files). You can't really change that.
The -l should preferably be glued to the library name:
g++ -Wall main.cpp -o main -lOpenCL
# ^^^ glue the -l to the library name
You probably want to also pass -g (in addition of -Wall) to the compiler to get a debuggable binary. Use the gdb debugger.
As James Kanze commented, you might want to replace -g with -ggdb if using specifically gdb.
With g++ (and generally under Unix), -l specifies a source of
input (either a .a or a .so), and input is processed in
order. When the input is a static library (a .a file), it
will be scanned for objects which resolve undefined references;
if it is a .so, there aren't any object files in it, but it
will still only be taken into consideration if it resolves some
undefined symbol.
When you put the -l before any object files, there are no
undefined symbols yet, so nothing will be incorporated into the
program.

V8 "Hello World" Example - Compiling on Ubuntu 13.10 - tons of undefined reference errors "icu_46"

I am trying to follow the basic "hello world" example for Google's V8 as found here. I'm on Ubuntu 13.10, gcc version 4.8.1; this should be straighforward, no?
After building v8 itself and creating the hello world .cpp file,
I run (exactly** as Google suggests)
** Update: Okay, per my comments on the accepted answer below, I unwittingly wasn't running it exactly as Google suggests, because I thought the braces in the file name were an instruction to the reader to choose one option, not a
syntax that g++ would understand. Nontheless, it still doesn't work except with the additions suggested in the answer below
g++ -Iinclude helloworld.cpp -o hello_world out/x64.debug/obj.target/tools/gyp/libv8_base.x64.a -lpthread
And get bombarded with compile errors. There are too many to print here, but nearly all the errors are of the form:
undefined reference to 'icu_46 ...'
for example (some sample lines)
/home/ray/Playground/v8/out/../src/i18n.cc:138: undefined reference to `icu_46::UnicodeString::~UnicodeString()'
/home/ray/Playground/v8/out/../src/i18n.cc:125: undefined reference to `icu_46::UnicodeString::~UnicodeString()'
/home/ray/Playground/v8/out/../src/i18n.cc:147: undefined reference to `icu_46::UnicodeString::~UnicodeString()'
After much Googling I can figure out this has something to do with something called ICU (see http://userguide.icu-project.org/howtouseicu) but why I'm getting the error, and what I can do about it, I don't know.
While the majority of errors are icu_46 related, there are some like this as well, from the 'bootstrapper.o':
/home/ray/Playground/v8/out/x64.debug/obj.target/v8_base.x64/src/bootstrapper.o: In function `v8::internal::Bootstrapper::NativesSourceLookup(int)':
/home/ray/Playground/v8/out/../src/bootstrapper.cc:77: undefined reference to `v8::internal::NativesCollection<(v8::internal::NativeType)0>::GetBuiltinsCount()'
/home/ray/Playground/v8/out/../src/bootstrapper.cc:81: undefined reference to `v8::internal::NativesCollection<(v8::internal::NativeType)0>::GetRawScriptSource(int)'
/home/ray/Playground/v8/out/x64.debug/obj.target/v8_base.x64/src/bootstrapper.o: In function `v8::internal::Genesis::CompileBuiltin(v8::internal::Isolate*, int)':
/home/ray/Playground/v8/out/../src/bootstrapper.cc:1448: undefined reference to `v8::internal::NativesCollection<(v8::internal::NativeType)0>::GetScriptName(int)'
I'm Googled endlessly on this and have found signs that other people have run into the issue but no solutions. Any help will be hugely appreciated. Thank you.
I had the same problem on Ubuntu 12.04, g++ 4.6.3 and v8 3.22.18.
To compile hello_world.cc successfully it is necessary to add icu .a libraries and link to rt library too. As you have built v8 with make x64.debug your completed command should be:
g++ -Wall -Iinclude -o hello_world hello_world.cc ./out/x64.debug/obj.target/tools/gyp/libv8_{base.x64,snapshot}.a ./out/x64.debug/obj.target/third_party/icu/libicu{i18n,uc,data}.a -lrt

Undefined Reference Error When Linking to Static Library

I am trying to compile a project that depends on the Xerces XML Parser. The project compiles for Windows without any difficulty, but I'm having some trouble compiling it with g++ in Cygwin.
In order to use Xerces, I am trying to compile my code against the static library libxerces-c.a. But when I do so, I get errors that look like this:
/tmp/cc2QGvMh.o:test.cpp:(.text+0x3a): undefined reference to `xercesc_2_8::DOMImplementationRegistry::getDOMImplementation(unsigned short const*)'
I've inspected the static library using ar, and confirmed that it contains the DOMImplementationRegistry.o file that defines the function that I am calling.
ar -t libxerces-c.a
...
DOMImplementationImpl.o
DOMImplementationRegistry.o
DOMLocatorImpl.o
...
I've also extracted the object files from the library, and used 'nm' to make sure that the function I am calling actually exists:
ar -x libxerces-c.a
nm --demangle DOMImplementationRegistry.o
...
00000080 T xercesc_2_8::getDOMImplSrcVectorMutex()
00000300 T xercesc_2_8::DOMImplementationRegistry::getDOMImplementation(unsigned short const*)
000002a0 T xercesc_2_8::DOMImplementationRegistry::addSource(xercesc_2_8::DOMImplementationSource*)
...
Since I can compile everything for Windows but not with g++, I thought that the error could be in the linker order (similar to the problem described in this question). However, even after changing the linker order, I am still getting the same compiler error. I have tried both
g++ -o test.exe test.cpp -Llib -lxerces-c
and
g++ -o test.exe test.cpp lib/libxerces-c.a
Any ideas?
Your project uses method from xercesc_2_6 namespace as pointed by compiler error message but your library offers xercesc_2_8 version. Problem is probably caused by mismatch between headers you use and library object file.
You didn't say the source of the archive. If it isn't compiled with cygwin, it could be a name mangling problem. Compiling the library from source might well fix this.
It could also be that the archive is built incorrectly so that it has internal resolution problems. Try giving the library name twice.
g++ -o test.exe test.cpp lib/libxerces-c.a lib/libxerces-c.a
If this works, the archive is broken and you should look for or build a new one.
Try the linker option --enable-stdcall-fixup (see 'man ld'). It will care for name mangling and calling conventions:
g++ -o test.exe test.o -Wl,--enable-stdcall-fixup -Llib -lxerces-c