I just started to learn the C programming language in my University. We have a task to create a Makefile that uses the executable program (battle in my case) and compiles only when is necessary. My problem with it is that it compiles every time I use the make command and it does not show "Is up to date" as I want to. I have 2 objects to compile (quest.o and thorgrim.o and only quest.o has to be created since we have the thorgrim.o already) into "battle". Here's my code:
CC=gcc
EXE=battle
CFLAGS=-Wall
build: run
run: quest.o
$(CC) $^ thorgrim.o -o $(EXE)
./$(EXE)
quest.o: quest.c
$(CC) -c $^ -o $@
clean: rm -rf quest.o $(EXE)
What am I doing wrong? I want it to compile once and then show up to date if I won't touch the quest.c.
Seeing as you're new at this, I'll walk you through it, so you can learn to do it right the first time. There's a lot of little details, that a lot of people end up missing, so hopefully this will give you a good reference:
First, lets start by defining your objects
OBJS := quest.o thorgrim.o
you can now create a pattern rule:
%.o: %.c
$(CC) $(CFLAGS) -MD -MP $< -c -o $@
The first line of this rule %.o:%.c
says that anything ending with a .o
depends on a file with the same name ending in .c
. Doing this prevents you from from having to write a separate rule for every object file. Notice that there is a default pattern rule to this effect, but we'll not go into that here.
Next, you call $(CC)
with $(CFALGS)
. Notice that $@
now represents the name of the .o file you are generating, and $<
represents the first dependency of the object (the .c file in this case).
The -MD
and -MP
are used to automatically generate dependency files -- for each .c
file it will also create a .d
file, which lists the dependencies (.h
files) that your source requires to build. You have to -include
the dependency files for it to work. (see https://gcc.gnu.org/onlinedocs/gcc-4.3.1/gcc/Preprocessor-Options.html for more details on exactly what these do). This way, if you modify a header file, it will automatically rebuild the necessary .o
files. Having said that, you have to include those .d files in your makefile:
-include $(OBJS:.o=.d)
This will include the .d files as if someone cut and paste the code into your makefile. The $(OBJS:.o=.d)
simply tells make to take the variable OBJS
and replace all the .o
's with .d
's. Notice the -
before the include. This tells make not to worry if the file doesn't exist (as will be the case on your first build ...).
Ok, now that you've got your .o files built, you need to build your program:
$(EXE): $(OBJS)
$(CC) $^ -o $@
Add a default rule and comments, and you're done. So, in summary, your makefile will look something like:
CC:=gcc
EXE:=battle
CFLAGS:=-Wall
OBJS:=quest.o thorgrim.o
%.o: %.c
$(CC) $(CFLAGS) -MD -MP $< -c -o $@
$(EXE): $(OBJS)
$(CC) $^ -o $@
clean:
rm -f $(OBJS) $(EXE)
-include $(OBJS:.o=.d)
EDIT: forgot the clean rule -- adding that.
The run target depends on files, but the build rule does not produce a file named 'run'. A better idea is to do something along these lines:
run: $(EXE)
./$(EXE)
$(EXE): $(OBJ)
$(CC) $(CFLAGS) -o $@ $+
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