How do I make Makefile to recompile only changed files?
The specific problem you're talking about -- Make rebuilds program1
(by relinking the objects) even when nothing has changed -- is in this rule:
program: a_functions.o main.o
gcc a_functions.o main.o -o program1
The target of this rule is program
, and Make assumes that it is a file. But since there is no such file, every time you run Make, Make thinks that this file needs to be rebuilt, and executes the rule. I suggest this:
program1: a_functions.o main.o
gcc a_functions.o main.o -o program1
Or better, this:
program1: a_functions.o main.o
gcc $^ -o $@
Or better still this:
$(EXEC_FILE): a_functions.o main.o
$(CC) $^ -o $@
(And don't forget to change the all
rule to match.)
A few other points:
-
As @paxdiablo pointed out,
a_functions.o: a_functions.c a.h main.o: main.c main.h
-
It doesn't make sense to link these objects together unless something in one (probably
main.o
) calls something in the other (probablya_functions.o
), so I would expect to see a dependency like this:main.o: a.h
So I suspect that you have some misplaced declarations.
-
You declare an
objects
rule, but never refer to it. So you never actually use it; Make uses the default rule for%.o: %.c
. I suggest this:OBJECTS = a_functions.o main.o $(OBJECTS): %.o: %.c $(CC) $< $(CFLAGS) -o $@
(In which case you can change
$(EXEC_FILE): a_functions.o main.o
to$(EXEC_FILE): $(OBJECTS)
.) Or just this:%.o: %.c $(CC) $< $(CFLAGS) -o $@
Not sure if this is causing your specific problem but the two lines:
a_functions.c: a.h
main.c: main.h
are definitely wrong, because there's generally no command to re-create a C file based on a header it includes.
C files don't depend on their header files, the objects created by those C files do.
For example, a main.c
of:
#include <hdr1.h>
#include <hdr2.h>
int main (void) { return 0; }
would be in the makefile
as something like:
main.o: main.c hdr1.h hdr2.h
gcc -c -o main.o main.c
Change:
a_functions.o: a_functions.c
a_functions.c: a.h
main.o: main.c
main.c: main.h
to:
a_functions.o: a_functions.c a.h
main.o: main.c main.h
(assuming that a_functions.c
includes a.h
and main.c
includes main.h
) and try again.
If that assumption above is wrong, you'll have to tell us what C files include what headers so we can tell you the correct rules.
If your contention is that the makefile
is still building everything even after those changes, you need look at two things.
The first is the output from ls -l
on all relevant files so that you can see what dates and times they have.
The second is the actual output from make
. The output of make -d
will be especially helpful since it shows what files and dates make
is using to figure out what to do.
In terms of investigation, make
seems to work fine as per the following transcript:
=====
pax$ cat qq.h
#define QQ 1
=====
pax$ cat qq.c
#include "qq.h"
int main(void) { return 0; }
=====
pax$ cat qq.mk
qq: qq.o
gcc -o qq qq.o
qq.o: qq.c qq.h
gcc -c -o qq.o qq.c
=====
pax$ touch qq.c qq.h
=====
pax$ make -f qq.mk
gcc -c -o qq.o qq.c
gcc -o qq qq.o
=====
pax$ make -f qq.mk
make: `qq' is up to date.
This very late after the fact, and actually it's based on paxdiablo's excellent answer, but while experimenting i found that you don't need separate targets for each .o file unless you're doing something clever.
So for my makefile:
all: program
program: a_functions.o main.o
gcc a_functions.o main.o -o program
clean:
rm -f *.o
rm -f program
In make 4.1 it compiles the .o files automatically, you don't have to do anything if your .o files have the same names as your source files. So, it will go and hunt for a_functions.c, a_functions.h, main.h and main.c automagically. If you don't have the expected source code names, then you'll get an error like:
make: *** No rule to make target 'a_functions.o', needed by 'program'. Stop.
I have also added a "clean" target for you. "Clean" is useful if you need to release your software as source code, or you just want to remove all the compiled object files and / or binaries.
And this is all you need to do.
Save this to "Makefile" and run:
$ make
to build your binary. And
$ make clean
to clean up the compiled objects and binaries in your code.