如何在makefile中为特定目标使用include伪指令

时间:2012-11-17 15:48:30

标签: makefile gnu-make

我想只为特定目标使用include指令。我不想在不需要目标时运行其他makefile,因为这意味着不必要地生成makefile。

那么有没有办法有条件地使用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 $@; \
    $(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

正如您应该能够告诉我不需要为“加密”包含“.d”文件,但我为“核心”(默认目标)做了。

感谢您的帮助。

3 个答案:

答案 0 :(得分:16)

制作不是一种程序性语言,所以将它视为一种语言是违背谷物的;你的makefile很难扩展,它可能导致细微的错误。

Tom Tromey有一个better way,它干净,高效且可扩展。诀窍是要意识到您可以在与目标文件相同的步骤中构建依赖项文件。依赖关系简单地告诉Make何时该对象将被重建;你第一次构建对象时不需要它们,因为Make知道必须构建对象。如果依赖项发生变化,那只能是因为源或旧依赖项中的某些内容发生了变化,所以再次知道必须重建该对象。 (这不明显,所以可能需要一点点思考。)

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

-include build/*.d

还有一个障碍:如果您更改代码以删除依赖项 - 并且还删除该文件 - 您将无法重建,因为旧的依赖项列表仍然需要一个不能的文件更长的时间。复杂的解决方案是处理依赖文件,以便在没有命令的情况下使每个先决条件(例如标题)成为一个目标,以便可以假定它在需要时重建:

$(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

一种更为粗俗的方法,但几乎是万无一失的,就是为标题和来源提供全面的规则:

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

%.cc %.h:

修改

分解新命令:

-MM选项告诉gcc为目标文件生成make规则,而不是预处理或编译。默认设置是将规则发送到发送预处理输出的位置,通常是stdout。

-MF一起使用的-MM选项指定输出文件。因此-MM -MF build/$*.d会将规则放在我们想要的位置。

因此以下两个命令(几乎总是)是等效的:

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

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

(我遗漏了-I$(...)以及使用-MMD选项的可能性,因为两者都有点复杂,并不是问题的重点。)

答案 1 :(得分:3)

您可以使用MAKECMDGOALS。

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

当然,如果有可能有多个目标,您可以使用ifneq (,$(findstring core,$(MAKECMDGOALS)))

注意:这是一个“快速而肮脏”的解决方案 - 我同意Beta,你不应该把它作为一种常见的做法(如果你在很多makefile中做到这一点,这可能会变得混乱......)。 / p>

约翰

答案 2 :(得分:1)

我不禁违反了什么是好答案的准则。

我对原始问题的回答在我看来,不是你不能包含依赖于目标的规则 - 在考虑目标之前处理所有规则。这是make的限制(我猜)。再说一遍,好的,有MAKECMDGOALS,但这不仅仅是make实用程序本身的黑客攻击吗?

Beta的答案是合理且正统的,但即使它是最好的,也不能称之为干净。如果make之前没有处理过特定的目标,并且相应的build / * .d依赖文件不在那里,那么它将无效。