当前位置: 动力学知识库 > 问答 > 编程问答 >

build - Object file target not matching implicit rule with pattern

问题描述:

I'm using GNU makefiles to build a C project. I want to keep all build artifacts on an isolated build tree in order to minimize clutter. The project looks like this:

$prefix/

include/$tree/program.h

source/$tree/program.c

build/

objects/$tree/program.o

dependencies/$tree/program.d

Where $prefix represents the directory of the project and $tree represents an arbitrary folder structure.

I wanted to match source files in the source/ directory to their object and dependency file counterparts in the build/ tree. So, I wrote the following rules:

# 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] $^

Make correctly figures out the compilation target and the object files needed to build it. However, make stops at this point with the error:

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

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

I investigated the problem by running make --print-data-base, the output of which included:

# Not a target:

build/objects/project/program.o:

# Implicit rule search has been done.

# File does not exist.

# File has not been updated.

Which suggests that the prerequisite is not matching the implicit rule as intended. However, I verified that it does match when I tried to work my way backwards by writing:

object := build/objects/project/program.o

$(object:$(objects_directory)/%.o=$(source_directory)/%.c)

$(object:$(objects_directory)/%.o=%)

These lines result in source/project/program.c and project/program, which means the stem is being correctly computed.

I have studied the GNU make documentation and I don't remember reading anything that suggests that this kind of pattern matching can't happen in implicit rule definitions.


Here are the variable definitions:

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

网友答案:

It turns out it wasn't the pattern matching. The root of the problem was in the dependency prerequisite of the implicit rule.

The dependency file isn't supposed to be a prerequisite in the first place; it should be one of the targets that gets generated along with the object file.

As I read once more § 4.14 Generating Prerequisites Automatically of the manual, the answer jumped out at me:

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

While my build system makes no use of sed, the fact that main.d was on the left-hand side of the example rule felt strange. In my code, it was on the right-hand side.

When I put my rule in the left-hand side, it worked and the problem was solved. The erroneous recipe was essentially treating one of its byproducts as a prerequisite.

分享给朋友:
您可能感兴趣的文章:
随机阅读: