2012-02-08 3 views
2

Je le Makefile suivant et je veux créer « debug » et des cibles « optimales » qui affectent les valeurs CPPFLAGS et CFLAGS, comme ceci:Makefile dynamique affectation de variable

include Makefile.inc 

DIRS = applib 
EXE_APPFS  = appfs 
EXE_APPMOUNT = appmount 
EXE_APPINSPECT = appinspect 
EXE_APPCREATE = appcreate 
BUILD_APPFS  = 
BUILD_APPMOUNT = -DAPPMOUNT 
OBJS_APPFS  = main.o appfs.o 
OBJS_APPMOUNT = main.o appmount.o 
OBJS_APPINSPECT = appinspect.o 
OBJS_APPCREATE = appcreate.o 
OBJLIBS = libapp.a 
LIBS = -L. -lpthread -lstdc++ -ldl -lrt -largtable2 -lm ./libapp.a  /usr/lib64/libfuse.a 

# Optimization settings. 
debug: CPPFLAGS=$(CPPFLAGS_DEBUG) 
debug: CFLAGS=$(CFLAGS_DEBUG) 
debug: 
    @true 

optimal: CPPFLAGS=$(CPPFLAGS_OPTIMAL) 
optimal: CFLAGS=$(CFLAGS_OPTIMAL) 
optimal: 
    @true 

appfs: appfs.o $(OBJLIBS) 
    @echo "stuff is done here" 

appmount: appmount.o $(OBJLIBS) 
    @echo "stuff is done here" 

appmount_optimal: optimal appmount 

Le problème que je vais avoir est que les affectations de variables dans "debug" et "optimal" ne se reportent pas à d'autres cibles (bien que si je mets @echo $ (CPPFLAGS) à l'intérieur de optimal qui fonctionne). Ni «make appmount optimal» ni «make appmount_optimal» ne me permet d'obtenir les résultats que j'attends.

Sûrement il existe un moyen de définir CPPFLAGS et CFLAGS selon que vous voulez ou non le débogage, non?

Répondre

6

Si vous utilisez GNU make, vous avez deux options (en plus de l'invocation make récursive, qui présente les problèmes décrits ci-dessus).

La première option consiste à utiliser des variables spécifiques à la cible. Vous les utilisez dans votre exemple original:

debug: CPPFLAGS=$(CPPFLAGS_DEBUG) 
debug: CFLAGS=$(CFLAGS_DEBUG) 

optimal: CPPFLAGS=$(CPPFLAGS_OPTIMAL) 
optimal: CFLAGS=$(CFLAGS_OPTIMAL) 

La chose vous manque est que les variables spécifiques à la cible sont héritées par leurs conditions. Vous devez donc déclarer les prérequis de "debug" et "optimal" (ils n'ont pas besoin d'avoir des recettes elles-mêmes, en fait, elles peuvent être déclarées .PHONY). Ainsi, par exemple:

debug: CPPFLAGS=$(CPPFLAGS_DEBUG) 
debug: CFLAGS=$(CFLAGS_DEBUG) 
debug: appfs appmount 

optimal: CPPFLAGS=$(CPPFLAGS_OPTIMAL) 
optimal: CFLAGS=$(CFLAGS_OPTIMAL) 
optimal: appfs appmount 

Maintenant, si vous exécutez « make debug » il va construire deux AppFS et appmount avec les paramètres de débogage pour CPPFLAGS et CFLAGS; Si vous exécutez "make optimal", il utilisera les paramètres optimaux.

Cependant, cela a le même inconvénient que l'invocation récursive de make; si vous lancez "make appfs" directement, aucun des paramètres ne sera utilisé; les variables spécifiques à la cible sont héritées du (des) parent (s) qui ont conduit à la construction de la cible dans cet appel de make. Si aucune de ces cibles n'est dans la liste des cibles parentes, leurs variables spécifiques à la cible ne seront pas utilisées.

La deuxième option, qui vous donne à peu près exactement l'interface que vous recherchez, consiste à utiliser la variable MAKECMDGOALS pour décider si l'utilisateur a demandé des versions optimales ou de débogage. Par exemple quelque chose comme ceci:

CPPFLAGS_debug = <debug CPPFLAGS> 
CFLAGS_debug = <debug CFLAGS> 

CPPFLAGS_optimal = <optimal CPPFLAGS> 
CFLAGS_optimal = <optimal CFLAGS> 

STYLE := $(firstword $(filter debug optimal,$(MAKECMDGOALS))) 
$(if $(STYLE),,$(error No style "debug" or "optimal" set)) 

CPPFLAGS = $(CPPFLAGS_$(STYLE)) 
CFLAGS = $(CFLAGS_$(STYLE)) 

debug optimal: 
.PHONY: debug optimal 

Ou si vous préférez, vous pouvez choisir un comportement par défaut si l'on est pas donné, au lieu de jeter une erreur; ce choisit « debug » par défaut par exemple:

STYLE := $(firstword $(filter optimal,$(MAKECMDGOALS)) debug) 

Cependant, il est important de noter que la raison pour laquelle cela semble difficile à faire est que ce que vous demandez est fondamentalement viciée. Suggérer qu'un seul fichier dérivé dans un répertoire doit être construit de l'une des deux façons différentes en fonction d'un paramètre de temps de construction pose des problèmes. Comment savez-vous quelle variante a été utilisée en dernier? Supposons que vous exécutiez make avec l'optimisation, que vous modifiiez certains fichiers, puis que vous exécutiez à nouveau cette fois avec le débogage ... maintenant certains de vos fichiers sont optimisés et d'autres sont débogués.

La meilleure façon de gérer différentes variantes de construction de code est de s'assurer que les fichiers dérivés sont uniques. Cela signifie que les cibles de débogage sont écrites dans un répertoire et que les cibles optimisées sont écrites dans un répertoire différent. Une fois que vous faites cette distinction, le reste tombe facilement: vous utilisez simplement les indicateurs de débogage lorsque vous écrivez les règles pour les cibles de débogage et les indicateurs optimaux lorsque vous écrivez les règles pour les cibles optimisées.

+0

Il devait y avoir un meilleur moyen - et «hérité des prérequis» est le bit que je ne connaissais pas. –

+0

Très bien, j'utilise cette solution maintenant (même si c'est plus spécifique à GNU make). J'ai également ajouté "$ (si $ (filtre 1, $ (mots $ (MAKECMDGOALS))), $ (erreur $ (ERROR_NOTARGET)),)" après la vérification de style pour s'assurer que l'utilisateur fournit une cible de construction (par exemple "). –

