I have a question regarding compiling and linking in Makefile (and perhaps in general).
I have a server.c file which consists of the main program which has a main()
function. server.c
includes rio.c. I have a module called rio
which consists of rio.c
and rio.h
. It has no main()
function.
I have two questions, how to actually write the Makefile, and the best practice for doing such a thing.
Q1: How to write the Makefile
I have the following Makefile:
CC = gcc
CFLAGS = -Wall -Werror -Wmissing-prototypes
OBJS = server.o rio.o
all: $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o sysstatd
server.o: server.c
$(CC) $(CFLAGS) -c server.c
rio.o: rio.c rio.h
$(CC) $(CFLAGS) -c rio.c
clean:
rm -f *~ *.o sysstatd
I am having linking issues with this. It says that I have multiple definitions of all the functions used in C. I'm not sure how this is possible since server.c is compiled with the -c
flag so nothing is actually linked. It should know that some functions exist but not actually link them until the all
rule compiles both object files together and produces a single object file which has everything linked.
What is the issue here?
Q2: Best practice
Since I have a module and then another file which contains the main program, should I compile the main program, server.c
, as a separate module and then compile both together in all
, or compile server.c in all and add the rio.o module there? Note that this still produces the same linking problem I have above so I'm pretty sure I have my issue lies somewhere else.
Compiling - The modified source code is compiled into binary object code. This code is not yet executable. Linking - The object code is combined with required supporting code to make an executable program. This step typically involves adding in any libraries that are required.
In this context, “relink” merely means that make will execute the command to link objects into an executable again.
The goal of Makefiles is to compile whatever files need to be compiled, based on what files have changed. But when files in interpreted languages change, nothing needs to get recompiled.
Compilation: the compiler takes the pre-processor's output and produces an object file from it. Linking: the linker takes the object files produced by the compiler and produces either a library or an executable file.
You should revise the structure a little:
CC = gcc
CFLAGS = -Wall -Werror -Wmissing-prototypes
OBJS = server.o rio.o
all: sysstatd
sysstatd: $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o sysstatd
server.o: server.c
$(CC) $(CFLAGS) -c server.c
rio.o: rio.c rio.h
$(CC) $(CFLAGS) -c rio.c
clean:
rm -f *~ *.o sysstatd
The difference is that the phoney rule all
depends on sysstatd
being up to date, and sysstatd
is up to date when it is up to date w.r.t the object files.
Now it is just rather verbose, writing the compilation actions explicitly. It would be sufficient to use:
CC = gcc
CFLAGS = -Wall -Werror -Wmissing-prototypes
OBJS = server.o rio.o
all: sysstatd
sysstatd: $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o sysstatd
server.o: server.c
rio.o: rio.c rio.h
clean:
rm -f *~ *.o sysstatd
You could also debate: does server.c
not use rio.h
? If it does, the dependency should be listed. If not, why does rio.h
exist? make
will assume that server.o
depends on server.c
, so you don't have to specify that (but it won't make assumptions about the headers). You could also use a macro to prevent repetition of the program name:
CC = gcc
CFLAGS = -Wall -Werror -Wmissing-prototypes
OBJS = server.o rio.o
PROG = sysstatd
all: $(PROG)
$(PROG): $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $@
server.o: rio.h
rio.o: rio.h
clean:
rm -f *~ *.o $(PROG) core a.out
If you needed other libraries, then you might use:
CC = gcc
CFLAGS = -Wall -Werror -Wmissing-prototypes
OBJS = server.o rio.o
PROG = sysstatd
LOCALLIBDIR = /usr/local/lib
LDFLAGS = -L$(LOCALLIBDIR)
LDLIBS = -lone -ltwo
all: $(PROG)
$(PROG): $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $@ $(LDFLAGS) $(LDLIBS)
server.o: rio.h
rio.o: rio.h
clean:
rm -f *~ *.o $(PROG) core a.out
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With