web-dev-qa-db-fra.com

Comment puis-je faire Makefile pour recompiler uniquement les fichiers modifiés?

J'ai eu un peu de mal à obtenir que make compile uniquement les fichiers qui ont été modifiés. Cependant, je n'ai pas eu beaucoup de succès et tous les fichiers sont recompilés. Quelqu'un peut-il m'expliquer pourquoi?

Mes fichiers sont:

main.c
a_functions.c

main.c comprend main.h et a_functions.c comprend ah

Voici mon 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)

Changer le makefile selon les suggestions semble avoir le même problème ::

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
55
Pithikos

Le problème spécifique dont vous parlez - Faites des reconstructions program1 (En reliant les objets) même lorsque rien n'a changé - est dans cette règle:

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

La cible de cette règle est program, et Make suppose qu'il s'agit d'un fichier. Mais comme il n'existe pas de fichier de ce type, chaque fois que vous exécutez Make, Make pense que ce fichier doit être reconstruit et exécute la règle. Je suggère ceci:

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

Ou mieux, ceci:

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

Ou mieux encore:

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

(Et n'oubliez pas de modifier la règle all pour qu'elle corresponde.)

Quelques autres points:

  1. Comme l'a souligné @paxdiablo,

    a_functions.o: a_functions.c a.h
    main.o: main.c main.h
    
  2. Il n'est pas logique de lier ces objets ensemble à moins que quelque chose dans l'un (probablement main.o) Appelle quelque chose dans l'autre (probablement a_functions.o), Donc je m'attendrais à voir une dépendance comme celle-ci:

    main.o: a.h
    

    Je soupçonne donc que vous avez des déclarations déplacées.

  3. Vous déclarez une règle objects, mais ne vous y référez jamais. Vous ne l'utilisez donc jamais réellement; Make utilise la règle par défaut pour %.o: %.c. Je suggère ceci:

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

    (Dans ce cas, vous pouvez changer $(EXEC_FILE): a_functions.o main.o en $(EXEC_FILE): $(OBJECTS).) Ou tout simplement ceci:

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

Je ne sais pas si cela cause votre problème spécifique, mais les deux lignes:

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

sont définitivement faux, car il n'y a généralement pas de commande pour recréer un fichier C sur la base d'un en-tête qu'il comprend.

Les fichiers C ne dépendent pas de leurs fichiers d'en-tête, contrairement aux objets créés par ces fichiers C.

Par exemple, un main.c de:

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

serait dans le makefile comme quelque chose comme:

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

Changement:

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

(en admettant que a_functions.c comprend a.h et main.c comprend main.h) et essayez à nouveau.

Si cette hypothèse ci-dessus est fausse, vous devrez nous dire quels fichiers C incluent quels en-têtes afin que nous puissions vous dire les règles correctes.


Si vous pensez que makefile est toujours en train de tout construire même après ces changements, vous devez regarder deux choses.

Le premier est la sortie de ls -l sur tous les fichiers pertinents afin que vous puissiez voir leurs dates et heures.

Le second est la sortie réelle de make. La sortie de make -d sera particulièrement utile car il affiche quels fichiers et dates make utilise pour comprendre ce qu'il faut faire.


En termes d'enquête, make semble bien fonctionner selon la transcription suivante:

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