Как сделать Makefile для перекомпиляции только измененных файлов?

Я немного боролся, чтобы получить make для компиляции только файлы, которые были отредактированы. Однако у меня не было большого успеха, и все файлы перекомпилируются. Может кто-нибудь объяснить мне, почему?

Мои файлы:

main.c
a_functions.c

здесь main.c включает в себя main.h и a_functions.c включает в себя а.ч

вот мой 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)

изменение файла makefile в соответствии с предложениями кажется чтобы иметь ту же проблему::

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

2 ответов


конкретная проблема, о которой вы говорите -- Make rebuilds program1 (путем связывания объектов), даже если ничего не изменилось - в этом правиле:

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

цель этого правила составляет program, и Make предполагает, что это файл. Но поскольку такого файла нет, каждый раз, когда вы запускаете Make, Make думает, что этот файл нужно перестроить, и выполняет правило. Я предлагаю следующее:--18-->

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

или лучше, это:

program1: a_functions.o main.o
    gcc $^ -o $@

или еще лучше это:

$(EXEC_FILE): a_functions.o main.o
    $(CC) $^ -o $@

(и не забудьте поменять all правила, чтобы соответствовать.)

еще несколько пунктов:

  1. как отметил @paxdiablo,

    a_functions.o: a_functions.c a.h
    main.o: main.c main.h
    
  2. не имеет смысла связывать эти объекты вместе, если что-то в одном (возможно main.o) вызывает что-то в другом (вероятно a_functions.o), поэтому я ожидал бы увидеть такую зависимость:

    main.o: a.h
    

    поэтому я подозреваю, что вы есть некоторые неуместные объявления.

  3. вы объявляете objects правило, но никогда не ссылайтесь на него. Таким образом, вы никогда не используете его; Make использует правило по умолчанию для %.o: %.c. Я предлагаю следующее:--18-->

    OBJECTS = a_functions.o main.o
    $(OBJECTS): %: %.c
        $(CC) $< $(CFLAGS) -o $@
    

    (в этом случае вы можете изменить $(EXEC_FILE): a_functions.o main.o to $(EXEC_FILE): $(OBJECTS).) Или просто так:

    %.o: %.c
        $(CC) $< $(CFLAGS) -o $@
    

не уверен, что это вызывает вашу конкретную проблему, но две строки:

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

определенно неверны, потому что обычно нет команды для повторного создания файла C на основе заголовка, который он включает.

C файлы не зависят от их заголовочных файлов,объекты созданный этими файлами C.

например, a main.c of:

#include <hdr1.h>
#include <hdr2.h>
int main (void) { return 0; }

будет makefile как-то например:

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

изменения:

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

в:

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

(предполагая, что a_functions.c включает в себя a.h и main.c включает в себя main.h) и попробуйте снова.

если это предположение выше неверно, вам придется сказать нам, какие файлы C включают в себя какие заголовки, чтобы мы могли сказать вам правильные правила.


если вы утверждаете, что makefile все еще строит все даже после этих изменений, вам нужно посмотреть на два вещи.

первый-это выход из ls -l на всех соответствующих файлов, так что вы можете увидеть, какие даты и время они имеют.

второй является фактическим выходом из make. Выход make -d будет особенно полезно, Так как это показывает какие файлы и даты make используется, чтобы выяснить, что делать.


С точки зрения расследования,make кажется, работает нормально в соответствии со следующей расшифровкой:

=====
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.