2010-07-02 3 views
2

J'ai un petit projet qui construit un certain nombre de cibles à partir des mêmes fichiers source. Les cibles nécessitent la construction des fichiers sources avec différents drapeaux de compilation. C'est en fait sur cygwin donc je vais utiliser cela comme exemple concret bien que je suppose que c'est un problème générique.Comment faire pour s'assurer que les fichiers objet sont compilés avec les paramètres corrects dans Makefile avec plusieurs cibles MAKE

Donc, ce serait un Makefile exemple:

a: CFLAGS = 

a: a.o c.o 

b: CFLAGS = -mno-cygwin 

b: b.o c.o 

Cela fonctionne en principe, la construction d'une compilera avec unset CFLAGS et la construction b compilera avec CFLAGS mis à -mno-Cygwin. Mais seulement si c.o n'existe pas déjà.

Ce faisant

> make a b 

dans un répertoire vierge d'abord compiler et a.c C.C en utilisant un CFLAGS vide. Ensuite, il va essayer de construire b en utilisant CFLAGS = -mno-cygwin. Mais comme c.o existe déjà, il ne recompilera pas c.c, ce qui se traduira par des erreurs de liens puisque les fichiers objets doivent avoir le même paramétrage de ce flag.

Encore une fois, le drapeau cygwin n'est qu'un exemple concret, et je cherche une solution générique.

Ce que j'ai essayé est d'introduire un objectif supplémentaire de vérifier les CFLAGS actuels et supprimer tous les fichiers d'objets si elle ne correspond pas à:

ARCH = `echo $(CFLAGS)` 
checkTarget: 
[email protected] test "`cat .arch`" != "$(ARCH)"; then \ 
    rm *.o; \ 
    /bin/echo -n $(ARCH) > .arch; \ 
fi 

Insérer cet objectif comme une dépendance pour les deux cibles assure que tous les objets les fichiers sont recompilés si nécessaire.

a: CFLAGS = 

a: checkTarget a.o c.o 

b: CFLAGS = -mno-cygwin 

b: checkTarget b.o c.o 

Cette recompile cependant chaque fichier objet, ce qui est inutile, et devient un problème dans un projet plus vaste.

Y a-t-il une meilleure façon de procéder?

EDIT: Dans les commentaires à la réponse unique inclus un indice que vous pourriez faire les fichiers objet dépendent du contenu du CFLAGS. Je n'arrive pas à comprendre comment faire cela, sauf les transférer dans un fichier temporaire et les comparer aux précédents, puis les copier sur un fichier dépendant. N'y a-t-il pas de meilleur moyen?

Répondre

0

Bien là où quelques suggestions sur la façon de faire ce que j'ai d'abord demandé here (comme souligné par slowdog), j'ai pris la décision de prendre un peu plus loin le schéma des noms différents de Beta et de mettre tous les objets pour les différentes variantes dans les sous-répertoires suivant la description dans Beta dans sa réponse à this question.

En substance qui a fait mon Makefile ressembler à:

A : AOBJDIR = .a 
AOBJECTS = $(addprefix $(AOBJDIR)/,$(ASRCS:.c=.o)) 

$(AOBJECTS): $(AOBJDIR)/%o: %.c 
    $(CC) $(CFLAGS) -MMD -o [email protected] -c $< 

$(AOBJDIR) : 
    @mkdir $(AOBJDIR) 

-include $(AOBJECTS:.o=.d) 

a: $(AOBJDIR) $(AOBJECTS) 
    $(LINK) ... 

Ainsi, les premiers noms de partie un sous-répertoire à utiliser pour les fichiers objet de « a » et crée une liste de fichiers d'objets dans ce répertoire en convertissant le les noms de fichiers source et en ajoutant le préfixe de sous-répertoire. Puis suit la règle par défaut pour ces fichiers d'objets (avec la génération de dépendances lancée pour faire bonne mesure).

Ensuite, deux vérifient que le sous-répertoire existe et que les informations de dépendance sont incluses.

Enfin la règle de lien avec une dépendance supplémentaire sur le sous-répertoire lui-même pour s'assurer qu'il est créé s'il n'existe pas.

Ce bloc peut être répété pour b, dans mon exemple, en échangeant tous les a. Donc, si seulement je pouvais trouver comment emballer ce bloc en quelque chose de plus général qui peut être paramétré, je serais heureux.

2

Ce dont nous avons besoin ici est de deux (ou plus) versions de c.o, compilées avec différents drapeaux et d'être liées dans différents exécutables. Vous pouvez le faire avec des noms contrived comme c_for_a.o, mais il est plus net pour les garder dans des répertoires différents, for_a/ et for_b/:

a for_a/%: CFLAGS = 

a: a.o for_a/c.o 

b for_b/%: CFLAGS = -mno-cygwin 

b: b.o for_b/c.o 

(Si cela est clair que je peux remplir le reste du Makefile.)

EDIT:
Si vous ne souhaitez pas conserver multiactivités « c.o, vous devrez recompiler parfois co. Il y a une petite amélioration possible sur l'idée checkTarget.

Lorsque vous construisez une cible comme b et c.o existe déjà, il importe que ce c.o a été construit avec le CFLAGS adapté à b, et que vous utilisez checkTarget pour enregistrer ces informations. Mais vous ne vous souciez pas de ce que CFLAGS ont été utilisés, seulement s'ils étaient bCFLAGS. Donc, vous ne devez pas enregistrer quoi que ce soit dans le fichier checkTarget, mettez à jour juste lorsque vous créez une nouvelle cible:

a: CFLAGS = 

b: CFLAGS = -mno-cygwin 

# You may be able to combine the a and b rules... 
a: a.o c.o checkTarget 
    # build c.o 
    touch checkTarget 
    # build the target 

b: b.o c.o checkTarget 
    # build c.o 
    touch checkTarget 
    # build the target 

# Need this to create checkTarget the first time 
checkTarget: 
    @touch [email protected] 
+0

Bonne réponse. Si le projet est volumineux, disons 50 fichiers objets, cela fonctionnera si le nombre de fichiers à recompiler (c.c dans l'exemple) est petit. Si la majorité exigeait une recompilation, cette stratégie deviendrait maladroite je pense. Des idées pour ce scénario? – thoni56

+0

@ Thomas Nilsson: cela dépend de ce que vous essayez d'optimiser. Si vous ne voulez pas recompiler 'c.c' plus que nécessaire, vous devez en conserver différentes versions, et c'est le meilleur moyen. Si vous ne voulez pas garder plusieurs 'c.o', mais que vous voulez recompiler' c.o' seulement quand vous devez, il y a une autre façon, une légère amélioration sur votre checkTarget. Je vais modifier ma réponse pour l'inclure. – Beta

+0

Hmmm, si je comprends bien, checkTarget est un horodatage de sorte que par exemple. Si vous construisez b mais que b.o et c.o existent, checkTarget déclenchera toujours la règle de construction. Ensuite, dans les commandes, vous êtes en train de câbler la construction de c.o selon le CFLAGS. Si c'est votre intention, je ne suis pas entièrement satisfait (mais encore une fois cela pourrait ne pas être possible ;-), parce que je devrais constamment mettre à jour les commandes de construction explicites lorsque mes exigences ont changé. J'espérais pouvoir faire en sorte que chaque% .o dépende des CFLAGS utilisés pour le compiler, et une compilation ne serait déclenchée que si le CFLAGS n'était pas le même. – thoni56

Questions connexes