如何使用 Makefile 将目标文件放入不同的目录中?

How to place object files into a different directory using Makefile?

提问人:Roland Tóbiás 提问时间:11/7/2023 最后编辑:Roland Tóbiás 更新时间:11/8/2023 访问量:57

问:

请考虑以下 Makefile 片段:

FORTRAN = ifort -c
PATH_MOD = mod/
FILE_MOD = mod_constant.f90 mod_rot.f mod_test.f90
SOURCE_MOD = $(FILE_MOD:%=$(PATH_MOD)%)
OBJECT_MOD = $(FILE_MOD:%.f*=%.o)

$(OBJECT_MOD): $(SOURCE_MOD)
   $(FORTRAN) $(SOURCE_MOD)

clean:
   rm -f *.o

此脚本执行命令 。ifort -c mod_constant.f90 mod_rot.f mod_test.f90

但是,我想实现 [但没有目录中的其他文件] 中列出的所有文件都将在单独的行中编译,将目标文件放入目录中。 在本例中,脚本应运行以下命令序列:$(FILE_MOD)$(PATH_MOD)$lnk

ifort -c mod_constant.f90 -o lnk/mod_constant.o
ifort -c mod_rot.f -o lnk/mod_rot.o
ifort -c mod_test.f90 -o lnk/mod_test.o

有什么办法可以做到这一点吗?

makefile 编译

评论

0赞 MadScientist 11/7/2023
我不明白你问题的标题。你说的同时是什么意思
0赞 TobiR 11/7/2023
@MadScientist 实际上,这无关紧要。我已经删除了这句话。
0赞 MadScientist 11/8/2023
约翰给了你一个很好的答案。但我敢肯定,如果你在谷歌或你最喜欢的搜索引擎中输入这个问题的(新)标题,你会发现很多例子和答案,包括在StackOverflow上。这是一个非常常见的问题。
1赞 MadScientist 11/8/2023
我不明白你想要什么。Make 将只构建您要求它构建的对象文件。在上面的示例中,您从内容构造变量内容,因此这些目标文件是唯一将被编译的目标文件。这与上面显示的“应运行以下命令序列”的输出相匹配。OBJECT_MODSOURCE_MOD
1赞 MadScientist 11/8/2023
你应该试试看。模式规则只是模板,用于弄清楚如何构建您要求它构建的目标。它们不等同于 glob 语句,例如它将进入磁盘并查找所有可以构建的文件。这不是 make 的工作方式。ls *.f

答:

0赞 John Bollinger 11/8/2023 #1

这条规则...

$(OBJECT_MOD): $(SOURCE_MOD)
    $(FORTRAN) $(SOURCE_MOD)

表示要扩展到的列表中的每个目标都具有要扩展到的列表中的所有文件作为先决条件,并且应由要扩展到的命令生成。那根本不是你想要的。$(OBJECT_MOD)$(SOURCE_MOD)$(FORTRAN) $(SOURCE_MOD)

我想实现 [但没有目录中的其他文件] 中列出的所有文件都将在单独的行中编译,将目标文件放入目录中。$(FILE_MOD)$(PATH_MOD)$lnk

既然你似乎已经对GNU的版本做出了承诺,那么自然的方法是编写一个模式规则。实际上,或者两个,因为您有两种不同的源名称模式。如果您希望目标文件进入与其相应源不同的目录,那么这也将在此类规则中处理。例如make

lnk/%.o : %.f
        $(FORTRAN) -c $< -o $@

lnk/%.o : %.f90
        $(FORTRAN) -c $< -o $@

可以解释为通配符,但需要注意的是,规则目标中的外观和其先决条件列表中的外观必须扩展为同一字符串。%

是一个自动变量,它扩展到规则的先决条件列表的第一个实际元素,但要扩展 。扩展到正在构建的实际目标。$<%$@

另外,请注意,这些规则告诉了如何构建想要的文件,但您仍然需要以某种方式告诉它们需要构建。这通常是通过使它们成为某些规则的先决条件,尽管您可以改为依赖于从命令行显式请求其中的一个或多个规则。makemake

评论

0赞 TobiR 11/8/2023
感谢您发布此答案。但是,我想用相同的规则处理所有这三个 *.f(90) 文件,不包括其他 .f(90) 文件。我尝试了 [换行符] ,但它无法处理源/目标目录中是否有其他 *.f(90) 和 .o 文件。该变量将告诉要编译哪些文件,但我不知道如何在您的 Makefile 规则中使用这些变量。你有解决这个问题的方法吗?lnk/%.o : %.f*$(FORTRAN) -c $< -o $@$(OBJECT_MOD)/$(SOURCE_MOD)
1赞 MadScientist 11/8/2023
@JohnBollinger可能并不完全清楚:你应该删除你现有的规则(包括配方),并用他在这里展示的模式规则来代替它。然后,您应该添加一个目标,该目标取决于要构建的文件;例如:$(OBJECT_MOD): $(SOURCE_MOD)all: $(OBJECT_MOD)
0赞 John Bollinger 11/8/2023
@RolandTóbiás,您不必依赖此处提供的模式规则来构建任何其他文件,但需要注意的是,对于目标模式和先决条件模式的每个不同组合,您只能有一个模式规则。但是,模式规则肯定要求您对源具有不同的(模式)规则,而不是对源。这是 的局限性。.f.f90make
0赞 John Bollinger 11/8/2023
@RolandTóbiás,正如这个答案已经说过的那样,你可以通过告诉需要构建与这些规则匹配的目标(仅)来参与这些规则。MadScientist谈到了这一点,但我应该补充一点,目前在你问题的代码中定义的变量都没有提供这一点。您可能希望担任此角色,但它当前正在命名源目录中的对象文件,而您希望它命名目标目录中的对象文件 ()。makeOBJECT_MODlnk/
0赞 TobiR 11/8/2023
@JohnBollinger 感谢您的详细解释。事实上,我的 Makefile 中还有其他一些问题,我设法将其转换为 MWE (stackoverflow.com/questions/77441283/...在这个问题下,您的建议也非常感谢。