Подтвердить что ты не робот

Как использовать директиву include в make файле для определенной цели

Я хочу использовать директиву include только для определенной цели. Я не хочу запускать другие make файлы, когда цель не нужна, потому что это означает, что make файлы генерируются без необходимости.

Итак, есть ли способ условно использовать директиву include, которая является условной для цели? Или каким-то образом сделать директиву include предпосылкой целевой.

Вот что я до сих пор:

# 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 [email protected]; \
    $(CC) -I$(INCDIR) -MM $< -MT '$(@:.d=.o) [email protected]' > [email protected]

# 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 [email protected]

# 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 [email protected]

#Clean

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

Как вы можете сказать, мне не нужно включать файлы ".d" для "крипто", но я делаю это для "ядра" (цель по умолчанию).

Спасибо за любую помощь.

4b9b3361

Ответ 1

Make не является процедурным языком, поэтому рассматривайте его как один против зерна; ваши make файлы будут трудно масштабироваться, и это может привести к тонким ошибкам.

Там есть лучший способ от Tom Tromey, который чист, эффективен и масштабируется. Хитрость заключается в том, чтобы понять, что вы можете создать файл зависимостей на том же шаге, что и файл объекта. Зависимости просто указывают Make, когда объект должен быть перестроен; вам не нужны они, когда вы сначала создаете объект, потому что Make знает, что объект должен быть построен. И если зависимости меняются, это возможно только потому, что что-то из исходной или старой зависимостей изменилось, поэтому снова Make знает, что объект должен быть перестроен. (Это не очевидно, поэтому может потребоваться немного размышлений.)

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

-include build/*.d

Там еще одна проблема: если вы измените код, чтобы удалить зависимость, а также удалить этот файл - вы не сможете перестроить, потому что старый список зависимостей по-прежнему потребует файл, который не может дольше. Усовершенствованное решение состоит в том, чтобы обрабатывать файл зависимостей, чтобы сделать каждое предварительное условие (например, заголовок) целью по своему усмотрению без команд, так что можно при необходимости его перестроить:

$(CORE_OBJS): build/%.o: src/%.c
    $(CC) -c $(CFLAGS) $< -o [email protected]
    $(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

Более грубый метод, но почти как надежный, заключается в том, чтобы установить правила для всех заголовков и источников:

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

%.cc %.h:

EDIT:

Чтобы разбить новые команды:

Опция -MM указывает gcc создать правило make для объектного файла вместо предварительной обработки или компиляции. По умолчанию отправляется правило, куда бы он отправил предварительно обработанный вывод, который обычно будет стандартным.

Параметр -MF, используемый с -MM, указывает выходной файл. Итак, -MM -MF build/$*.d поставит правило, где мы хотим.

Итак, следующие две команды (почти всегда) эквивалентны:

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

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

(Я оставил -I$(...) и возможность использовать параметр -MMD, потому что оба становятся немного сложными и на самом деле не суть вопроса.)

Ответ 2

Вы можете использовать MAKECMDGOALS.

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

Вы могли бы, конечно, использовать ifneq (,$(findstring core,$(MAKECMDGOALS))), если была возможность более чем одной цели.

Примечание: это "быстрое и грязное" решение. Я согласен с Beta, что вы не должны делать это обычной практикой (это может стать беспорядочным, если вы сделали это во множестве make файлов...).

Джон

Ответ 3

Я не могу не нарушать рекомендации относительно того, что является хорошим ответом.

Мой ответ на исходный вопрос на мой взгляд, вы не можете включать правила, зависящие от цели. Все правила обрабатываются до того, как будут рассмотрены цели. Это ограничение make (я думаю). Опять же, хорошая точка, есть MAKECMDGOALS, но разве это не просто взлом в самой утилите make?

Ответ от Beta достаточно обоснован и достаточно ортодоксален, но вы не можете назвать его чистым, даже если это лучшее, что можно сделать. Он не будет работать, если make не обработал конкретную цель раньше, и соответствующий файл сборки /*.d не сидит там.