Search code examples
cgccld

Final step in GCC compiling (ld) issue


I'm trying to write a makefile that goes through compilation step by step, the issue is on the fourth step, linking.

The program consists of multiple files, starting with main.c:

#include "file1.h"
#include "file2.h"

int main() {
  printout1("Print one");
  printout2(5);
  return 0;
}

file1.h

#include <stdio.h>

void printout1(char *str);

file1.c

#include "file1.h"

void printout1(char *str) {
  printf("%s\n", str);
}

file2.h

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

void printout2(int);

file2.c

#include "file2.h"

void printout2(int val) {
  printf("%d\n", val);
  printout1("Print two");
}

I'm trying to compile this program with the following makefile:

all:
    cpp main.c main.i 
    gcc -S main.i
    as -o main.o main.s
    ld -o main.o

The following error occurs:

ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
main.o: in function 'main':
main.c:(.text+0xa): undefined reference to 'printout1'
main.c:(.text+0x14): undefined reference to 'printout2'
makefile:2 recipe for target 'all' failed
make:***[all] Error 1

I'm fairly new to this sort of thing and I know the problem are the header files, I just don't know how to include them in this.


Solution

  • Two main issues:

    1. gcc is a frontend for all the required steps -- don't try to call the other tools of your toolchain directly, always use gcc. This will make sure it always adds the required options for these other tools.

    2. You have functions in different compilation units (file1 and file2), but never compile and link these.


    A sensible Makefile for GNU make with your structure would look like this:

    CC ?= gcc
    
    all: main
    
    main: main.o file1.o file2.o
        $(CC) -o$@ $^
    
    %.o: %.c
        $(CC) -c -o$@ $<
    
    .PHONY: all
    

    This compiles all .c files directly to object files, and finally links them (using $(CC), so, e.g. gcc) to your final executable. The rule all is marked as .PHONY because it doesn't create a file named all -- you should let make know about that.

    You can of course add additional steps explicitly, but it doesn't make much sense.