5

I am building a large application using libkml. I am using the cmake port of libkml from here: https://github.com/rashadkm/libkml

I am getting a stranged undefined reference to symbol error even thought the symbol appears to be referenced and defined.

This is the make command:

/usr/bin/c++ -fPIC -Werror=return-type -Werror=return-type -Wall 
-Werror=parentheses -Werror=uninitialized -Werror=missing-braces 
-fPIC -O0 -Wall -fPIC -fvisibility=hidden -fno-strict-aliasing 
-Wno-long-long -m64 -g -D_DEBUG --coverage -Wl,-Bsymbolic -Wl,--
no-undefined -shared -o GPS2KML.plb CMakeFiles/GPS2KML.dir
/gps.cpp.o CMakeFiles/GPS2KML.dir/kml.cpp.o CMakeFiles/GPS2KML.dir
/stdafx.cpp.o  /trunk/src/filter/GPS2KML/external/libkml/lib/cmake
/libkml/../../libkmlconvenience.so.1.3.1 /trunk/src/filter/GPS2KML
/external/libkml/lib/cmake/libkml/../../libkmlengine.so.1.3.1 
/trunk/src/filter/GPS2KML/external/libkml/lib/cmake/libkml/../..
/libkmldom.so.1.3.1 /trunk/src/filter/GPS2KML/external/libkml
/lib/cmake/libkml/../../libkmlbase.so.1.3.1 -lminizip -luriparser 
-lexpat

The make output:

CMakeFiles/GPS2KML.dir/kml.cpp.o: In function `cKML::~cKML()':
/trunk/src/filter/GPS2KML/src/kml.cpp:55: undefined reference to `*kmldom::SerializePretty(boost::intrusive_ptr<kmldom::Element> const&)*'
collect2: error: ld returned 1 exit status

Now if i do this: daniyal@daniyal-Inspiron-5521:/$ nm --demangle --extern-only --defined-only ../trunk/src/filter/GPS2KML/external/libkml/lib/libkmldom.so | grep SerializePretty

It clearly shows:

000000000013c9aa T kmldom::SerializePretty[abi:cxx11](boost::intrusive_ptr<kmldom::Element> const&)

Now I fail to understand what is the problem. I have check the existing questions on stackoverflow regarding this, I found four solutions in the existing questions:

  1. In some cases the demangled symbol name did not match with the symbol that was causing error. This is clearly not my case.
  2. Use -llibrary at the end of the command after putting the name of the .o file. So that when the linker encounters the library it has an undefined symbol present in that library. This is clearly not a solution for me as I have the libraries present at the end of the command.
  3. In some cases the symbol is present in the shared library but does not have external linkage or is not defined. This can be confirmed by using nm with --extern-only and --defined-only. And hence this is also not a solution for me.

Edit: Additional Info:

This is the cmake file I am using:

find_package(LibKML REQUIRED)

include_directories(${LIBKML_INCLUDE_DIRS})

add_filter(${PROJECT}
        gps.h
        gps.cpp
        kml.h
        kml.cpp
        #can2gps.h
        #can2gps.cpp
        stdafx.h 
        stdafx.cpp )


target_link_libraries (${PROJECT} ${LIBKML_LIBRARIES})

add_filter roughly translates to this macro:

add_library(${NAME} MODULE ${ARGN} ${${NAME}_MOC} ${${NAME}_UI} ${${NAME}_QRC})

target_link_libraries(${NAME} ${BUILD_LIBS} ${QT_LIBRARIES}  ${ADTF_OPENGL_LIBRARY} ${ADTF_ADDITIONAL_UTILS_LIBS})
set_target_properties(${NAME}
PROPERTIES
SUFFIX ".plb"
)
if(UNIX)
set_target_properties(${NAME}
PROPERTIES
PREFIX ""

)

Daniyal Yasin
  • 142
  • 1
  • 14
  • 1
    Order of linking is important... you must link with dependants first, then dependancies. If you have a circular reference, you may need to link to libraries multiple times – UKMonkey Jun 12 '17 at 14:14
  • Another possibility is that name demangling is somehow obscuring something. Try `nm --extern-only --defined-only | egrep 'kmldom.*Serialize.*boost.*intrusive_ptr.*kmldom.*Element'` and see if you can see the precise mangled symbol. Maybe the symbol is for a different ABI version or something. – Omnifarious Jun 12 '17 at 14:43
  • @Omnifarious On running your command, no output was produced. – Daniyal Yasin Jun 12 '17 at 15:12
  • @DaniyalYasin - Well, that's interesting. How about this... `nm --extern-only --defined-only | fgrep 'kmldom' | fgrep 'SerializePretty' | fgrep 'Element'`. That will set it up so the order of the embedded names inside of the mangled identifier don't matter, but it may give you too many symbols. You can try also filtering by `intrusive_ptr`. Are you generally familiar with what mangled names look like? – Omnifarious Jun 12 '17 at 15:18
  • There was only one result. This: `000000000013c9aa T _ZN6kmldom15SerializePrettyB5cxx11ERKN5boost13intrusive_ptrINS_7ElementEEE ` – Daniyal Yasin Jun 12 '17 at 15:32
  • Now do this to `kml.cpp.o`. `nm kml.cpp.o | fgrep 'kmldom' | fgrep 'SerializePretty' | fgrep 'Element'`. Do the symbols match? – Omnifarious Jun 12 '17 at 15:41
  • kml.cpp.o: `U _ZN6kmldom15SerializePrettyERKN5boost13intrusive_ptrINS_7ElementEEE` libkmldom.so:`T _ZN6kmldom15SerializePrettyB5cxx11ERKN5boost13intrusive_ptrINS_7ElementEEE` They don't match – Daniyal Yasin Jun 12 '17 at 15:48
  • If we do demangle: kml.cpp.o: `U kmldom::SerializePretty(boost::intrusive_ptr const&)` libkmldom.so: `T kmldom::SerializePretty[abi:cxx11](boost::intrusive_ptr const&) ` Has the issue got something to do with c++11? – Daniyal Yasin Jun 12 '17 at 15:50
  • @DaniyalYasin - Did this exchange and my answer actually help? – Omnifarious Jun 12 '17 at 19:42

1 Answers1

5

It looks like you have an ABI mismatch issue. ABI is "Application Binary Interface", basically the specification for exactly how arguments make it onto the stack (or are put in registers) and various other things like that.

Try making sure your code is compiled with the -std=c++11 (or -std=gnu++11 if you use any GNU extensions) flag. It looks like that's how libkml was compiled. C++11 has a bunch of new features that require an ABI compatibility break with pre-C++11. C++14 and C++1z are less drastic changes, but they may also break ABI compatibility, I'm not sure. In this case though, the demangled symbol is clear, libkml wants at least C++11.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
  • 1
    Sorry for marking this as accepted answer so late. My project's cmake structure was enforcing c++98.. I had to find out the add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1) option Thank you so much for your help – Daniyal Yasin Jun 13 '17 at 14:16
  • @DaniyalYasin - I'm just glad your problem is solved. – Omnifarious Jun 13 '17 at 14:34