Search code examples
clinuxgcclinkerclang

Different behavior of undefined reference error on linux gcc during linking with object file vs static library


I have following two source codes and want to link them.

// test.c
#include <stdio.h>

void lib2();

void lib1(){
    lib2();
    return 0;
}
// main.c
#include <stdio.h>

int main() {
    return 0;
}

I've used gcc -c main.c and gcc -c test.c to generate objects files

$ ls *.o
main.o  test.o

and I've used ar rcs test.a test.o command to generate static library(test.a) from object file test.o

Then, I tried to build executable by linking main.o with test.a or test.o. As far as I know, a static library file(.a extension) is a kind of simple collection of object files(.o). so I expected both would give same result: error or success. but it didn't.

Linking with the object file gives undefined reference error.

$ gcc -o main main.o test.o
/usr/bin/ld: test.o: in function `lib1':
test.c:(.text+0xe): undefined reference to `lib2'
collect2: error: ld returned 1 exit status
$

but linking with the static library doesn't give any error and success on compilation.

$ gcc -o main main.o test.a
$

Why is this happening? and how can I get undefined reference errors even when linking with static libraries?


Solution

  • If your code contains a function call expression then the language standard requires a function definition exists. (See C11 6.9/3). If you don't provide a definition then it is undefined behaviour with no diagnostic required .

    The rule was written this way so that implementation vendors aren't forced to perform analysis to determine if a function is ever called or not; for example in your library scenario the compiler isn't forced to dig around in the library if none of the rest of the code contains anything that references that library.

    It's totally up to the implementation what to do, and in your case it decides to give an error in one case and not the other. To avoid this, you can provide definitions for all the functions you call.

    You might be able to modify the behaviour in the first case by using linker options such as elimination of unused code sections. Another thing you can do is call lib1() from main() -- this is still not guaranteed to produce an error but is more likely to.