BigHead
BigHead

Reputation: 119

undefined reference to function in shared library created directly from static library

I have an old static library that contains a simple simulator. The simulator is initiated by calling a function (sim) also included in the library. Now, I am trying to make this static library into a dynamic library:

g++ -shared -fPIC -o libdynamicSimulator.so -Wl,--whole-archive libstaticSimulator.a -Wl,--no-whole-archive

The object files in ./libstaticSimulator.a are also compiled with the -fPIC flag. This step works fine with no compiler/linker error. I followed a SO post for this step.

However, I encountered linker error when I tried to test the shared library by calling the sim function from a main:

g++ -O2 -g -m64 -Wall -fno-strict-aliasing   -c -o main.o main.c
g++ -O2 -g -m64 -Wall -fno-strict-aliasing -L. main.o  -o sim_dynlib -ldynamicSimulator -lm -lpthread
main.o: In function `main':
main.c:40: undefined reference to `sim(unsigned long*, unsigned long*, unsigned long*, unsigned long)'
collect2: error: ld returned 1 exit status
make: *** [sim_dynlib] Error 1

I used nm to verify that the symbol is there in the dynamic library:

$ nm ./libdynamicSimulator.so | grep sim 
0000000000102e10 T sim

The library is written in C++ but sim's name is not mangled because it is defined within a extern "C" block:

extern "C" {
  uint64_t sim(uint64_t *a1, uint64_t *a2, uint64_t *a3, uint64_t len)
  {
    ...
  }
}

Here is how the main.c is declaring and using the function:

extern uint64_t sim(uint64_t *a1, uint64_t *a2, uint64_t *a3, uint64_t len);

int main(int argc, char **argv)
{
  ... // preparing a1, a2, a3, len
  uint64_t act_sum = sim(a1, a2, a3, len);
  ...
}

I have been googling for hours trying to find the problem but all I could find was about reordering the -l's in the g++ command line, which I already did -- -ldynamicSimulator after main.o.

I feel that I am missing something really simple/stupid here but for the life of me, I could not figure out what it is.

Any help or comment is appreciated.

Upvotes: 0

Views: 657

Answers (1)

BigHead
BigHead

Reputation: 119

I have figured it out. My feeling was correct -- it is a stupid mistake:

The declaration of the sim() function in main.c needs to be put into a extern "C" block, since I am using g++ as the compiler.

extern "C" {
  extern uint64_t sim(uint64_t *a1, uint64_t *a2, uint64_t *a3, uint64_t len);
}
int main(int argc, char **argv)
{
  ... // preparing a1, a2, a3, len
  uint64_t act_sum = sim(a1, a2, a3, len);
  ...
}

The linker error is gone after this change.

Another shorter declaration that works:

extern "C" uint64_t sim(uint64_t *a1, uint64_t *a2, uint64_t *a3, uint64_t len);

Upvotes: 1

Related Questions