请求解释给定Fortran Makefile的语法及各代码段含义
首先,先把你提供的Makefile代码展示出来,方便对照分析:
# compiler FC = gfortran # compile flags FCFLAGS = -c -ffixed-line-length-72 -std=gnu -Wline-truncation -Wunused-variable # link flags FLFLAGS = # module files MODULES = Calculator.f # object files OBJS = Calculator.o OBJS += Main.o Common.o Io.o # program name PROGRAM = calFap all: $(PROGRAM) $(PROGRAM): $(OBJS) $(FC) $(FLFLAGS) -o $@ $^ %.o: %.f $(FC) $(FCFLAGS) -o $@ $^ mod: $(MODULES) $(FC) $(FCFLAGS) $@ $^ clean: rm -f *.o *.mod
接下来逐个解答你的疑问:
1. MODULES = Calculator.f 是否只是占位符?是否关联已存在的Calculator.f?
它不是占位符,这个变量明确指向了你文件夹中存在的Calculator.f模块源文件。不过要注意:当前Makefile里的mod目标命令写得有问题——$(FC) $(FCFLAGS) $@ $^中的$@代表目标名mod,会让编译器尝试生成一个叫mod的文件,这显然不是编译模块的正确方式。实际上,你不需要这个mod目标,因为后面的模式规则%.o: %.f已经会自动处理Calculator.f的编译,生成对应的Calculator.o和模块文件.mod。
2. 定义OBJS时,Calculator.o、Main.o等文件不存在,这样定义合理吗?
完全合理!这正是Makefile的核心作用之一:根据源文件自动生成不存在的目标文件。OBJS变量是告诉Make工具,最终生成可执行程序需要哪些.o文件;Make会自动检查对应的.f源文件是否存在,然后通过模式规则编译生成这些.o文件,你完全不需要手动提前创建它们。
3. 目标all: $(PROGRAM)用于编译整个程序,和Makefile的增量编译特性冲突吗?
一点都不冲突!all是一个伪目标,它的作用是把$(PROGRAM)(也就是calFap)设为默认目标——当你直接敲make命令时,Make会自动执行all目标,最终生成可执行程序。而Make的增量编译特性依然会生效:它会检查每个.o文件对应的.f源文件是否有更新,或者.o文件是否不存在,只重新编译那些需要更新的部分,最后再链接生成可执行文件。all只是指定了最终要完成的目标,不会强制全量编译。
4. 规则中-o $@ $^是什么含义?是否编译所有变更的目标文件?
首先先明确这个规则的正确结构(缩进是Makefile的关键):
$(PROGRAM): $(OBJS) $(FC) $(FLFLAGS) -o $@ $^
这里的-o $@是告诉编译器输出文件名为$@,而$@是Make的自动变量,代表当前目标(也就是calFap);$^代表当前目标的所有依赖文件(也就是OBJS里的所有.o文件)。这个步骤不是编译,而是链接:把所有已经编译好的.o目标文件链接成最终的可执行程序。在执行这个链接命令之前,Make会先确保所有依赖的.o文件都已生成(如果对应的.f文件有变更,会先调用模式规则重新编译)。
5. 模式规则%.o: %.f的作用是什么?.f文件变更时会执行什么操作?
这个是通用模式规则,核心作用是定义「如何从.f源文件生成对应的.o目标文件」:
%.o: %.f表示:任何一个.o文件,它的依赖是同名的.f源文件(比如Calculator.o依赖Calculator.f,Main.o依赖Main.f)。- 当对应的
.f文件有更新,或者.o文件不存在时,Make会执行后面的命令:$(FC) $(FCFLAGS) -o $@ $^,也就是用gfortran编译器,加上你指定的编译选项,把.f源文件($^)编译成对应的.o目标文件($@)。简单说,只要你的.f源文件有修改,Make就会自动重新编译这个文件,生成最新的.o文件。
内容的提问来源于stack exchange,提问作者Helmut K.




