20

Why am I getting an "undefined reference" error using gcc?

I am trying to create a shared object (.so) that exports one function, "external()". I then try to link against the .so but get "undefined reference 'external'". What am I doing wrong here?

File: external.c

int external() {
    return 5;
}

File: program.c

int external();
int main(char** argv, int* argc) {
    return external();
}

Commands:

$ gcc -fPIC -c external.c
$ gcc -shared -o libexternal.so external.o
$ gcc -L. -lexternal -o program program.c
/tmp/cc3MmhAE.o: In function `main':
program.c:(.text+0x7): undefined reference to `external'
collect2: ld returned 1 exit status

I can even run nm and see that the .so is defining 'external':

Command:

$ nm libexternal.so | grep external
0000040c T external

What am I missing here?

octopusgrabbus
  • 10,555
  • 15
  • 68
  • 131
Warren
  • 1,903
  • 1
  • 21
  • 30

1 Answers1

42

Recent versions of gcc/ld default to linking with --as-needed.

This means if you write -lexternal before the C file the library will automatically get excluded (the order matters when testing if things are "needed" like this)

You can fix this with either of:

  • gcc -L. -o program program.c -lexternal
  • gcc -L. -Wl,--no-as-needed -lexternal -o program program.c

The latter of which passes --no-as-needed to the linker, which would cause the library to still be linked, even if you didn't call external() from it.

Note: -Wl,--no-as-needed isn't applied globally to everything that's linked, it's only applied to things that follow it in the command line order. So -lexternal -Wl,--no-as-needed also wouldn't work. This does mean that you can mix and match behaviours though, for example gcc -L. -Wl,--no-as-needed -lexternal -Wl,--as-needed -o program program.c -lmightneed would always link against external, but only link against mightneed if one or both of program.c/libexternal.so caused it to be needed.

Flexo
  • 87,323
  • 22
  • 191
  • 272
  • 3
    Thanks for also adding "--as-needed/--no-as-needed" explanation. This is exactly what I was looking for. – Warren Nov 15 '11 at 17:42
  • 1
    Adding on, when compiling a dynamic library (A.so) which also links to other dynamic library (B.so). And if linking to the compiled library (A.so) via dlopen. It is possible for the dlopen to just silently fail. Without error. As the 2nd library is not loaded properly (B.so); This alone costed me a month of productivity time, as we were migrating to 64-bit, to finally trace down this question as a "possible cause" for a project of mine. So be wary of it. – PicoCreator Jan 03 '13 at 09:12
  • "Recent versions" - any chance you know exactly which one introduced this change? – Nathan Osman Jun 11 '16 at 06:14
  • @NathanOsman not off hand and different distros patched it in earlier/later as they saw fit. I'd guess GCC 4.2 era being approximately the cutover. – Flexo Jun 11 '16 at 08:11