cmakefilerecompile

How do I make Makefile to recompile only changed files?


I have been struggling a bit to get make to compile only the files that have been edited. However I didn't have much success and all the files get recompiled. Can someone explain me why?

My files are:

main.c
a_functions.c

where main.c includes main.h and a_functions.c includes a.h

Here is my makefile:

CC=gcc
CFLAGS=-Wall -I. -c
EXEC_FILE=program1


all: program

a_functions.o: a_functions.c
a_functions.c: a.h
main.o: main.c
main.c: main.h

objects: a_functions.c main.c
    $(CC) a_functions.c main.c $(CFLAGS)

program: a_functions.o main.o
    $(CC) a_functions.o main.o -o $(EXEC_FILE)

Changing the makefile as per suggestions seems to have the same problem::

all: program

a_functions.o: a_functions.c a.h
    gcc a_functions.c -c

main.o: main.c main.h
    gcc main.c -c

program: a_functions.o main.o
    gcc a_functions.o main.o -o program1

Solution

  • 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:

    1. As @paxdiablo pointed out,

      a_functions.o: a_functions.c a.h
      main.o: main.c main.h
      
    2. It doesn't make sense to link these objects together unless something in one (probably main.o) calls something in the other (probably a_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.

    3. 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 $@