首页 文章

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

提问于
浏览
1

我正在使用GNU makefile来构建一个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) $@ $^

正确地计算出编译 target 以及构建它所需的目标文件 . 但是,此时使用错误停止:

没有规则来制作'build / program.dll'所需的目标'build / objects / project / program.o' .

So why is this happening, and how do I fix it?

我通过运行 make --print-data-base 调查了这个问题,其输出包括:

# Not a target:
build/objects/project/program.o:
#  Implicit rule search has been done.
#  File does not exist.
#  File has not been updated.

这表明先决条件与预期的隐式规则不匹配 . 但是,当我尝试通过写作向后工作时,我确认它确实匹配:

object := build/objects/project/program.o
$(object:$(objects_directory)/%.o=$(source_directory)/%.c)
$(object:$(objects_directory)/%.o=%)

这些行导致 source/project/program.cproject/program ,这意味着正确计算了词干 .

我研究过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

1 回答

  • 1

    事实证明,这不是模式匹配 . 问题的根源在于隐式规则的依赖性先决条件 .

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

    当我再次阅读本手册的§_1190815时,答案就跳了出来:

    sed命令的目的是翻译(例如):main.o:main.c defs.h
    into:main.o main.d:main.c defs.h

    虽然我的构建系统不使用 sed ,但 main.d 位于示例规则左侧的事实感觉很奇怪 . 在我的代码中,它位于右侧 .

    当我把我的规则放在左侧时,它起作用,问题就解决了 . 错误的配方主要是将其中一种副产品作为先决条件 .

相关问题