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

2

44

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?

Dardan answered 6/4, 2017 at 13:20 Comment(4)
You said the output contains the symbol Gps_Ephemeris::Gps_Ephermeris(), but don't show the actual output. This is relevant, and would be useful. Also, you clearly haven't copied-and-pasted that symbol into the question, because you misspelt it. I'm mistrustful of written summaries of this kind, because if you were a reliable judge of what to exclude from your summary, you probably wouldn't be asking the question.Heteromorphic
Thanks for noticing that, I fixed it. I mostly do high-level computer vision, so yes, I feel unqualified to judge what has to be excluded. I will post the output as soon as I can.Dardan
Without looking at the source code it is hard to tell why the .so and .a built from the same sources export different symbols. Conditional compilation may be involved.Reynaldoreynard
What are the mangled symbol names in both main.o and in libgnss_system_parameters_dyn.so? G++ has changed name mangling on occasion when the ABI has changed. Perhaps libgnss_system_parameters_dyn.so was not compiled the same as how you're compiling main.cpp. Try g++ -std=c++0x -c main.cpp; nm main.o and compare the mangled names to what's in the lib.Flummox
R
37

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.

Reynaldoreynard answered 6/4, 2017 at 13:55 Comment(1)
Thanks a lot! You were right. However, the symbols are present in the (equivalent) static library. I updated the question with some information at the end. Could you please take a look?Dardan
L
6

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.

Lavonna answered 11/4, 2017 at 18:27 Comment(2)
Could you elaborate how extern "C" linkage handles constructors?Reynaldoreynard
It doesn't. They are not part of C, but of C++.Lavonna

© 2022 - 2024 — McMap. All rights reserved.