2016-02-27 114 views
1

我正在使用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) [email protected] $< 

$(build_directory)/$(target) : $(objects) 
    $(compiler_command_line) $(compiler_option_output) [email protected] $^ 

制作正确地计算出编译target,并建立它所需的目标文件。然而,让停在此点出现错误:

No rule to make target 'build/objects/project/program.o' , needed by 'build/program.dll' .

那么,为什么会出现这种情况,如何解决呢?

我通过运行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

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

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

当我再次读取§本手册的4.14 Generating Prerequisites Automatically,答案在我跳了出来:

The purpose of the sed command is to translate (for example):

main.o : main.c defs.h 

into:

main.o main.d : main.c defs.h 

虽然我的编译系统是没有用的sed,事实main.d是在左侧这个例子规则感觉很奇怪。在我的代码中,它在右侧。

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

+0

链接器(或编译器)不使用'.d'。它们是由编译器生成的makefile,由父Makefile包含, 定义了“foo.o”的依赖关系,该标头否则不会被称为先决条件。当它相对于由'foo.c | cpp'包含的头部过期时,它们会提示* make *重新编译*'foo.o'。 –

+0

请参阅 [this](http://stackoverflow.com/questions/8025766/makefile-auto-dependency-generation) [this](http://make.mad-scientist.net/papers/advanced-auto-依赖生成/) 和[这](http://www.microhowto.info/howto/automatically_generate_makefile_dependencies.html) –

+0

@MikeKinghan,我不认为我理解这个过程,以及我想。根据它们之间的依赖关系,我认为目标文件和库都必须以特定顺序链接。我认为这是问题['pkg-config'](https://www.freedesktop.org/wiki/Software/pkg-config/)旨在解决的问题。这是不正确的?如果不是,请你澄清一下;我会编辑答案。 –