web-dev-qa-db-fra.com

Comment utiliser la directive Inclure dans un maquette pour une cible spécifique

Je souhaite utiliser la directive Inclure uniquement pour une cible spécifique. Je ne veux pas exécuter les autres maquillages lorsque la cible n'est pas nécessaire car cela signifie que les maquillages sont générés inutilement.

Il y a donc un moyen d'utiliser de manière conditionnelle la directive Inclure, qui est conditionnelle sur une cible? Ou d'une manière ou d'une autre pour inclure la directive inclure une condition préalable d'une cible.

Voici ce que j'ai jusqu'à présent:

# Flags

INCDIR = $(CURDIR)/include
CFLAGS = -Wall -Wno-overflow -Wno-uninitialized -pedantic -std=c99 -I$(INCDIR) -O3
LFLAGS = -flat_namespace -dynamiclib -undefined dynamic_lookup

# Directory names

# Set vpath search paths

vpath %.h include
vpath %.c src
vpath %.o build
vpath %.d build

# Get files for the core library

CORE_FILES = $(wildcard src/*.c)
CORE_OBJS = $(patsubst src/%.c, build/%.o, $(CORE_FILES))
CORE_DEPS = $(CORE_OBJS:.o=.d)

# Core library target linking

core : $(CORE_OBJS) | bin
    $(CC) $(LFLAGS) -o bin/libcbitcoin.2.0.dylib $(CORE_OBJS)

# Include header prerequisites (How to do only for "core" target?)

include $(CORE_DEPS)

# Makefiles for header dependencies. 

$(CORE_DEPS): build/%.d: src/%.c | build
    rm -f $@; \
    $(CC) -I$(INCDIR) -MM $< -MT '$(@:.d=.o) $@' > $@

# Objects depend on directory

$(CORE_OBS) : | build

# Create build directory

build:
    mkdir build

# Create bin directory

bin:
    mkdir bin

# Core Compilation

$(CORE_OBJS): build/%.o: src/%.c
    $(CC) -c $(CFLAGS) $< -o $@

# Depencies require include/CBDependencies.h as a prerequisite

build/CBOpenSSLCrypto.o: include/CBDependencies.h

# Crypto library target linking

crypto : build/CBOpenSSLCrypto.o -lcrypto -lssl | bin
    $(CC) $(LFLAGS) -o bin/libcbitcoin-crypto.2.0.dylib build/CBOpenSSLCrypto.o -lcrypto -lssl

# Crypto library compile

build/CBOpenSSLCrypto.o: dependencies/crypto/CBOpenSSLCrypto.c
    $(CC) -c $(CFLAGS) $< -o $@

#Clean

clean:
    rm -f $(CORE_OBJS) $(CORE_DEPS) build/CBOpenSSLCrypto.o

Comme vous devriez pouvoir dire, je n'ai pas besoin d'inclure les fichiers ".d" pour "crypto", mais je fais pour "Core" (objectif par défaut).

Merci pour toute aide.

17
Matthew Mitchell

Faire n'est pas une langue procédurale, donc le traiter comme on va à l'encontre du grain; Vos maquillages seront difficiles à mettre à l'échelle et cela peut conduire à des bugs subtils.

Il y a une meilleur moyen par Tom Tromey qui est propre, efficace et évolutif. L'astuce consiste à réaliser que vous pouvez créer le fichier de dépendance dans la même étape que le fichier d'objet. Les dépendances disent simplement à faire lorsque l'objet doit être reconstruit; Vous n'en avez pas besoin lorsque vous construisez d'abord l'objet, car vous savez que l'objet doit être construit. Et si les dépendances changent, cela ne peut être que parce que quelque chose dans la source ou des vieilles dépendances a changé, il est donc de nouveau en sachant que l'objet doit être reconstruit. (Ce n'est pas évident, il peut donc prendre un peu de cogitation.)

$(CORE_OBJS): build/%.o: src/%.c
    $(CC) -c $(CFLAGS) $< -o $@
    $(CC) -MM -MF build/$*.d $<

-include build/*.d

Il y a un autre attelage: si vous modifiez le code afin de supprimer une dépendance - et de supprimer ce fichier - vous ne pourrez pas reconstruire, car l'ancienne liste de dépendance demandera toujours un fichier qui ne peut plus être trouvé. . La solution sophistiquée consiste à traiter le fichier de dépendance afin de rendre chaque prérequis (par exemple en-tête) une cible à part entière, sans commandes, de sorte qu'elle puisse être supposée être reconstruite en cas de besoin:

$(CORE_OBJS): build/%.o: src/%.c
    $(CC) -c $(CFLAGS) $< -o $@
    $(CC) -MM -MF build/$*.d $<
    @cp build/$*.d build/$*.P
    @sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
            -e '/^$$/ d' -e 's/$$/ :/' < build/$*.P >> build/$*.d;
    @rm build/$*.P

Une méthode de crudère, mais presque aussi infaillible, est de mettre en charge toutes les règles pour les en-têtes et les sources:

$(CORE_OBJS): build/%.o: src/%.c
    $(CC) -c $(CFLAGS) $< -o $@
    $(CC) -MM -MF build/$*.d $<

%.cc %.h:

ÉDITER:

Pour décomposer les nouvelles commandes:

L'option -MM indique à GCC de produire une règle make pour le fichier d'objet, au lieu de prétraitement ou de compilation. La valeur par défaut consiste à envoyer la règle à l'endroit où elle envoie une sortie prétraitée, qui sera généralement stdout.

L'option -MF, utilisée avec -MM, spécifie le fichier de sortie. Alors -MM -MF build/$*.d mettra la règle où nous le voulons.

Donc, les deux commandes suivantes sont (presque toujours) équivalentes:

    $(CC) -MM -MF build/$*.d $<

    $(CC) -MM $< > build/$*.d

(J'ai laissé de côté la fonction -I$(...) et la possibilité d'utiliser l'option -MMD, car les deux ont un peu compliqué et ne sont pas vraiment le point de la question.)

17
Beta

Vous pouvez utiliser Makecmdgoals.

ifeq (core,$(MAKECMDGOALS))
include $(CORE_DEPS)
endif

Vous pouvez bien sûr utiliser ifneq (,$(findstring core,$(MAKECMDGOALS))) S'il y avait une possibilité de plus d'une cible.

Remarque: il s'agit d'une solution "rapide et sale" - je suis d'accord avec la bêta que vous ne devriez pas faire une pratique courante (cela pourrait devenir désordonné si vous le faites dans de nombreux maquillages ...).

John

3
John