Search code examples
cmakefileheader-files

undefined reference when using makefile


I have a given makefile, written by our Professor.

SHELL  = /bin/bash
CC     = gcc
CFLAGS = -Wall -W -std=c99 -pedantic
LIBS   =

# Rajouter le nom des executables apres '=', separes par un espace.
# Si une ligne est pleine, rajouter '\' en fin de ligne et passer a la suivante.

# To compile without bor-util.c file 
EXECS = main

# To compile with bor-util.c file 
EXECSUTIL = 

# To compile with bor-util.c & bor-timer.c files
EXECSTIMER = 


.c.o :
    $(CC) -c $(CFLAGS) $*.c

help ::
    @echo "Options du make : help all clean distclean"

all :: $(EXECS) $(EXECSUTIL) $(EXECSTIMER)

$(EXECS) : %: %.o 
    $(CC) -o $@ [email protected] $(LIBS)

$(EXECSUTIL) : %: %.o bor-util.o
    $(CC) -o $@ [email protected] bor-util.o $(LIBS)

$(EXECSTIMER) : %: %.o bor-util.o bor-timer.o
    $(CC) -o $@ [email protected] bor-util.o bor-timer.o $(LIBS)

clean ::
    \rm -f *.o core

distclean :: clean
    \rm -f *% $(EXECS) $(EXECSUTIL) $(EXECSTIMER)

All we have to do in this project, is to write our code in other file and use this makefile to compile as usual. I've written a helloWorld function to test. I have 3 files

FUNCTIONS.C

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

void printMsg(){
    printf("Hello World !");
}

FUNCTIONS.H

#ifndef FUNCTIONS_H
#define FUNCTIONS_H

void printMsg();
#endif /* FUNCTIONS_H */

And a MAIN.C file to test out everything

#include "functions.h"


int main(){
    
    printMsg(); 
    return 0;
}

and I've added main to the makefile. But I get this error message when I compile

gcc -o main main.o 
main.o: In function `main':
main.c:(.text+0xa): undefined reference to `printMsg'
collect2: error: ld returned 1 exit status
Makefile:32: recipe for target 'main' failed
make: *** [main] Error 1

Does anyone know what's the solutions please ? Thank you


Solution

  • The error message is clear: the linker did not find the printMsg function. And this is perfectly normal: the link command that was executed was:

    gcc -o main main.o
    

    See? No trace of functions.o where the printMsg function is implemented. To fix this you must link with this command:

    gcc -o main main.o functions.o
    

    The problem is that your Makefile does not mention functions.o as a pre-requisite of main and it does not use it neither in the recipe. Either you did not understand the professor's instructions (who did not ask you to add functions.c and functions.h), or you forgot that he also indicated how to update the Makefile, or his Makefile is not compatible with his own instructions. In the two last cases you can adapt the Makefile by changing the rule for $(EXECS):

    $(EXECS) : %: %.o functions.o
        $(CC) -o $@ $^ $(LIBS)
    

    $^ expands as the list of all pre-requisites, that is, in your case, main.o functions.o. This new rule will:

    1. Re-build main if main.o or functions.o changed.
    2. Link main.o and functions.o.

    Warning: if you have other executables listed in $(EXECS) that do not depend on functions.o, or that depend on other object files, or if you have more other files like functions.o, you will need something a bit more sophisticated. Ask a new question.

    Note: as SO is English, it is better to translate the French comments in your example code. I suggest:

    Add the executable names after '=', separated by one space. If a line is full, add a '\' at the end and continue on the next line.

    One last note: letter case matters. If your file is functions.c do not type FUNCTIONS.C in your question. Same with the other file names.