5

I'm trying to link a small C++ test program, main.o to a 3rd party static library, but get some inexplicable undefined reference errors.

Specifically:

g++  -o secoTest -lpthread  main.o  libEAPI.a
main.o: In function `main':
main.cpp:(.text+0x29fe): undefined reference to `EApiWDog_SetConfigAndStart(unsigned int, unsigned int, unsigned int, unsigned int, unsigned char, unsigned char, unsigned char)'
main.cpp:(.text+0x33fc): undefined reference to `EApiSetCarrier(unsigned char)'
main.o:main.cpp:(.text+0x3956): more undefined references to `EApiSetCarrier(unsigned char)' follow
main.o: In function `main':
main.cpp:(.text+0x3965): undefined reference to `EApiGPIOGetSerialCfg(unsigned char*)'
main.cpp:(.text+0x3a0a): undefined reference to `EApiSetCarrier(unsigned char)'
main.cpp:(.text+0x3a19): undefined reference to `EApiGPIOSetSerialCfg(unsigned char)'
main.cpp:(.text+0x3adf): undefined reference to `EApiFanEnable(unsigned int, unsigned char)'
main.cpp:(.text+0x3b83): undefined reference to `EApiFanDisable()'
collect2: ld returned 1 exit status

However, it seems the symbols are present in the library. For example:

nm --demangle libEAPI.a | grep EApiFanDisable
00003c20 T EApiFanDisable

The strange thing is the symbols are not exactly the same. In main.o it is

nm --demangle main.o | grep EApiFanDisable
         U EApiFanDisable()

So one has () and one doesn't.

Similarily,

nm --demangle main.o | grep EApiSetCarrier
         U EApiSetCarrier(unsigned char)
nm --demangle libEAPI.a | grep EApiSetCarrier
000015d0 T EApiSetCarrier

If I leave out the library altogether from the command line (eg, g++ -o secoTest -lpthread main.o) it shows lots of errors as expected.

main.o references external symbols with and with () [why?]:

     U EApiVgaSetBacklightEnable
     U EApiWDogStart
     U EApiWDogTrigger
     U EApiFanEnable(unsigned int, unsigned char)
     U EApiFanDisable()
     U EApiSetCarrier(unsigned char)

But the library has only symbols without () [why?]:

000020e0 T EApiVgaSetBacklightEnable
000024e0 T EApiWDogStart
000026f0 T EApiWDogTrigger
00003c20 T EApiFanDisable
00003bf0 T EApiFanEnable
000015d0 T EApiSetCarrier

Would that be the reason for the undefined references? How would I fix it? Not sure where to look next...

(I cannot modify the 3rd party library but have the header files.)

EDIT

As lisyarus suggested, here is the nm without the --demangle. Indeed, the symbols are different. The g++ compiler (v4.4.7) generates a mangled symbol for some symbols only while the library always has plain symbols... [why?]

nm libEAPI.a main.o | grep EApiWDogTrigger
000026f0 T EApiWDogTrigger
         U EApiWDogTrigger
nm libEAPI.a main.o | grep EApiSetCarrier
000015d0 T EApiSetCarrier
         U _Z14EApiSetCarrierh
Danny
  • 2,482
  • 3
  • 34
  • 48
  • 1
    What does `nm` without demangling show? It may happen that the library was compiled with a different compiler / standard / etc, and the mangled names are somehow different. – lisyarus Feb 28 '18 at 11:02

1 Answers1

14

The library libEAPI.a contains object files compiled in C, not C++. The symbols therefore have not been name-mangled and cannot serve to resolve the name-mangled function references generated by your C++ code.

Run:

nm libEAPI.a | grep EApiFanDisable

and you will see no change.

Run:

nm main.o | grep EApiFanDisable

and you will see the mangled symbol, which is neither EApiFanDisable nor EApiFanDisable() but something more like _Z14EApiFanDisablev, that the linker is actually trying to resolve.

To avoid these linkage errors you must inform your C++ compiler, when it compiles the header file(s) of libEAPI, that the declarations therein have external C linkage, so it will emit unmangled references to the symbols declared: like so:

main.cpp

...
extern "C" {
#include "EAPI.h"   // or whatever
}

...

BTW, this commandline:

g++  -o secoTest -lpthread  main.o  libEAPI.a

will fail to link libpthread on a Debian-based distro (Ubuntu et al) more recent than Debian 6, as all libraries must be linked in dependency order since then:

g++  -o secoTest main.o  libEAPI.a -lpthread

Even better, do not use the non-portable -lpthread and pass the portable option -pthread for both compilation and linkage. It means: Do whatever is right to compile/link with Posix Threads support

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182