我的Makefile中有此行:
$(CC) $(CFLAGS) -o $@ -c $(filter %$(*F).cpp, $(SOURCES))
[假设我有2个cpp文件,例如“ docinfo.cpp”和“ info.cpp”,当g ++将“ docinfo.cpp”构建为“ docinfo.o”时,它可以工作。
g++ -I ... -o docinfo.o -c docinfo.cpp
但是当g ++将“ info.cpp”构建为“ info.o”时,会出现错误。
g++ -I ... -o info.o -c docinfo.cpp info.cpp
我如何使其起作用?
这是我的Makefile:
CC := gcc
RM := rm -rf
WORKSPACE := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
TARGET := $(WORKSPACE)test.so
SOURCES := $(foreach dir,$(WORKSPACE),$(wildcard $(dir)source/*.c))
INCLUDE := -I$(WORKSPACE)include/
CFLAGS := $(INCLUDE) -O0 -Wall -fPIC
#CFLAGS += -g
#CFLAGS += -D__DEBUG__
OBJS := $(notdir $(SOURCES:.c=.o))
OBJ_PATH := $(WORKSPACE)object/
OBJS_O := $(addprefix $(OBJ_PATH), $(OBJS))
LIB_PATH := $(WORKSPACE)lib
LIBS := -ldl -shared
.PHONY: all clean
all: $(OBJ_PATH) $(LIB_TAG) $(TARGET)
$(OBJ_PATH):
mkdir -p $@
$(TARGET): $(OBJS_O)
$(CC) $(CFLAGS) -o $@ $^ -L$(LIB_PATH) $(LIBS)
@echo "$@"
$(OBJS_O): $(SOURCES)
$(CC) $(CFLAGS) -o $@ -c $(filter %$(*F).c,$(SOURCES))
clean:
-$(RM) $(OBJS_O) $(OBJ_PATH) $(TARGET)
首先,为什么不只使用$<
而不是尝试从$(SOURCES)中过滤掉某些内容?
$(CC) $(CFLAGS) -o $@ -c $<
[如果出于某种奇怪的原因,您确实需要过滤器,那么如果您不希望为以$(* F).cpp结尾的任何值返回匹配项,那么就不要在其前面加上模式匹配项字符(%
):
$(CC) $(CFLAGS) -o $@ -c $(filter $(*F).cpp, $(SOURCES))
但是,这很奇怪,因为$(*F)
应该扩展为foo.cpp
,这意味着它将解析为foo.cpp.cpp
。
所以,我认为您的makefile有点不寻常(或可能不正确)……但是由于您仅提供了配方,没有向我们展示整个规则,所以我们无法确定。
ETA
现在我们可以看到您的makefile,果然有问题。这条规则是错误的:
$(OBJS_O): $(SOURCES)
$(CC) ...
解析变量后,这将扩展为什么?假设您有SOURCES
解析为source/foo.c source/bar.c
和OBJS_O
解析为object/foo.o object/bar.o
。然后上述规则解析为:
object/foo.o object/bar.o: source/foo.c source/bar.c
$(CC) ...
在这里做什么?它不会神奇地将目标与先决条件进行逐文件匹配。它将解释此规则,就好像您是这样写的:
object/foo.o: source/foo.c source/bar.c
$(CC) ...
object/bar.o: source/foo.c source/bar.c
$(CC) ...
也就是说,每个对象都依赖于[[all源文件,因此,如果更改了任何源文件,则将重建每个对象。
如果要使其正常工作并将所有目标文件放在一个目录中,无论它们位于哪个源目录下,那么您都必须将vpath
与一个模式规则一起使用,如下所示:vpath %.c $(sort $(dir $(SOURCES)))
$(OBJ_PATH)%.o : %.c
$(CC) $(CFLAGS) -o $@ -c $<
现在您可以使用$<
而不是filter
函数,因为每个目标文件都完全依赖于它的源文件,而不是所有的源文件。