0

I have 2 .c files and respective .h files and main.c.

The files' content are as follow:

main.c

#include "a.h"

int main() {
    a_func();
}

a.h

#include "b.h"

/* struct defined in b.h is used here */

void a_func();

a.c

#include "a.h"
#include "b.h"

void a_func(){...} /* b_func is called within a_func */

b.h

void b_func();

b.c

#include "b.h"

b_func(){...}

I wrote a Makefile to compile main.c:

main: main.o a.o
    gcc main.o a.o -o main

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

a.o: a.c a.h b.h
    gcc -c a.c

However, make complains:

a.o: In function `a_func':
a.c: undefined reference to `b_func'

I was wondering how should I revise the Makefile to make it work.

  • You never build `b.c` or link with `b.o`. – Some programmer dude Aug 01 '23 at 06:10
  • `b_func()` defined in `b.`c is not linked for the compiler to process – Raky Aug 01 '23 at 06:23
  • So if I'm compiling `main.c` I have to link every non-sandard library `.c` file that is related to `main.c` even though only `a.h` is present in `main.c`? Can't make figure out the dependency on its own? – Yiyang Yan Aug 01 '23 at 14:39
  • Also please see [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – Some programmer dude Aug 02 '23 at 06:12

1 Answers1

0

I think this is the perfect time to learn about the concept of translation units.

In short, a translation unit is a single source file, with all included headers. This is the unit that the compiler itself works with.

Your code uses multiple translation units, with functions defined (implemented) in them that are used from other translation units. The compiler doesn't know anything about other translation units, only the one it is compiling at the moment.

It is the linkers job to take all the translation units (the *.o files that the compiler creates, essentially the binary form of the translation unit) and pull them together with libraries to create the executable program file. The linker resolves missing external functions, so if the object file main.o uses a function from a.o then it will make sure to resolve that connection.

The problem you have is that you link with only the main.o and a.o translation units. And a.o doesn't define the b_func function, leading to the error you get.

To solve the problem you need to build the b.c source file into the b.o object file, and then link with it. You need to create a rule like the one you have for a.o, and add b.o in the dependencies for main.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 1
    May I propose a rewording of "single source file, with..."? I would write this as "A translation unit is the body of text which results after the compiler (to be precise: the preprocessor of the compiler) was given a start file in C/C++ syntax and has replaced all _active_ (i.e. in the active branch of `#if`-`#else` directives) `#include` directives with the respective files, recursively resolving the included texts `#include` directives, until the end of the start file is reached" – Vroomfondel Aug 02 '23 at 09:21