Makefile 隐式规则不起作用

Posted

技术标签:

【中文标题】Makefile 隐式规则不起作用【英文标题】:Makefile implicit rule not working 【发布时间】:2016-09-28 17:19:14 【问题描述】:

我有这个 makefile,我正在尝试编写一些测试目标

#This a make file of serial communication driver that i'm writing.
#serial_target would be a target to test this driver isolated.
 
CC = gcc
 
DISPLAY_STRING = -DDISPLAY_STRING
LFLAGS = 
CFLAGS = $(DISPLAY_STRING) 
 
#mains macros
BUILD_DIR =build
SOURCE_DIR =src
HEADER_DIR =src
BIN_DIR =bin
 
SOURCES = $(wildcard $(SOURCE_DIR)/*.c)
OBJECTS =  $(patsubst $(SOURCE_DIR)/%.c, $(BUILD_DIR)/%.o, $(SOURCES))
HEADERS =  $(patsubst $(SOURCE_DIR)/%.c, $(HEADER_DIR)/%.h, $(SOURCES))
 
 
#serial_tests
TEST_DIR=src/test
TEST_TARGET=serial_test
 
TEST_SOURCES = $(wildcard $(TEST_DIR)/*_test.c) \
    $(SOURCES)
TEST_OBJECTS = $(filter %.o ,$(patsubst %.c, $(BUILD_DIR)/%.o, $(subst /, , $(TEST_SOURCES))))
TEST_HEADERS = $(TEST_SOURCES:.c=.h)
 
 
all:
    
serial_test: $(TEST_OBJECTS)
    $(CC) $(CFLAGS) -I$(SOURCE_DIR) -I$(HEADER_DIR) -o $(BIN_DIR)/$@ $^
    
$(BUILD_DIR)/%.c.o: %.c $(HEADERS)
    $(CC) $(CFLAGS) -I$(HEADER_DIR) -I$(SOURCE_DIR) -c $< -o $@     
 
setup:
    mkdir $(BUILD_DIR)
    mkdir $(BIN_DIR)
    
clean:
    rm -rf $(EXEC) $(OBJECTS)

运行“make serial_test”时,我总是得到这个:

make: *** No rule to make target `build/serial_test.o', needed by `serial_test'. Stop.

这是疑问。如果规则 $(BUILD_DIR)/%.c.o 存在,为什么我会收到此错误?

编辑

为了确保其他一切正常,我尝试了这个(效果很好)

serial_test: $(TEST_OBJECTS)
    $(CC) $(CFLAGS) -I$(SOURCE_DIR) -I$(HEADER_DIR) -o $(BIN_DIR)/$@ $^
build/serial_test.o: src/test/serial_test.c
    $(CC) $(CFLAGS) -I$(HEADER_DIR) -I$(SOURCE_DIR) -c $< -o $@ 
build/serialCom_xsens.o: src/serialCom_xsens.c
    $(CC) $(CFLAGS) -I$(HEADER_DIR) -I$(SOURCE_DIR) -c $< -o $@

为了确保变量 BUILD_DIR 是空的,我这样做了:

$(BUILD_DIR)/serial_test.o: %.c
    $(CC) $(CFLAGS) -I$(HEADER_DIR) -I$(SOURCE_DIR) -c $< -o $@

使用上面的这段代码,我得到了另一个错误:

make: *** No rule to make target `%.c', needed by `build/serial_test.o'. Stop.

%.c 和 %.o 规则是否有可能被破坏?

如果您有任何设计技巧,请回答。这也很有帮助。

【问题讨论】:

【参考方案1】: 您正在混合模式和后缀规则,坚持使用模式规则 不完全确定你想用TEST_OBJECTS做什么 您使每个对象都依赖于每个标头,请改用依赖生成 serial_test 的规则已损坏,始终使用 $@ 作为任何给定规则的输出 使目录成为先决条件 回收内置配方(COMPILE.cLINK.o
display_string := -Ddisplay_string

source_dir := src
header_dir := src
build_dir  := build
bin_dir    := bin
 
sources := $(wildcard $(source_dir)/*.c)
objects := $(sources:$(source_dir)/%.c=$(build_dir)/%.o)
 
test_dir    := src/test
test_target := serial_test
 
test_sources := $(wildcard $(test_dir)/*_test.c)
test_objects := $(test_sources:$(test_dir)/%.c=$(build_dir)/%.o) $(objects)
 
deps := $(test_objects:%.o=%.d)

CPPFLAGS := $(display_string) -I$(header_dir) -MMD -MP
    
$(bin_dir)/serial_test: $(test_objects) | $(bin_dir)
    $(LINK.o) $^ $(LDLIBS) -o $@
    
$(build_dir)/%.o: $(source_dir)/%.c | $(build_dir)
    $(COMPILE.c) $(OUTPUT_OPTION) $<
 
$(build_dir) $(bin_dir): ; mkdir $@
    
clean: ; $(RM) serial_test $(objects) $(deps)

-include $(deps)

【讨论】:

我已经使用 TEST_OBJECTS 来获取所有测试对象的列表。对于我的目的来说,这可能不是最好的设计,但我试图做的是一个 makefile(有两个主要规则,一个用于真正的项目可执行文件,另一个用于测试)。我在“文件树组织”上苦苦挣扎。如果您有任何 makefile 设计书籍(或网站),我将不胜感激。 @PescadorParrudo 至少阅读了一次manual,maintainer 在论文和沉思部分也有一些很好的信息。谨防在线或书籍中的 make 信息,其中很多已经过时,因为现在很少有人使用 plain make。【参考方案2】:

仔细看看你的模式规则:

$(BUILD_DIR)/%.c.o: %.c $(HEADERS)

它匹配带有.c.o 扩展名的文件名。错误消息表明您正在尝试构建 build/serial_test.o,它与模式不匹配,因为路径未以 .c.o 结尾。

在您的构建规则中修复您的模式,或者您的patsubst.c 替换为.c.o,以便模式规则匹配。

【讨论】:

$(BUILD_DIR)/%.o: %.c $(HEADERS) 我这样做了,但我得到了相同的结果。 > 这是我最初的规则,但我改变了,因为我看到有人在某个网站上使用 %.c.o @PescadorParrudo, %.c.o 看起来像是模式规则和后缀规则的虚假合并。 “有人在其他网站上使用它”并不重要。看起来模式规则是您真正想要的,在这种情况下,几乎可以肯定合适的目标是$(BUILD_DIR)/%.o %.c.o 从 .c 文件创建一个 .o 文件(根据手册)。我试过这个$(BUILD_DIR)/%.o 并陷入同样的​​错误。

以上是关于Makefile 隐式规则不起作用的主要内容,如果未能解决你的问题,请参考以下文章

隐式导航不起作用

JSF Flow - 隐式导航不起作用

-L 和 -l 命令在 Makefile 中不起作用

为多个操作系统创建一个makefile,这个make(ext?)不起作用?

Makefile bash和xargs变量不起作用

UPI 隐式意图选择器在 Redmi 设备上不起作用