Как мне сделать Makefile для перекомпиляции только измененных файлов? - PullRequest
54 голосов
/ 19 октября 2011

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

Мои файлы:

main.c
a_functions.c

, где main.c включает main.h и a_functions.c включает a.h

Вот мой make-файл:

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)

Изменение make-файла в соответствии с предложениями, похоже, имеет ту же проблему: *

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 ]

75 голосов
/ 19 октября 2011

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

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

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

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. Я предлагаю это:

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

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

    %.o: %.c
        $(CC) $< $(CFLAGS) -o $@
    
11 голосов
/ 19 октября 2011

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

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

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

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

Например, main.c из:

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