You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

请求解释给定Fortran Makefile的语法及各代码段含义

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.fMain.o依赖Main.f)。
  • 当对应的.f文件有更新,或者.o文件不存在时,Make会执行后面的命令:$(FC) $(FCFLAGS) -o $@ $^,也就是用gfortran编译器,加上你指定的编译选项,把.f源文件($^)编译成对应的.o目标文件($@)。简单说,只要你的.f源文件有修改,Make就会自动重新编译这个文件,生成最新的.o文件。

内容的提问来源于stack exchange,提问作者Helmut K.

火山引擎 最新活动