【问题标题】:How to use the include directive in a makefile for a specific target如何在特定目标的生成文件中使用 include 指令
【发布时间】:2012-11-17 15:48:30
【问题描述】:

我只想将包含指令用于特定目标。我不想在不需要目标时运行其他 makefile,因为这意味着生成文件是不必要的。

那么有没有办法有条件地使用以目标为条件的包含指令?或者以某种方式使包含指令成为目标的先决条件。

这是我目前所拥有的:

# 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

正如您应该能够告诉我的,我不需要为“crypto”包含“.d”文件,但我为“core”(默认目标)包含。

感谢您的帮助。

【问题讨论】:

  • 可以这样做,但你不应该。它违背了 Make 的原则,并且有更好的方法。您喜欢快速简单的方法,还是先进而强大的方法?
  • 那么我可以问一个问题:什么是“制作的颗粒”和这些“更好的方法”?只要它易于维护。这就是我想要的。我不想手动添加标题先决条件。

标签: makefile gnu-make


【解决方案1】:

Make 不是一种程序语言,因此将其视为一种违背规则的语言;您的 makefile 将难以扩展,并且可能导致细微的错误。

Tom Tromey 的 better way 干净、高效且可扩展。诀窍是意识到您可以在与目标文件相同的步骤中构建依赖文件。依赖项只是告诉 Make 对象何时应该被重建;首次构建对象时不需要它们,因为 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 规则,而不是预处理或编译。默认是将规则发送到它将发送预处理输出的任何地方,通常是标准输出。

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

所以以下两个命令(几乎总是)是等价的:

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

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

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

【讨论】:

  • 好的,谢谢。我必须将 $(CC) -MM -MF build/$*.d $&lt; 更改为 $(CC) -I$(INCDIR) -MM -MF build/$*.d $&lt; &gt; build/$*.d 才能使其工作,但在我的系统上不支持 MF 标志。更换MF的功能应该怎么做?
  • @MatthewMitchell,你几乎自己回答了这个问题,但我会编辑我的答案。
  • 请注意,-MP 选项现在允许使用 sed 避开最后一步。
  • @Norswap:是的,而且很好摆脱。这些天我可以推荐a much simpler makefile
  • @Beta:你能否解释一下那个可怕的长 sed 命令的作用:)
【解决方案2】:

您可以使用 MAKECMDGOALS。

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

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

注意:这是一个“快速而肮脏”的解决方案——我同意 Beta 版的观点,即您不应该将其作为一种常见做法(如果您在很多 makefile 中这样做,这可能会变得混乱......)。

约翰

【讨论】:

  • 谢谢。我猜这是一种方法,但 Beta 的替代方法似乎是最理想的。我想使用 automake 将是实现类似目标的一种方法。
【解决方案3】:

我忍不住要打破关于什么是好的答案的准则。

在我看来,我对原始问题的回答是,不,您不能包含依赖于目标的规则 - 在考虑目标之前处理所有规则。这是 make 的限制(我猜)。话又说回来,有 MAKECMDGOALS,但这不只是 make 实用程序本身的 hack 吗?

Beta 的回答是合理且足够正统的,但即使是能做到的最好也不能说干净。如果 make 之前没有处理过特定的目标,并且相应的 build/*.d 依赖文件不在那里,它将无法工作。

【讨论】:

  • 你错了。如果 Make 之前没有构建目标并且相应的 .d 文件不存在,我描述的方法(我没有发明)效果很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-28
  • 1970-01-01
  • 1970-01-01
  • 2020-10-29
相关资源
最近更新 更多