Build 对象文件目标与模式的隐式规则不匹配

Build 对象文件目标与模式的隐式规则不匹配,build,makefile,gnu-make,Build,Makefile,Gnu Make,我正在使用GNU makefiles构建一个C项目。我希望将所有构建工件保存在一个独立的构建树上,以尽量减少混乱。该项目如下所示: $prefix/ include/$tree/program.h source/$tree/program.c build/ objects/$tree/program.o dependencies/$tree/program.d 其中,$prefix表示项目的目录,$tree表示任意文件夹结构 我想将sou

我正在使用GNU makefiles构建一个C项目。我希望将所有构建工件保存在一个独立的构建树上,以尽量减少混乱。该项目如下所示:

$prefix/
    include/$tree/program.h
    source/$tree/program.c
    build/
        objects/$tree/program.o
        dependencies/$tree/program.d
其中,
$prefix
表示项目的目录,
$tree
表示任意文件夹结构

我想将
source/
目录中的源文件与其
build/
树中的对象和依赖项文件对应项进行匹配。因此,我写了以下规则:

# Remove the built-in rules
%.o : %.c

$(objects_directory)/%.o : $(source_directory)/%.c $(dependencies_directory)/%.d
    $(compiler_command_line) $(compiler_option_output) $@ $<

$(build_directory)/$(target) : $(objects)
    $(compiler_command_line) $(compiler_option_output) $@ $^
这表明前提条件与隐含规则不匹配。然而,当我试图通过写下以下内容来反向工作时,我验证了这一点:

object := build/objects/project/program.o
$(object:$(objects_directory)/%.o=$(source_directory)/%.c)
$(object:$(objects_directory)/%.o=%)
这些行导致
source/project/program.c
project/program
,这意味着正在正确计算stem

我研究过GNU make文档,我不记得读过任何东西表明这种模式匹配不能发生在隐式规则定义中


以下是变量定义:

include_directory := include
source_directory := source

build_directory := build
objects_directory := $(build_directory)/objects
dependencies_directory := $(build_directory)/dependencies

sources := $(wildcard $(source_directory)/**/*.c)
objects := $(sources:$(source_directory)/%.c=$(objects_directory)/%.o)

# Take the name of the project's directory
target := $(notdir $(CURDIR)).dll

compiler_dependency_file = $(patsubst $(source_directory)/%.c,$(dependencies_directory)/%.d,$<)
compiler_options = -I $(include_directory) -MMD -MF $(compiler_dependency_file)

CC = gcc
compiler_command_line = $(CC) $(compiler_options) $(CFLAGS)
compiler_option_output = -o
include\u目录:=include
source\u目录:=源
build\u目录:=build
对象\u目录:=$(生成\u目录)/对象
依赖项\u目录:=$(生成\u目录)/依赖项
sources:=$(通配符$(source\u目录)/***.c)
对象:=$(源:$(源目录)/%.c=$(对象目录)/%.o)
#获取项目目录的名称
目标:=$(notdir$(CURDIR)).dll

编译器\u dependency\u file=$(patsubst$(源目录)/%.c,$(dependency\u目录)/%.d,$结果表明,这不是模式匹配。问题的根源在于隐式规则的依赖先决条件

依赖项文件首先不应该是一个先决条件;它应该是与对象文件一起生成的目标之一

当我再次阅读手册的§时,我突然想到了答案:

sed命令的目的是翻译(例如):

进入:

main.o main.d : main.c defs.h
虽然我的构建系统没有使用
sed
,但是
main.d
位于示例规则的左侧这一事实让人感到奇怪。在我的代码中,它位于右侧


当我把我的规则放在左手边时,它起作用了,问题解决了。错误的配方基本上是把它的一个副产品作为先决条件。

.d
不被链接器(或编译器)使用。它们是编译器生成的makefile,由父makefile包含,定义了
foo.o
对标头的依赖关系,否则这些标头将不被视为先决条件。当相对于
foo.c | cpp
包含的任何标头过期时,它们会提示make重新编译
foo.o
。请参阅和@MikeKing韩,我认为我对这个过程的理解不如我所希望的。我的印象是,目标文件和库都必须按照它们之间的依赖关系按特定顺序链接。我认为这就是问题的目的。这不对吗?如果不对,请您澄清;我将编辑答案。目标文件和d库需要按这样的顺序链接,即在链接器命令行中,任何需要符号定义的库都出现在提供符号定义的库之前。这些需要/提供关系是链接依赖项,但与
make
依赖项完全不同,它们的关系形式为:如果X是n在Y之外,再做Z。
.d
文件表示
make
依赖关系:链接器对它们一无所知。事物链接的顺序完全独立于
make
的顺序。
main.o : main.c defs.h
main.o main.d : main.c defs.h