简介:面向需要在 Visual Studio Code 中编写和运行 Fortran 代码的用户,这套压缩包提供了从环境搭建到代码调试的完整支持,尤其适合备战 VNOI 等算法竞赛的选手和从事科学计算的科研人员。压缩包内共有 99 个文件,涵盖可执行的 exe 程序、保存工程结构的 sln 与 vfproj 项目文件、以 for 为后缀的 Fortran 源代码、编译生成的 obj 中间产物,以及多份 PDF 格式的教程与参考文档,整体大小约 20.6MB,便于用户对照学习并快速还原一个完整的 Fortran 项目。目前已有 371 人浏览学习,说明其在同类资料中具有一定参考热度。通过资源中的示例与说明,读者可以掌握编译器配置、任务与调试设置,也能了解常见竞赛题目在 Fortran 下的实现方式,包括输入输出、数组与矩阵处理、循环分支等核心语法,从而在实践练习中提升数值计算与算法编程能力。
1. 拿到 FORTRAN.rar 之后:这不是老古董压缩包,是一套能直接跑的 VSCode Fortran 环境
我最近从同事手里接过一个 FORTRAN.rar,压缩包名字看着像上世纪的东西,解压后却发现里面装的是一整套给 VSCode 用的 Fortran 开发环境配置:tasks.json、launch.json、settings.json,外加几个示例.f90源文件。它的目标很直接——让一个刚接手 Fortran 遗留代码的工程师,从零到能断点调试,全程不碰那些又贵又笨重的商业 IDE。Fortran 至今在科学计算、数值仿真和大量遗留工业代码里仍是主力语言,而 VSCode 配合 gfortran 和 Modern Fortran 插件,是目前综合成本最低的轻量方案。这篇文章就把这套配置从头拆到尾,讲清楚为什么这么搭、每一步怎么设置,以及新手最容易在哪翻车。
2. 搭建前先定编译器:gfortran 是 VSCode 里跑 Fortran 的合理选择
2.1 编译器生态对比:gfortran 为什么是默认答案
先说结论:在 VSCode 里做 Fortran 开发,编译器选 gfortran,基本没有第二个值得犹豫的选项。
目前还在活跃维护的 Fortran 编译器主要有三支:GCC 套件里的 gfortran、英特尔的 ifort(经典版)和 ifx(新版)、以及 NAG 的商用编译器。英特尔编译器在 x86 平台上性能确实好,对现代 Fortran 标准支持也全,但它是商业授权,配置起来更麻烦——要装 Intel oneAPI 工具包,体积几个 GB,在 VSCode 里对接 tasks 和调试器也不顺滑。NAG 更不用说,主要服务大型商业客户。gfortran 是 GNU 项目的一部分,跟随 GCC 一起发布,Windows 下有成熟的二进制发行版,免费、跨平台,对 Fortran 2018 标准的支持在逐步补齐,而且和 VSCode 的 C/C++ 调试体系(gdb)天然匹配。
另一个选型上的关键点:gfortran 与 Fortran 语言服务器(fortls)的配合度高。fortls 在解析代码时依赖编译器预处理器和你配置的 include 路径,gfortran 的参数规则简单清晰,两者之间的坑最少。你要是用 ifx,fortls 也能配,但碰到诊断信息格式和标准版本不一致的情况,排查起来就是无底洞。科学计算领域还有一个现实因素——大量开源数值库(LAPACK、netCDF-Fortran、OpenBLAS 的 Fortran 接口)的官方构建文档默认就是 gfortran,跟着生态走能少踩很多编译兼容性的坑。
2.2 Windows 下 gfortran 的安装:MSYS2 与 MinGW-w64 的取舍
在 Windows 上装 gfortran,常见做法是走 MSYS2 或者直接解压 MinGW-w64 的离线包。我一般推荐 MSYS2,理由有两个:一是包管理器维护更新,随时可以用pacman -Syu跟上 GCC 版本;二是 MSYS2 自带的 gdb、make、cmake 能一起装,后续做调试和工程构建不用到处找依赖。
安装步骤很直接:到 MSYS2 官网下载安装器,装到默认目录C:\msys64,安装完成后打开 MSYS2 MINGW64 终端,先执行:
pacman -Syu这条命令会把 MSYS2 自身的运行时和核心包更新到最新。首次执行时它会要求你关闭终端重新打开,这是正常现象,因为核心组件被替换了。更新完成后再执行:
pacman -S mingw-w64-x86_64-gcc-fortran注意包名里的gcc-fortran是 gfortran 这一个子包,mingw-w64-x86_64前缀代表面向 64 位 Windows 的 MinGW-w64 工具链。如果你还需要编译 Fortran 依赖库,比如 BLAS/LAPACK 源码或 netCDF,通常要补装mingw-w64-x86_64-gcc、mingw-w64-x86_64-make、mingw-w64-x86_64-gdb,一条命令全装齐:
pacman -S mingw-w64-x86_64-gcc-fortran mingw-w64-x86_64-gcc mingw-w64-x86_64-gdb mingw-w64-x86_64-make这里解释一下,MSYS2 其实包含了三个子环境:MSYS2 原生环境、MINGW64 和 UCRT64。我们装的是 MINGW64 子环境,它的程序在C:\msys64\mingw64\bin下,依赖的 DLL 也都在这一个目录里,所以把这个目录加进 PATH 后,gfortran、gdb 和 make 在外部的 VSCode 终端里就能直接跑。另外一个细节:不要把 MSYS2 自己的/usr/bin路径加进 Windows PATH,那会把一堆 Unix 工具和 Windows 命令行工具混在一起,后面的麻烦比省下的功夫多得多。
2.3 验证编译器:PATH 设置与 Hello World
配置 PATH 不想进系统设置界面的话,可以在 PowerShell 里用一条命令完成:
[Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\msys64\mingw64\bin", "User")这条命令把C:\msys64\mingw64\bin追加到当前用户的 PATH,"User"表示写进用户级环境变量,不需要管理员权限。注意必须新开一个终端窗口才会生效,因为已启动的会话里 PATH 不会自动刷新,这一点 VSCode 也一样,改完环境变量要完全重启 VSCode。然后验证:
gfortran --version看到类似GNU Fortran (MinGW-W64 x86_64-msvcrt-...)的输出就说明编译器就位了。顺手把 gdb 也验证一下:
gdb --version接下来写一个最小 Fortran 源文件,跑通第一轮编译:
program hello implicit none print *, 'Hello, Fortran in VSCode!' end program hello保存为hello.f90,在 VSCode 的终端里执行:
gfortran -g -Wall -o hello.exe hello.f90 ./hello.exe能输出Hello, Fortran in VSCode!就算跑通。这里的-g是生成调试信息,后面 launch.json 做断点调试时要靠它;-Wall打开全部编译警告,写严肃代码的人应该习惯开着它。-o hello.exe指定输出文件名,不写的话默认生成a.exe,多文件工程时容易乱。
这里有几个一开始就要避掉的坑。第一,如果 VSCode 终端里敲 gfortran 提示“不是内部或外部命令”,但系统 cmd 里能识别,多半是 VSCode 没重启,旧终端的 PATH 没刷新。第二,如果你之前装过 Conda 的 gfortran,PATH 里路径先后顺序会决定实际调用的是哪一个——执行where gfortran看解析到哪个路径。如果解析到 Conda 的 bin,建议把 MSYS2 的路径挪到前面,别让一个封装的旧编译器干新活。
3. 解开 FORTRAN.rar 里的编辑器配置:Modern Fortran 插件与 settings.json 逐项解释
3.1 VSCode 插件市场里选谁:Modern Fortran 是当前唯一值得装的主力
VSCode 的扩展市场里搜 Fortran 会看到好几个插件,名字相近但维护状态差异很大。目前维护最活跃、功能最完整的是Modern Fortran,发布者 ID 是fortran-lang.fortls,由 fortran-lang 社区维护,内置了 Fortran 语言服务器(fortls),负责提供函数跳转、语法高亮、智能提示和错误标注。另一个常见的Fortran(发布者 REVA)基本只有语法高亮,功能单薄,不推荐当主力。还有叫Fortran IntelliSense的插件,曾经是另一个语言服务器客户端,现在基本停止更新,新机器上直接跳过。
安装方式就是在扩展市场搜modern fortran,认准发布者fortran-lang再装。装完之后,你的.f90、.f95、.f文件会自动获得语法高亮,打开源码文件后,左侧大纲视图会列出 module、subroutine、function 的完整层级。这些能力全部走 fortls 的 Language Server 协议,也就是说它的行为是可以通过 settings.json 里以fortran.fortls.*为前缀的选项去控制的。
这里要理解一个机制:fortls 本身不编译代码,它只做静态解析。它对符号的把握来自于你配置的 include 目录里的.mod文件和源文件本身的结构。所以当你发现它报的错和 gfortran 不一致时,优先检查配置是否同步,而不是怀疑插件坏了。
3.2 settings.json 中必调的四个参数
FORTRAN.rar 里通常带一份配置好的.vscode/settings.json。没有的话按下面这份写,注释已经标出每个参数的作用:
{ "fortran.fortls.includeDirectories": ["${workspaceFolder}/include", "${workspaceFolder}/src"], "fortran.linterExtraArgs": ["-I./include", "-I./src"], "fortran.formatting.freeform": true, "[fortran]": { "editor.tabSize": 4, "editor.insertSpaces": true }, "files.encoding": "utf8", "files.autoGuessEncoding": false }按顺序说。includeDirectories是给 fortls 的预处理解析用的:当代码里出现#include "config.h"或者使用其他模块文件生成的.mod文件时,fortls 需要知道去哪找这些依赖。linterExtraArgs是传给 linter 的额外参数,-I./include的写法等价于 gfortran 命令行里的-I选项,这两块配合才能让语言服务器和编译器对同一份代码的解析结果保持一致。freeform指自由格式——现代 Fortran 源码默认是自由格式,不要打开固定格式,否则每行长度限制和缩进规则会完全不同。最后files.encoding设成utf8是为了让 VSCode 按 UTF-8 读取 Fortran 源码,这一点在你的注释里用了中文时特别关键。
特别强调一个容易误解的地方:linterExtraArgs里的-I路径是相对工作区根目录的,而 gfortran 实际编译时用的是 tasks.json 里传入的-I。两者必须一致,否则就会出现编辑器解析正确、真正 gfortran 编译却找不到头文件的诡异情况。我见过不少人在 settings 里写绝对路径,换一台机器或者换一个用户目录就全断,正确做法是统一用${workspaceFolder}变量前缀,这样工程可以整体复制到任何工作区目录。
{ "fortran.fortls.ignoreStandard": true }这个参数值得单独说。当你的代码面向比较老的 Fortran 标准(比如 F77 风格的固定格式程序),或者包含厂商扩展语法时,fortls 会因为“不符合标准”报一堆红波浪线。把ignoreStandard设成 true,语言服务器会降低对标准语法检查的严格程度,优先保证你能在旧代码里工作。但对新写的代码,我建议让它保持默认值 false,标准检查能在早期拦住不少隐式类型和未声明变量的低级错误。
3.3 调试扩展:为什么 Fortran 调试要装 C/C++ 插件
Modern Fortran 负责编辑体验,但断点要真正生效,还得装 VSCode 的 C/C++ 插件(扩展 ID 是ms-vscode.cpptools)。是的你没看错,Fortran 的断点和变量监视走的是 C/C++ 调试器的通道,因为 gdb 本身就能解析 Fortran 的 DWARF 调试信息,而 VSCode 里对 gdb 的图形化封装最成熟的实现就是cppdbg调试类型,它由 C/C++ 插件提供。
装完 C/C++ 插件后,你的 launch.json 才能用"type": "cppdbg"。这是 Windows 上 gdb 对接 VSCode 最常见也最稳的方式。如果你追求更现代的工具链,也可以尝试 CodeLLDB 扩展搭配 LLDB,对 Fortran 的表达式求值在某些场景下比 gdb 友好,但 Windows 上 CodeLLDB 需要额外配置 LLDB 可执行文件路径,第一台机器不建议走这条路,调试工作流本身的排障压力会分散你对语言的注意力。
插件装齐之后的检查清单:命令面板输入Fortran: Restart Fortran Language Server,能正常执行说明语言服务器已经注册;打开一个.f90文件,看状态栏是否有 fortls 图标。如果语言服务器启动失败,最常见的原因是扩展安装在旧版本 VSCode 上出现兼容问题,或者工作区里有多个 Fortran 扩展抢同一个语言服务器,把多余的禁用掉再重载窗口即可。
4. 把编译、运行、调试串成一条龙:tasks.json 与 launch.json 配置解读
4.1 tasks.json:在 VSCode 里一键编译 Fortran 的最小任务
Fortran 工程的编译与运行,本质上就是一条 gfortran 命令行。在 VSCode 里把这条命令固化成一个 task,按 Ctrl+Shift+B 就能执行,是效率提升的第一步。下面这份 tasks.json 是 FORTRAN.rar 里最常见的形态:
{ "version": "2.0.0", "tasks": [ { "label": "fortran: build single file", "type": "shell", "command": "gfortran", "args": [ "-g", "-Wall", "-o", "${fileDirname}\\${fileBasenameNoExtension}.exe", "${file}" ], "group": { "kind": "build", "isDefault": true }, "options": { "cwd": "${workspaceFolder}" }, "problemMatcher": { "owner": "fortran", "pattern": [ { "regexp": "^(.*):([0-9]+):([0-9]+): (fatal error|error|warning): (.*)$", "severity": 4, "code": 5, "file": 1, "line": 2, "column": 3, "message": 6 } ] } } ] }先说 command 和 args 的拼接逻辑:gfortran会收到参数-g -Wall -o {当前文件目录}\{当前文件名去掉扩展名}.exe {当前文件完整路径}。其中${fileDirname}和${fileBasenameNoExtension}是 VSCode 预置的变量,在当前活动文件是D:\code\hello.f90时,会展开成D:\code和hello,最终命令等价于手动执行gfortran -g -Wall -o D:\code\hello.exe D:\code\hello.f90。
problemMatcher这段是让 VSCode 能读懂 gfortran 的报错输出,并在“问题”面板里高亮错误位置。gfortran 对语法错误的输出格式是hello.f90:3:16: error: ...,正则里用编号把路径、行号、列号和严重级别分别映射到 VSCode 问题面板的字段。这个 matcher 对新手来说是最省事的一项配置,不写的话编译报错只堆在输出面板里,定位问题还要自己肉眼扫行号。
有个容易忽略的细节是${fileDirname}\\${fileBasenameNoExtension}.exe里的反斜杠。在 Windows 的 shell 任务里,VSCode 默认调用 cmd.exe 执行命令,路径分隔符用\\转义。如果你写成正斜杠/,大部分情况 cmd 也能解析,但在可执行文件名带空格的项目里会被截断成两个参数,报“不是内部或外部命令”的假错误。守规矩用反斜杠是最省心的做法。
4.2 launch.json:让断点真正起作用的调试配置
调试 Fortran 意味着启动 gdb 并加载编译好的 exe 与调试符号。下面这份配置对应调试面板里的“Fortran Debug”启动项:
{ "version": "0.2.0", "configurations": [ { "name": "Fortran Debug (gdb)", "type": "cppdbg", "request": "launch", "program": "${fileDirname}\\${fileBasenameNoExtension}.exe", "args": [], "cwd": "${workspaceFolder}", "stopAtEntry": false, "externalConsole": true, "MIMode": "gdb", "miDebuggerPath": "C:\\msys64\\mingw64\\bin\\gdb.exe", "preLaunchTask": "fortran: build single file" } ] }逐项说关键的。program就是要调试的可执行文件路径,规则和 tasks 里的完全一致,保证按 F5 时加载的就是刚编译出来的那个 exe。preLaunchTask指定启动调试前先执行的编译任务,这实现了一条龙:按 F5 → 先编译 → 再启动 gdb 并加载 exe。MIMode指 gdb 的 MI 接口,miDebuggerPath是 gdb 的绝对路径——这里C:\\msys64\\mingw64\\bin\\gdb.exe对应前面的 MSYS2 安装位置,改了安装目录要同步改这里。externalConsole设为 true 很关键:Fortran 程序里常见的read(*,*)和write(*,*)在集成终端里有时拿不到标准输入,或者输出刷新不及时,打开一个独立控制台能根治这类问题。
stopAtEntry: false表示启动后不会停在运行时的入口处。如果你调的程序包含 Fortran 运行时初始化逻辑,true 和 false 对你后续断点位置没有本质差别——你总会自己在目标行打上断点。我见过有人把这个字段设成 true 想“从第一行开始调”,实际效果是 gdb 停在了运行时库的内部函数里,反而每次都要手动 Continue 一次才能到源码,纯浪费时间。
要提醒的是,调试配置里最容易出错的就是miDebuggerPath和编译器版本不匹配。MSYS2 安装的 gfortran 和 gdb 来自同一套 MinGW-w64 工具链,天然配套;但如果你在系统里装过 Conda 的 gfortran,又让 launch.json 去 C:\msys64 找 gdb 加载 exe,会报“符号格式错误”或“无法读取 DWARF”。记住一个原则:gfortran 和 gdb 必须来自同一个工具链。
4.3 F5 之前的三项自检
配置都写完后,按 F5 之前花 30 秒做三项检查。第一,确认当前打开的文件是 Fortran 源文件而且已经保存。tasks 里用的${file}变量取自当前活动文件,如果活动的是别的语言文件,编译任务会拿那个文件去跑 gfortran,直接报文件格式不识别。这个坑我踩过不止一次——开着日志文件按 Ctrl+Shift+B,结果编译报错,折腾两分钟才反应过来标签页切走了。
第二,确认 gdb 在终端里能启动。直接执行gdb --version,如果报错,回第 2 章把 gdb 装好并加进 PATH。这个步骤最容易被跳过,但调试器启动失败的报错信息晦涩,往往给新手造成“Fortran 根本不能调试”的错觉,实际只是miDebuggerPath指向的 exe 不存在。
第三,确认 Fortran 文件已经用-g编译过。如果不带-g,gdb 加载后断点全部失效,设置断点时会提示无法插入,无调试信息。这条是纯玄学,因为 tasks 里默认带了-g,但如果你后来把编译任务改成发布版-O2,断点立刻废。检查时先看 tasks.json 里有没有-g,再看 gfortran 实际执行时有没有把它传给编译器。
5. VSCode 里写 Fortran 的避坑指南:编码、模块与 IntelliSense 失灵
Fortran 的生态比较特殊:语言标准老、编译器实现差异大、VSCode 周边工具还是社区维护。下面这些坑是真实项目里踩过并验证过解决方案的,按现象→原因→解决的方式写,遇到问题直接对照排查。
5.1 现象:中文注释和字符串变成了乱码
中文用户最容易在第一周撞上的坑。具体表现是用 VSCode 打开别人传过来的.f90文件,注释全是“锟斤拷”;或者自己写好中文注释保存再去编译,gfortran 提示非法字符。
原因分两种。一种是你用 UTF-8 写的文件,但 gfortran 默认按系统区域设置去解析源码字符——在中文版 Windows 上默认是 GBK(代码页 936),UTF-8 编码的中文字节串会被错误拆分。另一种反过来:别人用 GBK 存的文件,VSCode 按 UTF-8 打开,屏幕上看到乱码,编辑器里一改动就会波及整个文件。
解决方法是先确定文件原始编码:VSCode 右下角状态栏会显示当前编码(UTF-8 或 GBK),点击后选择“通过编码重新打开”,逐个试到正常显示为止。对需要长期维护的项目,统一为 UTF-8,并在 gfortran 编译参数里显式指定输入字符集:
gfortran -finput-charset=UTF-8 -fdiagnostics-color=always hello.f90-finput-charset=UTF-8明确告诉 gfortran 按 UTF-8 解析源码,-fdiagnostics-color=always让报错信息在终端里带颜色,扫起来轻松。如果你的源码是 GBK 存量文件,末尾还带乱码,更快的做法是写脚本统一转码成 UTF-8,而不是在编译器参数里做映射——编译器参数能救一时,救不了你下次在别的编辑器里打开又变乱码。
一个容易被忽视的点:如果你的 Fortran 文件在 Windows 上用了 GBK,而你在 VSCode 集成终端里运行编译,终端本身的代码页可能跟不上,导致编译输出里的中文内容也一团糟。这时在终端里执行chcp 65001切到 UTF-8 代码页,再跑编译,乱码立刻消失。
5.2 现象:编辑器红波浪线铺满,但是编译完全通过
Modern Fortran 插件的错误标注和 gfortran 实际编译结果不一致,这个很让人崩溃:代码在终端里能出正确结果,编辑器里却全是红波浪线。
原因是 fortls 的语言服务器解析不到某些 include 路径或模块文件,导致它认为你用了未定义符号。常见触发是代码里有#include "mpi.h"或use mod_something,而对应的头文件和.mod文件不在 fortls 默认搜索路径里。gfortran 编译时因为 tasks 里显式传了-I参数而风平浪静。
解决方法是把编译参数同步给语言服务器,对照第 3 章的 settings.json,把fortran.fortls.includeDirectories和fortran.linterExtraArgs补齐。这里有个经验值:-I路径要按实际模块所在目录来,不要偷懒只写根目录。比如你的.mod文件生成在build/目录,那 include 就该写build/而不是src/。fortls 对.mod文件的搜索优先级和 gfortran 不完全一致,两边的路径列表保持同样顺序能减少很多奇怪的偏差。
5.3 现象:module symbol 找不到,但编译却能过
比红波浪线更迷惑的是符号跳转失效:工程里别的文件写use my_mod,按住 Ctrl 点my_mod跳不进去,编辑器还提示“undefined module”。但实际编译完全正常,程序跑了几个星期都没出错。
原因是.mod文件不存在或者是残留旧版本。fortls 必须有my_mod.mod文件才能提供符号表和跳转:第一次编译会产生它,但你修改了my_mod.f90的接口而没重新编译,或者清理了 build 目录却没重跑编译,语言服务器就一直在看旧文件。
解决方法是先整个工程编译一遍,确认build/或源码目录里生成了所有.mod文件,然后在 VSCode 里执行Fortran: Restart Fortran Language Server,或者直接Developer: Reload Window重载窗口。这个操作我一般放在固定流程里:改.f90→ 跑编译 → 重启语言服务器。这十秒的仪式感能省下后面大半天的排查时间。
5.4 现象:启动调试时报“无法启动此程序,路径无效”
F5 之后没有任何反应,调试控制台里冒出类似Unable to start debugging. Program path 'xxx.exe' is missing or invalid的提示。
原因通常是三类。第一类是 exe 根本就没生成,也就是preLaunchTask里的编译任务失败了,但你没注意到输出面板里的错误。第二类是program路径和实际生成位置对不上,最常见是脚本把 exe 生成到了子目录,而 launch.json 还指向旧路径。第三类是 gdb 本体在 Windows 上启动失败——MSYS2 的 gdb 依赖几个运行时 DLL,如果C:\msys64\mingw64\bin不在 PATH 里,gdb 进程会直接闪退出错,连错误信息都没有。
解决步骤按优先级来:先在 VSCode 终端手动执行 tasks.json 里那条 gfortran 命令,确认 exe 真实存在;然后执行gdb --version确认 gdb 本体可用;最后如果 gdb 启动闪退,检查 PATH 里是否包含C:\msys64\mingw64\bin。注意顺序别颠倒——大多数人遇到这个问题会先去调 launch.json 的参数,但实际原因往往出在更前面的编译环节。
5.5 现象:编译出来的 exe 被杀毒软件拦截或闪退
你没看错,编译出来的 Fortran 可执行文件有时会被 Windows Defender 或第三方杀毒软件误报,尤其是用 MinGW-w64 这类没有代码签名证书的工具链直接编译的 exe。
解决方法是做白名单,而不是关杀毒:在 Windows 安全中心里把代码目录(例如C:\code\fortran_project)加进“排除项”,同时在 VSCode 首次打开文件夹时点击“信任”按钮。不信任工作区就进入受限模式,tasks、调试器全部禁用,这个下载提示容易顺手点掉,但不点信任你会发现编译任务都是灰的。
顺手补一个高危习惯:不要在C:\Windows\System32或者桌面根目录下建 Fortran 工程。前者会被权限机制和杀毒软件双重刁难,后者路径里大概率有空格和中文字符,在 tasks 和 PATH 上反复翻车。项目目录统一用纯英文路径,这是 Windows 上所有编译型语言工程师的老规矩,Fortran 没有特权。
6. 从单文件到多模块工程:用 Makefile 组织 Fortran 项目的可行路径
单文件用 tasks.json 就够了,但一个真实的 Fortran 项目动辄二三十个.f90文件,靠任务面板一条条编译不现实。这时常见做法是引入 Makefile,把编译依赖和模块顺序交给 make 统一管理。
一份最小可用的 Makefile 长这样:
FC = gfortran FFLAGS = -O2 -g -Wall -finput-charset=UTF-8 -I$(BUILD_DIR) BUILD_DIR = build SRCS = src/main.f90 src/mod_utils.f90 src/mod_solver.f90 OBJS = $(patsubst src/%.f90,$(BUILD_DIR)/%.o,$(SRCS)) app: $(OBJS) $(FC) $(FFLAGS) -o $@ $(OBJS) $(BUILD_DIR)/%.o: src/%.f90 | $(BUILD_DIR) $(FC) $(FFLAGS) -c $< -o $@ $(BUILD_DIR): mkdir -p $@ clean: rm -f app $(OBJS)这里OBJS用patsubst把源码路径映射到 build 目录,| $(BUILD_DIR)是 order-only prerequisite,确保目录先建好。Fortran 模块对编译顺序有硬约束:mod_utils必须先于mod_solver编译,因为后者use mod_utils时需要前者生成的.mod文件。MinGW 的 make 不会自动分析.mod依赖,因此SRCS的排列顺序就是你声明依赖顺序的方式——无依赖的模块放最前面,被依赖的放后面,否则第一次构建必然失败。这是 Windows 上 Fortran + Makefile 最常见的一次翻车现场。
如果你的工程规模再大,比如加入了外部依赖库或者需要跨平台 CI,我建议新应用直接上 fpm(Fortran Package Manager),它天然按依赖优先的规则管理模块编译顺序,一条fpm build就能拉取和处理所有依赖。不过很多遗留代码是上个时代的目录结构,改造成 fpm 的成本不小,这类代码用 Makefile 反而是更稳的选择。
我自己的习惯是:凡是接手超过一年的老 Fortran 仓库,先把-Wall打开全量编译一遍,把警告当作业绩清理干净,再谈功能改动——这些陈年代码的警告里往往藏着某个模块接口不一致的定时炸弹,编译期多花十分钟,运行期省三天。Fortran 语法本身不复杂,复杂的是几十年沉淀下来的老代码、奇怪的构建习惯和不统一的工具链,有一个干净、可从零复现的 VSCode 环境,比什么都强。希望帮到你。
本文还有配套的精品资源,点击获取