Makefile, Compiling and Linking - c

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.

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

Related

makefile not changing input filename

I am trying to make a C program and have the following makefile:
CC=clang
CFLAGS=-std=c99 -Wall -pedantic
LDFLAGS=
LDLIBS=
OUT=nes_slop
SRC_DIR=src/
OBJ_DIR=obj/
SRCS=$(wildcard $(SRC_DIR)*.c)
OBJS=$(addprefix $(OBJ_DIR),$(notdir $(SRCS:.c=.o)))
MAKE=make
CLEAR=TRUE
all: clean $(OUT)
clean:
rm -i $(OUT) $(OBJS) -f
$(OUT): $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $(OUT)
$(OBJS): $(SRCS)
$(CC) -c $(CFLAGS) $(LDLIBS) $< -o $#
It was all well and good until I had more than 1 .c file:
clang -c -std=c99 -Wall -pedantic -lncurses src/gamestate.c -o obj/gamestate.o
clang -c -std=c99 -Wall -pedantic -lncurses src/gamestate.c -o obj/main.o
so, somehow the source file is not being updated, it's always gamestate.c... what's wrong with my makefile? any help is appreciated, thank you
In short, your rule should look something like this:
$(OBJS): %.o: %.c
$(CC) -c $(CFLAGS) $(LDLIBS) $< -o $#
You may also want to read this for how to generate automatic dependencies (so if you change a header file, your c files will automatically regenerate as needed) There's a TL;DR section at the top of that page, if you're not interested in the details.

How can I change my makefile to redirect .o

I'm trying to change my makefile to redirect the .o to a lib folder (and have the .c in a src folder). I would also like the executables to be at the same level as the makefile.
As for the .h, I have no idea where to put it!
CC = gcc
CFLAGS = -std=c11 -Wpedantic -Wall -Wextra -Wconversion -Werror -fPIC -pthread -D_XOPEN_SOURCE=500 -fstack-protector
LDLIBS = -lrt
RM = rm -f
ARFLAGS = rs
all: server client info_proc info_user
server: server.o header.o
$(CC) $(CFLAGS) -o $# $^ $(LDLIBS)
server.o: server.c header.h
gcc -c server.c
client: client.o header.o
$(CC) $(CFLAGS) -o $# $^ $(LDLIBS)
client.o: client.c header.h
header.o: header.c header.h
gcc -c header.c
info_proc: info_proc.o
info_proc.o: info_proc.c
gcc -c info_proc.c
info_user: info_user.o
info_user.o: info_user.c
gcc -c info_user.c
rmpipe:
$(RM) question_pipe
clean:
$(RM) server client info_proc info_user question_pipe *.o *~$
You could do something like this:
all: main
main: lib/a.o lib/b.o lib/main.o
$(CC) $(CFLAGS) -o $# $^
lib/a.o: a.c
$(CC) $(CFLAGS) -c -o $# $<
lib/b.o: b.c
$(CC) $(CFLAGS) -c -o $# $<
lib/main.o: main.c
$(CC) $(CFLAGS) -c -o $# $<
Or instead of writing your own Makefile you could use one of these build
tools:
GNU Autotools
Cmake
SCons
which on the long run are much easier to maintain than a self-written
Makefile.

Understanding Makefile syntax

Can someone help me understand the below makefile?
I have comment on the bits I am not sure on. I have used make files but not extensively and I do not believe I have followed good practises so any advice is welcome.
CC=gcc #is CC, libs, deps, obj, etc predefined keywords or could I use something else
CFLAGS=-I. -g -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse #same with CFlags
LIBS = -luuid -lfuse -pthread
DEPS = fs.h unqlite.h
OBJ = unqlite.o fs.o
TARGET1 = test
TARGET2 = test2
TARGET3 = test3
TARGET4 = test4
TARGET5 = main
all: $(TARGET1) $(TARGET2) $(TARGET3) $(TARGET4) $(TARGET5)
%.o: %.c $(DEPS) #not sure on this line
$(CC) -c -o $# $< $(CFLAGS) #same here
$(TARGET1): $(TARGET1).o $(OBJ)
gcc -o $# $^ $(CFLAGS) $(LIBS) #what are $# and $^
$(TARGET2): $(TARGET2).o $(OBJ)
gcc -o $# $^ $(CFLAGS) $(LIBS)
$(TARGET3): $(TARGET3).o $(OBJ)
gcc -o $# $^ $(CFLAGS) $(LIBS)
$(TARGET4): $(TARGET4).c
gcc -o test test.c
$(TARGET5): $(TARGET5).c
gcc -o uuid uuid.c -luuid
.PHONY: clean
clean:
rm -f *.o *~ core $(TARGET1) $(TARGET2) $(TARGET3) $(TARGET4) $(TARGET5)
CC, CFLAGS, LIBS, DEPS, OBJ and TARGETs are not predefined keywords. They are variables. You can change the name into any you feel appropriate. Just make sure you also change their reference names: $(CC) $(CFLAGS) etc.
%.o: %.c $(DEPS) -
It is a pattern rule: https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html
In brief, it says: any .o file depends on .c file with the same prefix and $(DEPS) (which are fs.h and unqlite.h)
$#, $<, $^ are automatic variables for the rules: https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html#Automatic-Variables
If works the following way: when making test.o object file from source, the rule
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
Is interpreted as:
test.o: test.c fs.h unqlite.h
gcc -c -o test.o test.c -I. -g -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
Then, when making test binary, the rule
$(TARGET1): $(TARGET1).o $(OBJ)
gcc -o $# $^ $(CFLAGS) $(LIBS)
Becomes:
test: test.o unqlite.o fs.o
gcc -o test test.o unqlite.o fs.o -I. -g -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse -luuid -lfuse -pthread
So, we can see, CFLAGS reference is useless in the rule, as it defines compilation flags, and the rule actually performs linking. So the right one would be:
$(TARGET1): $(TARGET1).o $(OBJ)
gcc -o $# $^ $(LDFLAGS) $(LIBS)
Where LDFLAGS would be defined to some useful value, or can be left empty:
LDFLAGS =