2

Un horrible mais technique modérément efficace est:

# Optimization settings. 
debug: 
    +$(MAKE) CPPFLAGS="$(CPPFLAGS_DEBUG)" CFLAGS="$(CFLAGS_DEBUG)" 

optimal: 
    +$(MAKE) CPPFLAGS="$(CPPFLAGS_OPTIMAL)" CFLAGS="$(CFLAGS_OPTIMAL)" 

Cela signifie que make debug reinvokes make avec les drapeaux de déboguage sur la ligne de commande, et make optimal reinvokes make avec les drapeaux optimaux fixés sur la ligne de commande.

Ceci est loin d'être parfait; cela signifie que la règle par défaut sera exécutée lorsque make est réinvocé.

Vous pouvez modifier cela avec:

# Optimization settings. 
debug: 
    +$(MAKE) CPPFLAGS="$(CPPFLAGS_DEBUG)" CFLAGS="$(CFLAGS_DEBUG)" debug_build 

optimal: 
    +$(MAKE) CPPFLAGS="$(CPPFLAGS_OPTIMAL)" CFLAGS="$(CFLAGS_OPTIMAL)" optimal_build 

Cela va maintenant deux cibles de construction différentes pour la version de débogage et la construction optimale. D'autres règles, telles que clean ou depend n'obtiennent pas le traitement spécial. La notation + sur les lignes de commande est la manière de POSIX de dire «exécuter cette règle même sous make -n», ce qui est probablement ce que vous voulez. La notation $(MAKE) peut également obtenir le même effet. Si votre make n'aime pas les signes +, essayez de les supprimer.


Cela ne me laisse pas faire « make debug appmount » pour construire la cible de appmount en mode débogage ne se il? Il ne permet que 'make debug' qui construit toutes les cibles dans le débogage.

Vous avez raison; C'est le genre de raison pour laquelle ce n'est pas parfait. Si vous avez de la chance, quelqu'un d'autre va trouver une meilleure solution. Il y a une façon légèrement sournoise à plus ou moins obtenir ce que vous voulez:

BUILD_TARGET = all 

# Optimization settings. 
debug: 
    +$(MAKE) CPPFLAGS="$(CPPFLAGS_DEBUG)" CFLAGS="$(CFLAGS_DEBUG)" $(BUILD_TARGET) 

optimal: 
    +$(MAKE) CPPFLAGS="$(CPPFLAGS_OPTIMAL)" CFLAGS="$(CFLAGS_OPTIMAL)" $(BUILD_TARGET) 

Maintenant lorsque vous exécutez make debug, il recommencera et construire la cible all par défaut avec les options de débogage. Mais, vous pouvez changer cela avec:

make optimal BUILD_TARGET="appmount totherprog" 

Ceci construira les deux cibles nommées avec les indicateurs optimaux. La ligne de commande initiale n'est pas terriblement élégante, mais elle vous mènerait à votre destination - à peu près. Le choix judicieux des valeurs par défaut et la possibilité de les remplacer devraient vous permettre d'aller où vous voulez.

+0

Cela ne me permet pas de faire «make debug appmount» pour construire la cible appmount en mode debug mais le fait-il? Il ne permet que 'make debug' qui construit toutes les cibles dans le débogage. –

+0

Très bien, je vais marquer cela comme la réponse car c'est ce que j'utilise (puisque la requête d'origine n'est pas réellement possible dans make). –

+0

Il existe peut-être une meilleure façon de le faire, surtout si vous connaissez suffisamment les fonctionnalités spéciales de GNU make et qu'il est acceptable de l'utiliser. Clairement, vous utilisez GNU make. Je n'ai pas étudié les fonctionnalités avancées de GNU make car elles ne sont pas disponibles partout où j'ai besoin de mes makefiles pour fonctionner. –