undefined reference when using makefile

15,632

Solution 1

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.

Solution 2

Use this makefile it works and it is more comprehensible/better

GREEN   = \033[1;32m

WHITE   = \033[0;m

NAME    = main

CC      = gcc -g

RM      = rm -f

SRCS    = functions.c    \
          main.c

OBJS    = $(SRCS:.c=.o)

CFLAGS = -I ./include/
CFLAGS += -W -Wall -Wextra

all: $(NAME)

$(NAME): $(OBJS)
         @$(CC) $(OBJS) -o $(NAME) $(LDFLAGS)
         @printf "\n[$(GREEN)OK$(WHITE)] Binary : $(NAME)\n"
         @echo "-------------------\n"

%.o :    %.c
         @$(CC) $(CFLAGS) -c -o $@ $<
         @printf "[$(GREEN)OK$(WHITE)] $<\n"

clean:
        $(RM) $(OBJS)

fclean: clean
    $(RM) $(NAME)

re: fclean all

.PHONY: all clean fclean re

The functions.h file :

#ifndef FUNCTIONS_H_
#define FUNCTIONS_H_

void printMsg();

#endif /* !FUNCTIONS_H_ */

And the same main.c. You don't need to include "functions.h" in the function.c

Allez l'om,

Nicolas :)

Share:
15,632
Hajar Elkoumikhi
Author by

Hajar Elkoumikhi

Software Engineer &amp; iOS Developer

Updated on June 13, 2022

Comments

  • Hajar Elkoumikhi
    Hajar Elkoumikhi almost 2 years

    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