3

I have a project with the following files, all in the same folder

client.c
server.c
reliable_udp.h
reliable_udp.c
conf.h

Among the other libraries, client.c includes also reliable_udp.h ( #include "reliable_udp.h") in order to use the functions packet_send and print_conf (that are implemented in reliable_udp.c).

I'm new to Makefiles, and I'm trying to write one:

CC = gcc
CFLAGS = -Wall -Wextra -Wpedantic -O3
SRC = client.c server.c
OBJ = $(SRC:.c=.o)

all: $(OBJ)
        ${CC} ${CLFAGS} client.o -o client
        ${CC} ${CLFAGS} server.o -o server

client.o: reliable_udp.h

clean:
        rm -f *.o core

cleanall:
        rm -f *.o core client server

If I try to run make, I get the following output:

gcc -Wall -Wextra -Wpedantic -O3   -c -o client.o client.c
gcc  client.o -o client
client.o: In function `main':
client.c:(.text.startup+0x84): undefined reference to `packet_send'
client.c:(.text.startup+0x8b): undefined reference to `print_conf'
collect2: error: ld returned 1 exit status
Makefile:7: recipe for target 'all' failed
make: *** [all] Error 1

Obviously I'm failing writing correctly the Makefile. How should I fix it? Why am I getting this error?

Robb1
  • 4,587
  • 6
  • 31
  • 60
  • Possible duplicate of [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) – n. m. could be an AI Jan 06 '18 at 07:53
  • I do not see "reliable_udp.c" mentioned in your make. How is it supposed to be compiled? – Yunnosch Jan 06 '18 at 07:53
  • @Yunnosch how should I mention it? I thought `client.o: reliable_udp.h` was enough – Robb1 Jan 06 '18 at 07:55
  • You want client.o updated when reliable_udp.h changes. How? And how should that involve reliable_udp.c ? – Yunnosch Jan 06 '18 at 07:57
  • 1
    Or to put it differently, why is `SRC = client.c server.c` not mentioning reliable_udp.c? What I want to say is that you should explain the logic of your makefile, in order to make answering your question easier. – Yunnosch Jan 06 '18 at 07:59
  • @Yunnosch I tried editing my OP to make it more clear. To answer your question, I think the problem is in the Makefile itself – Robb1 Jan 06 '18 at 08:08
  • to start, this: `${CLFAGS}` should be: `${CFLAGS}` in both instances – user3629249 Jan 07 '18 at 05:17

2 Answers2

4

Why am I getting this error?

Because the link recipes do not include the 'reliable_udp.0' object and because nothing in the makefile will compile 'reliable_udp.c into 'reliable_udp.o`

the posted makefile contains several problems, as expressed in the comments to the question.

The following is a proposed, simple makefile that should perform the desired functionality.

Note: replace <tab> with a tab character

Note: in the following makefile, the invocation command can be:

make          -- to generate both 'client' and 'server'
                 as it will use the first target, which is 'all'
make all      -- to generate both 'client' and 'server'
make client   -- to only generate the 'client' executable
make server   -- to only generate the 'server' executable
make clean    -- to delete the object files
make cleanall -- to delete the object files and the executables

and now the proposed makefile

#use ':=' rather than '=' so macros only evaluated once

#assure the desired utilities are used
CC := /usr/bin/gcc
RM := /usr/bin/rm -f

CFLAGS := -Wall -Wextra -Wpedantic -std=GNU11 -O3

#generate a list of all the source files
SRC := client.c server.c reliable_udp.c

#generate a list of all the object file names
OBJ := $(SRC:.c=.o)

#let make know that the target 'all' will not produce a file of the same name
#notice the 'all' target dependencies are the final executables
.PHONY: all
all: client server

#this will perform all the compiles
#while expecting the user supplied header files to be in the local directory
%.o:%.c
<tab>$(CC) -c $(CFLAGS) $^ -o $@ -I.

#link the 'client' executable
client: client.o reliable_udp.o
<tab>${CC}  $^ -o $@

#link the 'server' executable
server: server.o reliable_udp.o
<tab>${CC}  $^ -o $@

#let make know that this target will not produce a file of the same name
.PHONY: clean
clean:
<tab>$(RM) $(OBJ) core

#let make know that this target will not produce a file of the same name
.PHONY: cleanall
cleanall:
<tab>$(RM) $(OBJ) core client server
user3629249
  • 16,402
  • 1
  • 16
  • 17
  • Thanks for your answer. There's no need to mention `reliable_udp.h` in the `Makefile`? It surprises me – Robb1 Jan 07 '18 at 10:44
  • @Robb1, you stated that all your files are in the same directory. The recipe to compile the .c files has the option: `-I.` which says to look in the local directory for the header files. That is all that is necessary – user3629249 Jan 07 '18 at 19:36
1

A quick fix would be to modify the Makefile as follows:

all: $(OBJ)
        ${CC} ${CLFAGS} reliable_udp.o client.o -o client
        ${CC} ${CLFAGS} reliable_udp.o server.o -o server

It's not pretty though, in "real world" a better option might be to make a shared library for "reliable_udp", or at least refactor Makefile a little bit.

The reason of the error is that "reliable_udp" is not compiled in to the final binaries, since it's not explicitly specified anywhere in the makefile.