Comment puis-je avoir un Makefile qui reconstruit automatiquement les fichiers source qui incluent un fichier d'en-tête modifié? (En C / C++)
j'ai le makefile suivant que j'utilise pour construire un programme (un noyau, en fait) sur lequel je travaille. C'est à partir de zéro et j'apprends sur le processus, donc ce n'est pas parfait, mais je pense que c'est assez puissant à ce stade pour mon niveau d'expérience de l'écriture de makefiles.
AS = nasm
CC = gcc
LD = ld
TARGET = core
BUILD = build
SOURCES = source
INCLUDE = include
ASM = assembly
VPATH = $(SOURCES)
CFLAGS = -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions
-nostdinc -fno-builtin -I $(INCLUDE)
ASFLAGS = -f elf
#CFILES = core.c consoleio.c system.c
CFILES = $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
SFILES = assembly/start.asm
SOBJS = $(SFILES:.asm=.o)
COBJS = $(CFILES:.c=.o)
OBJS = $(SOBJS) $(COBJS)
build : $(TARGET).img
$(TARGET).img : $(TARGET).elf
c:/python26/python.exe concat.py stage1 stage2 pad.bin core.elf floppy.img
$(TARGET).elf : $(OBJS)
$(LD) -T link.ld -o $@ $^
$(SOBJS) : $(SFILES)
$(AS) $(ASFLAGS) $< -o $@
%.o: %.c
@echo Compiling $<...
$(CC) $(CFLAGS) -c -o $@ $<
#Clean Script - Should clear out all .o files everywhere and all that.
clean:
-del *.img
-del *.o
-del assembly*.o
-del core.elf
mon principal problème avec ce makefile est que lorsque je modifie un fichier d'en-tête qu'un ou plusieurs fichiers C incluent, les fichiers C ne sont pas reconstruits. Je peux arranger ça assez facilement en ayant tout de mes fichiers d'en-tête sont des dépendances pour tous mes fichiers C, mais cela provoquerait effectivement une reconstruction complète du projet chaque fois que j'ai changé/ajouté un fichier d'en-tête, qui ne serait pas très gracieux.
ce que je veux, c'est seulement pour les fichiers C que inclue le fichier d'en-tête que je change pour être reconstruit, et pour que l'ensemble du projet soit à nouveau lié. Je peux faire le lien En faisant en sorte que tous les fichiers d'en-tête soient des dépendances de la cible, mais je ne peux pas comprendre comment pour rendre les fichiers C invalides lorsque leurs fichiers d'en-tête inclus sont plus récents.
J'ai entendu que GCC a quelques commandes pour rendre cela possible (de sorte que le makefile peut d'une manière ou d'une autre comprendre quels fichiers doivent être reconstruits) mais je ne peux pas pour la vie de moi Trouver un exemple d'implémentation réelle à regarder. Quelqu'un peut-il poster une solution qui permettra ce comportement dans un makefile?
EDIT: je dois clarifier, je suis familier avec le concept de mettre le cibles individuelles et ayant chaque cible.o exiger de fichiers d'en-tête. Cela me demande d'éditer le makefile chaque fois que j'inclus un fichier d'en-tête quelque part, ce qui est un peu pénible. Je suis à la recherche d'une solution qui peut dériver les dépendances du fichier d'en-tête de ses propres, que je suis assez certain que j'ai vu dans d'autres projets.
9 réponses
comme déjà indiqué ailleurs sur ce site, voir cette page: http://make.paulandlesley.org/autodep.html
En bref, gcc peut créer automatiquement .D des fichiers de dépendances pour vous, qui sont des fragments de mini makefile contenant les dépendances de la .c fichier que vous avez compilé. Chaque fois que vous changez le .c fichier et de les compiler, de les .le fichier d sera mis à jour.
en plus d'ajouter le drapeau-M à gcc, vous aurez besoin d'inclure .les fichiers d dans le makefile (comme Chris a écrit ci-dessus). Il y a des problèmes plus compliqués dans la page qui sont résolus en utilisant sed, mais vous pouvez les ignorer et faire un "make clean" pour effacer les .d files chaque fois que make se plaint de ne pas être en mesure de construire un fichier d'en-tête qui n'existe plus.
vous pouvez ajouter une commande 'make depend' comme d'autres l'ont indiqué, mais pourquoi ne pas obtenir de gcc pour créer des dépendances et compiler en même temps:
DEPS := $(COBJS:.o=.d)
-include $(DEPS)
%.o: %.c
$(CC) -c $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$@) -o $@ $<
le paramètre'- MF ' spécifie un fichier pour stocker les dépendances.
le tiret au début de '-include' indique à Make de continuer quand le .le fichier d n'existe pas (par exemple sur la première compilation).
Note il semble y avoir un bug dans gcc concernant l'option-O. Si vous définissez le nom de fichier de l'objet pour dire obj/_file__c.o
alors le _file_.d
généré contiendra toujours _file_.o
, pas obj/_file_c.o
.
c'est l'équivalent de la réponse de Chris Dodd , mais utilise une convention de nommage différente (et par coïncidence ne nécessite pas la magie sed
. Copié de une copie ultérieure de .
si vous utilisez un compilateur GNU, le compilateur peut assembler une liste de dépendances pour vous. Fragment de Makefile:
depend: .depend
.depend: $(SOURCES)
rm -f ./.depend
$(CC) $(CFLAGS) -MM $^>>./.depend;
include .depend
Il y a aussi l'outil makedepend
, mais je n'ai jamais il aimait autant que gcc -MM
vous devrez faire des cibles individuelles pour chaque fichier C, puis énumérer le fichier d'en-tête comme une dépendance. Vous pouvez toujours utiliser vos cibles génériques, et placer les dépendances .h
après, comme ceci:
%.o: %.c
@echo Compiling $<...
$(CC) $(CFLAGS) -c -o $@ $<
foo.c: bar.h
# And so on...
au-delà de ce que @mipadi a dit, Vous pouvez également explorer l'utilisation de l'option -M
' pour générer un enregistrement des dépendances. Vous pourriez même les générer dans un fichier séparé (peut-être " dépend.mk') que vous incluez ensuite dans le makefile. Ou vous pouvez trouver un " make depend
règle " qui édite le fichier makefile avec les bonnes dépendances (Google termes: "ne pas supprimer cette ligne" et dépendent).
fondamentalement, vous devez dynamiquement créer les règles makefile pour reconstruire les fichiers objet lorsque les fichiers d'en-tête changent. Si vous utilisez gcc et gnumake, c'est assez facile; il suffit de mettre quelque chose comme:
$(OBJDIR)/%.d: %.c
$(CC) -MM -MG $(CPPFLAGS) $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(@D)/.o $(@D)/.d:,' >$@
ifneq ($(MAKECMDGOALS),clean)
include $(SRCS:%.c=$(OBJDIR)/%.d)
endif
dans votre makefile.
aucune des réponses n'a fonctionné pour moi. Par exemple: La réponse de Martin Fido suggère que gcc peut créer des fichiers de dépendances, mais quand j'ai essayé de générer des fichiers d'objets vides (zéro bytes) pour moi sans aucun avertissement ou erreur. Il peut être un bug de gcc. Je suis sur
$ gcc -- version gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16)
alors voici mon Makefile complet qui fonctionne pour moi; c'est une combinaison de solutions + quelque chose cela n'a été mentionné par personne d'autre (par exemple "règle de remplacement du suffixe" spécifiée sous .cc.o:):
CC = g++
CFLAGS = -Wall -g -std=c++0x
INCLUDES = -I./includes/
# LFLAGS = -L../lib
# LIBS = -lmylib -lm
# List of all source files
SRCS = main.cc cache.cc
# Object files defined from source files
OBJS = $(SRCS:.cc=.o)
# # define the executable file
MAIN = cache_test
#List of non-file based targets:
.PHONY: depend clean all
## .DEFAULT_GOAL := all
# List of dependencies defined from list of object files
DEPS := $(OBJS:.o=.d)
all: $(MAIN)
-include $(DEPS)
$(MAIN): $(OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)
#suffix replacement rule for building .o's from .cc's
#build dependency files first, second line actually compiles into .o
.cc.o:
$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$@) $<
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
clean:
$(RM) *.o *~ $(MAIN) *.d
avis que j'ai utilisé .cc .. Le Makefile ci-dessus est facile à régler .c fichiers.
également important de noter l'importance de ces deux lignes:
$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$@) $<
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
donc gcc est appelé une fois pour construire un fichier de dépendance d'abord, puis compile réellement un .fichier cc. Et ainsi de suite pour chaque fichier source.
solution plus simple: il suffit d'utiliser le Makefile pour avoir le .c pour .o la règle de compilation dépend du(DES) fichier (s) d'en-tête et de tout ce qui est pertinent dans votre projet en tant que dépendance.
par exemple, dans le Makefile quelque part:
DEPENDENCIES=mydefs.h yourdefs.h Makefile GameOfThrones.S07E01.mkv
::: (your other Makefile statements like rules
::: for constructing executables or libraries)
# Compile any .c to the corresponding .o file:
%.o: %.c $(DEPENDENCIES)
$(CC) $(CFLAGS) -c -o $@ $<
je crois que la commande mkdep
est ce que vous voulez. Il fait des analyses .c fichiers pour les lignes #include
et crée une arborescence de dépendances pour elles. Je crois que les projets Automake/Autoconf l'utilisent par défaut.