Makefile通配符具有不同的输入和输出名称

时间:2017-07-02 06:43:04

标签: c++ makefile compilation

我的src文件夹中有一个文件夹结构,我希望将其保存在我的obj文件夹中,其中包含所有.o个文件。我不想使用mkdir,因为跨平台使用会出现很多问题。相反,我做了

$(OBJECTS) := $(patsubst %,obj/%,$(subst /,_,$(SOURCES)))

现在的问题是,创建这些文件的规则的输入和输出文件名是不同的,这意味着要做

$(OBJECTS): obj/%.o: %.cpp
    # whatever compile command

不再有效,因为obj/Core_Graphics_Window.o的输出示例输入为Core/Graphics/Window.cpp

这仍然可以吗?

3 个答案:

答案 0 :(得分:1)

如果要使用其他名称,则不能使用隐式规则或静态模式规则。您必须为每个目标创建显式规则。为了避免手动执行此操作,您需要做一些更高级的事情,例如使用eval / call组合:

COMPILE.cxx = whatever compile command

define cxx_rule
obj/$(subst /,_,$1).o: $1.cpp
        $$(COMPILE.cxx) -c -o $$@ $$<
endef

$(foreach O,$(OBJECTS),$(eval $(call cxx_rule,$(basename $O))))

请仔细注意逃脱(加倍)的美元符号。要了解有关其工作原理的更多信息,请阅读this set of blog posts

答案 1 :(得分:0)

试试这个(因为我没有,所以它可能不起作用)

  1. 使用其路径(明确地或https://stackoverflow.com/a/2483203/2064196)收集所有来源的列表,让我们称之为来源。
  2. 创建明确的依赖项列表:echo ${SOURCES} | tr ' ' "\n" | perl -nwle '$c = $_; s!/!_!g; print "obj/$_ : $c\n\twhatever compile command"' > rules.mk
  3. 制作rules.mk取决于来源:rules.mk : ${SOURCES}
  4. include rules.mk
  5. 如果您要将每个目标文件转储到同一目录中,我建议您忘记源中的层次结构。然后你可以写一个

    obj/%.o : %.cpp
        # whatever compile command
    

    通过构建适当的VPATH来获取源代码。

答案 2 :(得分:0)

(这不是另一个答案,只是对kim366评论的解释)。

  

为什么$(OBJECTS):$(SOURCES)不起作用?

扩展到

a.o b.o c.o : a.c b.c c.c
    compiler command

这不是一个规则,告诉你如何从a.c创建a.o,从b.c创建b.o,从c.c创建c.o

这实际上是三条规则;它相当于

a.o : a.c b.c c.c
    compiler command
b.o : a.c b.c c.c
    compiler command
c.o : a.c b.c c.c
    compiler command

通常,您可以在(GNU)make中使用两种规则:显式规则(其中依赖项列表由手指定)和模式/后缀规则(其中推导出依赖项列表)。在这两种情况下,目标都是单个文件。实际上,make对于生成多个文件的命令很困难(源代码生成器,如lexyaccprotobuf等。

例如,您无法告诉make protoc同时创建.cc和.h文件:

%.pb.cc %.pb.h : %.proto
    protoc .... $<

这是两个单独的规则,我已经看到它在并行构建多个作业时启动两个单独的protoc进程(使用相同的命令行)。