makefile - que - Cómo usar la directiva de inclusión en un archivo MAKE para un objetivo específico
makefile 112 makeopts no existe el fichero o el directorio (3)
Quiero usar la directiva de inclusión solo para un objetivo específico. No quiero ejecutar los otros makefiles cuando el objetivo no es necesario porque significa que los makefiles se generan innecesariamente.
Entonces, ¿hay alguna manera de usar condicionalmente la directiva include, que es condicional en un objetivo? O de alguna manera hacer que la directiva de inclusión sea un requisito previo de un objetivo.
Esto es lo que tengo hasta ahora:
# 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
Como debería poder decir, no es necesario que incluya los archivos ".d" para "criptografía", pero lo hago para "núcleo" (objetivo predeterminado).
Gracias por cualquier ayuda.
No puedo evitar romper las pautas de lo que es una buena respuesta.
En mi opinión, mi respuesta a la pregunta original es que no, no puede incluir reglas que dependen del objetivo; todas las reglas se procesan antes de considerar los objetivos. Esta es una limitación de make (supongo). Por otra parte, buen punto, hay MAKECMDGOALS, ¿pero no es solo un truco en la utilidad make?
La respuesta de Beta es razonable y lo suficientemente ortodoxa, pero no se puede llamar limpia, incluso si es lo mejor que se puede hacer. No funcionará si make no ha procesado el objetivo particular anteriormente y el archivo de dependencia compilación / *. D apropiado no está allí.
Puedes usar MAKECMDGOALS.
ifeq (core,$(MAKECMDGOALS))
include $(CORE_DEPS)
endif
Por supuesto, podría usar ifneq (,$(findstring core,$(MAKECMDGOALS)))
si existiera la posibilidad de más de un objetivo.
Nota: esta es una solución ''rápida y sucia''. Estoy de acuerdo con Beta en que no debes hacer de esto una práctica común (esto podría complicarse si lo hicieras en muchos archivos make ...).
John
Make no es un lenguaje de procedimiento, por lo que tratarlo como uno va contra la corriente; sus makefiles serán difíciles de escalar y pueden provocar errores sutiles.
Hay una forma mejor por Tom Tromey que es limpia, eficiente y escalable. El truco consiste en darse cuenta de que puede compilar el archivo de dependencia en el mismo paso que el archivo objeto. Las dependencias simplemente le dicen a Make cuando el objeto debe ser reconstruido; no los necesita cuando crea el objeto por primera vez, porque Make sabe que el objeto debe ser construido. Y si las dependencias cambian, eso solo puede deberse a que algo en el origen o en las antiguas dependencias ha cambiado, por lo que, de nuevo, Make sabe que el objeto debe reconstruirse. (Esto no es obvio, por lo que puede requerir un poco de reflexión).
$(CORE_OBJS): build/%.o: src/%.c
$(CC) -c $(CFLAGS) $< -o $@
$(CC) -MM -MF build/$*.d $<
-include build/*.d
Hay un inconveniente más: si modifica el código para eliminar una dependencia y también elimina ese archivo, no podrá volver a generarlo, porque la lista de dependencias anterior seguirá exigiendo un archivo que ya no se puede encontrar. . La solución sofisticada es procesar el archivo de dependencia para que cada requisito previo (por ejemplo, el encabezado) sea un objetivo por derecho propio, sin comandos, de modo que se puede suponer que se reconstruirá cuando sea necesario:
$(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
Un método más crudo, pero casi tan infalible, es poner reglas generales para encabezados y fuentes:
$(CORE_OBJS): build/%.o: src/%.c
$(CC) -c $(CFLAGS) $< -o $@
$(CC) -MM -MF build/$*.d $<
%.cc %.h:
EDITAR:
Para desglosar los nuevos comandos:
La opción -MM
le dice a gcc que produzca una regla de -MM
para el archivo de objeto, en lugar de preprocesar o compilar. El valor predeterminado es enviar la regla a donde envíe la salida preprocesada, que generalmente será stdout.
La opción -MF
, utilizada con -MM
, especifica el archivo de salida. Entonces -MM -MF build/$*.d
pondrá la regla donde queremos.
Entonces los siguientes dos comandos son (casi siempre) equivalentes:
$(CC) -MM -MF build/$*.d $<
$(CC) -MM $< > build/$*.d
(He -MMD
el -I$(...)
y la posibilidad de usar la opción -MMD
, porque ambos se vuelven un poco complicados y realmente no son el objetivo de la pregunta).