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.

alk
  • 69,737
  • 10
  • 105
  • 255
Chris Cummings
  • 2,007
  • 5
  • 25
  • 39

2 Answers2

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.

qrdl
  • 34,062
  • 14
  • 56
  • 86
  • So what's stopping me from just doing the following? #include #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. – Chris Cummings Jun 04 '10 at 07:24
  • 2
    @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.) – sbi Jun 04 '10 at 07:37
  • 1
    @j33r: At the point where your program has more than one `.c` file, it's time to write a simple `Makefile` to build it. – caf Jun 04 '10 at 08:00
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.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • 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. – Chris Cummings Jun 04 '10 at 07:20
  • This explanation for *why separate compilation is a feature* is quite useful. Thanks. – jds Dec 30 '14 at 01:54