Undefined reference when dynamically linking with gcc in cygwin
Asked Answered
C

2

5

(This is gcc 3.3.1 (long story -- blame NIST) on Cygwin.)

I have compiled some source files with gcc -c -fPIC ... to get .o files.

Then I did:

$ gcc -shared -o foo.dll foo.o bar.o

But when I go to use it:

$ gcc -o usefoo.exe usefoo.o -L. -lfoo
  usefoo.o:usefoo.cpp:(.text+0x2e0): undefined reference to `_get_template_size'
  collect2: ld returned 1 exit status

However, if using the same .o files I instead do:

$ ar rcs libfoo-static.a foo.o bar.o

The link against that is successful:

$ gcc -o foo.exe foo.o -L. -lfoo-static

What is weird to me is that as you can see below, the reference in question is present in both the .a and the .dll. So why the error when linking against the .dll?

Reference is found in the shared library:

$ nm foo.dll|grep get_template
1001b262 T _get_template_size

And it's also in the static library:

$ nm libfoo-static.a |grep get_template
00000352 T _get_template_size

And here's the reference to the symbol generated in the file that wants to use the function:

$ nm usefoo.o
00000000 b .bss
00000000 d .data
00000000 t .text
0000012c T __Z12ErrorMessagei
         U ___main
         U __alloca
         U _atoi
         U _get_template_size
0000026c T _main
         U _printf

Updated to address Marco's answer

Interestingly/annoyingly, when I try to make a minimum test example of this I can't make it happen (though it happens every time with the real thing):

func1.h:

#ifndef FUNC1_H
#define FUNC1_H

int func1(int i);

#endif

func1.c:

#include "func1.h"

int func1(int i) {
  return 2*i;
}

usefunc.c:

#include <stdio.h>
#include "func1.h"

int main() {
  printf("%d\n", func1(10));
}

Then:

$ rm *.o *.dll *.a

$ gcc -fPIC -I. -c func1.c usefunc.c

$ gcc -shared -o func.dll func1.o

$ gcc -L. -o usefunc.exe usefunc.o -lfunc

$ ./usefunc.exe
20
Cheap answered 16/2, 2012 at 19:30 Comment(0)
C
6

I found the answer (in that it solves my link problem) on a Cygwin web page: http://cygwin.com/cygwin-ug-net/dll.html

What I ended up having to do was create the shared library and do the final link like this:

$ gcc -shared -o cygfoo.dll \
      -Wl,--out-implib=libfoo.dll.a \
      -Wl,--export-all-symbols \
      -Wl,--enable-auto-import \
      -Wl,--whole-archive *.o \
      -Wl,--no-whole-archive

$ gcc -L. -o usefoo.exe usefoo.o -lfoo

But I'd still love to know why I didn't have to do this for my simple test.

Cheap answered 17/2, 2012 at 20:35 Comment(0)
S
2

I'm not entirely sure, but afaik Windows has namespaces per module (like exe or .dll). When statically linking you are putting everything in one .exe, thus one module, one namespace.

When dynamically linking, you create an two modules (1 exe, 1 dll), and they both have their namespaces.

You need to export the symbol from the DLL for this to work iirc (read up on importlibs, e.g. in the excellent Linkers and Loaders

Selfconsequence answered 16/2, 2012 at 22:0 Comment(2)
Interesting! Two things to note: (1) With the actual code in question, if I add calls to other things in the shared library, they also show up as undefined under a dynamic link -- so it's not just that specific function. This supports your answer. However... (2) When I try to make a simple test of this, the simple test works fine under a dynamic link! (See the update to my question).Cheap
No idea. There might be helper functionality in the compiler here and there, I don't know the various windows ports that well. Btw PIC on Windows ?!?Selfconsequence

© 2022 - 2024 — McMap. All rights reserved.