C - Makefile possibly missing a line

I'll say first I don't have as much experience which makefiles as I wished, this is actually my first.
The error I currently get is:
Makefile:1: missing separator. Stop.
This happens when I try to run the make command.
As far as I know this means that I'm missing a hard tab at the first line it tries to run, I think at least.
I'm not missing a hard tab though as far as I know, so I'm assuming I'm just missing a whole line somewhere.
CFLAGS = -ansi -Wall -pedantic
HEADERS = menu.h file1.h file2.h file3.h file4.h
OBJECTS = menu.o file1.o file2.o file3.o file4.o
CC = gcc
all:runprog
runprog:$(OBJECTS)
$(CC) $(OBJECTS) -o runprog
menu.o:menu.c $(HEADERS)
$(CC) $(CFLAGS)
file1.o:file1.c $(HEADERS)
$(CC) $(CFLAGS)
file2.o:file2.c $(HEADERS)
$(CC) $(CFLAGS)
file3.o:file3.c $(HEADERS)
$(CC) $(CFLAGS)
file4.o:file4.c $(HEADERS)
$(CC) $(CFLAGS)
clean:rm -f *.o runprog
The clean target has its code in the place of dependencies. Also, your code uses spaces instead of tabs. Additionally, you forgot to add the .c files to the CC command lines. Moreover, you can simplify all the rules to
CFLAGS = -ansi -Wall -pedantic
HEADERS = menu.h file1.h file2.h file3.h file4.h
OBJECTS = menu.o file1.o file2.o file3.o file4.o
CC = gcc
all:runprog
runprog:$(OBJECTS)
$(CC) $(OBJECTS) -o runprog
%.o: %.c $(HEADERS)
$(CC) -c -o $# $< $(CFLAGS)
clean:
rm -f *.o runprog

How to use makefile to compile all sources (some only to object files)?

I'm getting an "undefined reference to main" error on one of my files when trying to compile. I know this is because this file doesn't have a main method. This is just an implementation file for some helper methods, so I only want it compiled to an object file not an executable. I know how to do this if I explicitly tell the makefile what to do for each file, but I'm trying to write a makefile that will compile all of my sources at once. I tried using the -c flag, but then it compiled all of my files to only object files rather than executables. How in the world do I do this?
Here it is:
CC = gcc
CFLAGS = -g -Wall
SRCS = ./src/server.c ./src/client_slave.c ./src/sockaddrAL.c
EXECS = ./bin/server ./bin/client_slave
OBJS = $(SRCS:.c=.o)
all: clean $(SRCS) server client
server: $(OBJS)
$(CC) $(CFLAGS) ./src/server.o -o ./bin/server
client: $(OBJS)
$(CC) $(CFLAGS) ./src/client_slave.o -o ./bin/client_slave
.c.o:
$(CC) $(CFLAGS) -c $< -o $#
clean:
#rm -f $(EXECS) $(OBJS)
You should add the -c flag to the rule that builds .o files (your .c.o suffix rule) and not add it to the rule that builds the executables (the $(EXECS) rule).
CC = gcc
CFLAGS = -g -Wall
EXECS = ./bin/server ./bin/client_slave
all: $(EXECS)
./bin/%: ./src/%.o ./src/sockaddrAL.o
$(CC) $(CFLAGS) -o $# $^
.c.o:
$(CC) $(CFLAGS) -c $< -o $#
clean:
#rm -f $(EXECS) $(OBJS)
You didn't show sockAddrAL at all in your question so I assumed it belonged in both executables. Also note that the above syntax assumes GNU make. If you want to use only features available in POSIX standard make you pretty much have to write it all out.
Let implicit rules be your friend. Your entire Makfefile should just be:
CC = clang
CFLAGS = -O0 -g -Wall
SRCS = server.c client_slave.c sockaddrAL.c
OBJS = $(SRCS:.c=.o)
EXECS = server
server: $(OBJS)
clean:
#rm -f $(EXECS) $(OBJS)
Invoke it from the src directory.

Resources