Undefined symbols error when using a header file
Asked Answered
R

2

8

I'm getting the following error and can't for the life of me figure out what I'm doing wrong.

$ gcc main.c -o main

Undefined symbols:
  "_wtf", referenced from:
      _main in ccu2Qr2V.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

main.c:

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

main(){
    wtf();
}

wtf.h:

void wtf();

wtf.c:

void wtf(){
    printf("I never see the light of day.");
}

Now, if I include the entire function in the header file instead of just the signature, it complies fine so I know wtf.h is being included. Why doesn't the compiler see wtf.c? Or am I missing something?

Regards.

Raleigh answered 4/6, 2010 at 7:0 Comment(2)
You never told the compiler to compile wtf.c. That's why.Augur
Yeah, I come from the land of magic and unicorns so I just assumed that having the implementation named the same as the header would allow the compiler to find both.Raleigh
P
14

You need to link wtf with your main. Easiest way to compile it together - gcc will link 'em for you, like this:

gcc main.c wtf.c -o main

Longer way (separate compilation of wtf):

gcc -c wtf.c
gcc main.c wtf.o -o main

Even longer (separate compilation and linking)

gcc -c wtf.c
gcc -c main.c
gcc main.o wtf.o -o main

Instead of last gcc call you can run ld directly with the same effect.

Peng answered 4/6, 2010 at 7:1 Comment(3)
So what's stopping me from just doing the following? #include <stdio.h> #include "wtf.h" #include "wtf.c" It feels unpleasant but so does the idea of having to include an argument for every implementation when I run gcc.Raleigh
@j33r: Presumably nothing is stopping you. We, who we need to earn money writing C++ code for a living, however, have our fellow-workers to stop us doing so, in order to protect their sanity. (And if you really didn't know: One of the key features of C is separate compilation. Among other things it allows us to deal with the insanely compile-times the preprocessor file inclusion comes with. And then there's also information hiding, encapsulation and other nice - and, unfortunately, often underrated - principles.)Syllepsis
@j33r: At the point where your program has more than one .c file, it's time to write a simple Makefile to build it.Romanticist
A
4

You are missing the fact that merely including a header doesn't tell the compiler anything about where the actual implementation (the definitions) of the things declared in the header are.

They could be in a C file next to the one doing the include, they could come from a pre-compiled static link library, or a dynamic library loaded by the system linker when reading your executable, or they could come at run-time user programmer-controlled explicit dynamic loading (the dlopen() family of function in Linux, for instance).

C is not like Java, there is no implicit rule that just because a C file includes a certain header, the compiler should also do something to "magically" find the implementation of the things declared in the header. You need to tell it.

Anatto answered 4/6, 2010 at 7:5 Comment(2)
You're exactly right. I was assuming that as long as the header file and the implementation were named the same that the compiler would find both when I included the header.Raleigh
This explanation for why separate compilation is a feature is quite useful. Thanks.Brandon

© 2022 - 2024 — McMap. All rights reserved.