C++ 在makefile中,如何对变量中的每个文件名执行命令?

C++ 在makefile中,如何对变量中的每个文件名执行命令?,c++,makefile,C++,Makefile,我知道我做错了,但我不知道如何组织这个makefile。我定义了我的util源文件,并使用一些函数从中定义.o文件: UTIL_SRC = utils/src/foo.cpp utils/src/bar.cpp utils/src/baz.cpp UTIL_OBJS = $(patsubst utils/src/%.cpp,utils/obj/%.o,$(UTIL_SRC)) 这是我使用这些文件的目标: lib : lib/libutils.a lib/libutils.a : $(UTI

我知道我做错了,但我不知道如何组织这个makefile。我定义了我的util源文件,并使用一些函数从中定义.o文件:

UTIL_SRC = utils/src/foo.cpp utils/src/bar.cpp utils/src/baz.cpp

UTIL_OBJS = $(patsubst utils/src/%.cpp,utils/obj/%.o,$(UTIL_SRC))
这是我使用这些文件的目标:

lib : lib/libutils.a

lib/libutils.a : $(UTIL_OBJS)
    rm -f lib/libutils.a
    ar -c -q lib/libutils.a $(UTIL_OBJS)
然后,当我开始编译这些婴儿时,我希望只有一个命令可以遍历每个UTIL_OBJS文件和每个UTIL_SRC文件。相反,我求助于这个怪物,它破坏了将它们存储在变量中的目的

$(UTIL_OBJS) : $(UTIL_SRC)
    g++ $(UTIL_FLAGS) utils/src/foo.cpp -o utils/obj/foo.o
    g++ $(UTIL_FLAGS) utils/src/bar.cpp -o utils/obj/bar.o
    g++ $(UTIL_FLAGS) utils/src/baz.cpp -o utils/obj/baz.o
CXX=g++
CXXFLAGS=$(UTIL_FLAGS)

我能把它压缩成一行吗?怎么用?谢谢,好孩子们

我想你可以用这个:

$(UTIL_OBJS) : $(UTIL_SRC)
    g++ $(UTIL_FLAGS) $(@ : .o = .cpp)  -o $@ 

再说一次,我不太确定。。。特别是关于$(@:.cpp=.o)部分,使用隐式规则通常更容易。有很多预定义的变量,您只需要指定变量

$(UTIL_OBJS) : $(UTIL_SRC)
    g++ $(UTIL_FLAGS) utils/src/foo.cpp -o utils/obj/foo.o
    g++ $(UTIL_FLAGS) utils/src/bar.cpp -o utils/obj/bar.o
    g++ $(UTIL_FLAGS) utils/src/baz.cpp -o utils/obj/baz.o
CXX=g++
CXXFLAGS=$(UTIL_FLAGS)
然后需要定义一个可执行文件,如下所示

myutil: $(UTIL_OBJS)
由于您没有将对象存储在同一目录中,因此还需要指定一个新的隐式规则(否则,我们现在就完成了)

%是模式匹配,它将在左侧和右侧匹配相同的文本,因此此规则将使foo.o脱离foo.cpp。 如果没有该命令(它可能从另一条规则中获取了该命令,我不确定),请尝试,否则让它说:

utils/obj/%.o: utils/obj/%.cpp
    $(CXX) $(CXXFLAGS) -o $@ $^
$@是规则的目标(例如foo.o),$^是右侧的所有文件。 我只是在脑海中写下这一点,没有可能测试它,所以请让我知道结果如何:)

为了使它更加优雅,您可以包含一个依赖项文件

include .depend
如果您运行的是GNU make,如果找不到它,它将尝试生成.dependen文件(对于老式的make,您需要首先自己创建它,如果您希望通过makefile管理它,它可能只是一个虚拟文件)

依赖项文件将包含每个.cpp文件的行,告诉make它需要什么头文件,这将允许make在您更改某些内容时重新编译必要的文件。不过,这对你原来的问题没有帮助,只是觉得它可能会派上用场

编辑:

作为对编辑的响应。您可能也可以删除创建.a文件的命令,这也是一个隐式规则。虽然不确定它到底是如何工作的,但我并没有太多地使用它。我确实知道make在处理.a(rchive?)文件时有很多怪癖。

所有这些神奇的符号是什么意思?它看起来像是破解中的Perl。$@是规则的目标,:告诉它替换后缀注:
$(@:.o=.cpp)
因为空格而不起作用,它必须是
$(@:.o=.cpp)
(至少对我来说)事实上,模式规则是可行的。我在没有命令的情况下尝试了模式规则,但它不起作用。但是,显式定义命令是有效的。模式规则是否导致make搜索utils/src/%.cpp?不,它不会搜索.cpp文件,它会查看它需要什么utils/obj/%.o文件,并且此规则适用,因此它将从utils/src/%.cpp进行搜索。它有点像倒过来的。触发器是一行
myutil:$(UTIL\u OBJS)
,您可以在该行中告诉它您需要什么.o文件。在本例中,它们都在utils/obj/中,因此如果我理解正确,make会看到对$(UTIL_OBJS)的依赖性,并注意到有一个编译文件的规则,该规则应该类似于utils/obj/%.o。然后,它使用$(UTIL_OBJS)中每件事情的模式规则来生成.o文件。是吗?是的,make会看到$(UTIL_OBJS)中所有.o文件的依赖项,并尝试使每个文件都成为依赖项。对于每个.o文件,它依次确定utils/obj/%.o规则最适合,并使用该规则生成.o文件(如有必要,即cpp文件比o文件新,或者o文件不存在)。