\chapter{编译器}\label{fortran_compiler}
\def\r{\text{\textregistered}}

\begin{table}[!htbp]
    \centering
    \begin{tabularx}{\textwidth}{|c|X|X|}
        \hline
        编译器&Ifx (+VS)&Gfortran (+VS Code)\\
        \hline
        类型&专有软件&自由软件\\
        \hline
        总空间占用&约 5.2 G&约 780 M\\
        \hline
        语法支持&略多于 Gfortran, 较宽松&略少于 Ifx, 较严格\\
        \hline
        自动纠错&无&有\\
        \hline
        自动补全&无&有\\
        \hline
        编译提示信息&次于 Gfortran&优于 Ifx\\
        \hline
        平均运行速度&快于 Gfortran&慢于 Ifx\\
        \hline
        \hline
        本笔记使用版本&
        2024.2.0, on Intel${}^\r$ 64, Build 20240602&
        13.2.0, 64-posix-seh-rev1, Built by MinGW-Builds\\
        \hline
    \end{tabularx}
    \caption{Ifx (+VS) 与 Gfortran (+VS Code) 的对比}
\end{table}

\section{安装}

\subsection[Intel${}^\r$ Fortran\\Compiler]{Intel${}^\r$ Fortran Compiler (Ifx)}

Windows 系统安装方式如下.
\begin{enumerate}
    \item 安装 \href{https://visualstudio.microsoft.com/zh-hans/thank-you-downloading-visual-studio/?sku=Community&channel=Release&version=VS2022&source=VSLandingPage&cid=2030&passive=false}
    {Visual Studio Community 2022}. 安装时可选择语言为中文.
    \item ``工作负载'' 选择 ``使用 C++ 的桌面开发''.
    \item 安装 \href{https://registrationcenter-download.intel.com/akdlm/IRC_NAS/7feb5647-59dd-420d-8753-345d31e177dc/w_fortran-compiler_p_2024.2.0.424.exe}{Intel${}^\r$ Fortran Compiler}.
    \item 找到开始菜单内 Intel oneAPI 2023 文件夹中的 Intel oneAPI command prompt for Intel 64 for Visual Studio 2022 和 Intel oneAPI command prompt for IA32 for Visual Studio 2022, 右键选择 ``更多'' $\rightarrow$ ``打开文件位置'', 可以找这两个东东的快捷方式. 然后右键这两个快捷方式, 选择 ``属性'', 把 ``起始路径'' 改成自己最常访问的路径 (比如桌面的路径), 然后点 ``应用'', 点 ``继续'', 点 ``确定''.\label{to_desktop}
\end{enumerate}

\subsection[GNU Fortran\\Compiler]{GNU Fortran Compiler (Gfortran)}

Windows 系统安装方式如下.\footnote{
    以下是直接安装 MinGW-w64 来安装 Gfortran 的, 但如果有 Python, 也许能直接通过 Pip (或 Conda) 来安装 Gfortran (或 MinGW-w64, MSYS2, \dots{})? 我也不知\dots{}
}
\begin{enumerate}
    \item 访问 \href{https://github.com/niXman/mingw-builds-binaries/releases}
    {MinGW-Builds-binaries releases}, 选择最新的 release 进入.
    \item 选带 posix 的; 64 位系统选带 x86\_{}64 的, 32 位系统选带 i686 的; Win 10 及以上选带 ucrt 的, Win 10 以下选带 msvcrt 的. 下载并解压.
    \item 把解压出来的名为 \ttt{mingw64} 的文件夹剪切到随便哪个目录. 暂称粘贴到的目录为 \ttt{[dir]}.
    \item 在系统环境变量 \ttt{Path} 中加入 \ttt{[dir]\bs{}mingw64\bs{}bin}.比如, 如果刚才粘贴到 \ttt{C:\bs{}Program Files}, 就加入 \ttt{C:\bs{}Program Files\bs{}mingw64\bs{}bin}.
    \item 下载 \href{https://code.visualstudio.com/sha/download?build=stable&os=win32-x64-user}{Visual Studio Code} 并安装.
    \item 打开 Visual Studio Code, 点击左边四个正方形飞出一个的图标, 搜索 C/C++,Modern Fortran 和 Code Runner 并安装.
    \item[] 如果已经装了 Python, 装 Modern Fortran 前先用 Pip\footnote{有 Conda 当然用 Conda 啦!} 装 fortls .
    \item 按 Ctrl+Shift+P, 然后选择 ``Preferences: Open Settings (JSON)'', 打开名为 \ttt{settings.json} 的 JSON 文件.
    \item 在 \ttt{settings.json} 里加入下面这些键值对.\label{add_key_value}
    \begin{lstlisting}[numbers=none]
"code-runner.executorMap": {
    "FortranFreeForm":
    "cd $dir; gfortran *.f*; if($?){.\a.exe}",
    "FortranFixedForm":
    "cd $dir; gfortran *.f*; if($?){.\a.exe}"
},
"code-runner.runInTerminal": true,
"code-runner.saveAllFilesBeforeRun": true
    \end{lstlisting}
\end{enumerate}
最后第 \ref{add_key_value} 步还需解释, 因为牵涉到 JSON 文件的语法. JSON 文件里的内容应该满足下面的形式.
\begin{lstlisting}[numbers=none]
{
  key_1: value_1,
  ...
  key_n: value_n
}
\end{lstlisting}
每一个形如 \ttt{key\_{}i: value\_{}i} 的东东称作一个键值对, 任意两个键值对之间用逗号隔开. 所以, 如果一开始 \ttt{settings.json} 里头空空如也, 则加入键值对后可能长这样.
\begin{lstlisting}[numbers=none]
{
  "code-runner.executorMap": {
    "FortranFreeForm":
    "cd $dir; gfortran *.f*; if($?){.\a.exe}",
    "FortranFixedForm":
    "cd $dir; gfortran *.f*; if($?){.\a.exe}"
  },
  "code-runner.runInTerminal": true,
  "code-runner.saveAllFilesBeforeRun": true
}
\end{lstlisting}
如果一开始 \ttt{settings.json} 里长这样,
\begin{lstlisting}[numbers=none]
{
  "editor.wordWrap": "wordWrapColumn",
  "editor.wordWrapColumn": 80,
  "workbench.colorTheme": "Red"
}
\end{lstlisting}
则加入键值对后可能长这样.
\begin{lstlisting}[numbers=none]
{
  "editor.wordWrap": "wordWrapColumn",
  "editor.wordWrapColumn": 80,
  "workbench.colorTheme": "Red",
  "code-runner.executorMap": {
    "FortranFreeForm":
    "cd $dir; gfortran *.f*; if($?){.\a.exe}",
    "FortranFixedForm":
    "cd $dir; gfortran *.f*; if($?){.\a.exe}"
  },
  "code-runner.runInTerminal": true,
  "code-runner.saveAllFilesBeforeRun": true
}
\end{lstlisting}
注意第 4 行最后要多加一个逗号来隔开键值对.

\section{使用}

CLI (Command Line Interface, 命令行界面) 和 GUI (Graphical User Interface, 图形用户界面) 两手都要抓, 两手都要硬. GUI 大家其实老熟了, 平常大家用手机电脑, 只要开机, 见到的就是 GUI. CLI 就是大家看电影里黑客们用的黑框框, 不过现在手机电脑进步了, 框框不一定是黑的, 也可能是红的蓝的之类的.

\subsection{使用 CLI}\label{use_ifx}\label{use_gfortran}

我们首先需要请出 CLI 框框. 用 Ifx 的同学请打开开始菜单内 Intel oneAPI 2023 文件夹中的 Intel oneAPI command prompt for Intel 64 for Visual Studio 2022 (32 位系统请打开 Intel oneAPI command prompt for IA32 for Visual Studio 2022). 用 Gfortran 请打开 Powershell, 可以在电脑桌面或文件夹中按鼠标右键然后点 ``在终端中打开'', 也可以按 Win+R, 输入 ``powershell'' 然后点 ``确定'', 还可以在 Visual Studio Code 中, 点上面 ``Terminal'' 后点 ``New Terminal''.

我们要熟悉 CLI 的运作流程. 首先我们需要在一些文本文档里写 Fortran 代码, 这些文本文档称为源代码文件 (source code file), 其文件后缀名一般是 \ttt{.f90}/\ttt{.for}/\ttt{.f}. 然后我们需要用编译器把每个源代码文件依次变成对应的目标文件 (object file), 这个过程称作编译 (compilation), Ifx 编译出的目标文件后缀名是 \ttt{.obj}, Gfortran 编译出的目标文件后缀名是 \ttt{.o}. 然后我们需要用编译器把所有目标文件合起来变成一个可执行文件 (executable file), 这个过程称作链接 (linking), Windows 系统中链接出的可执行文件后缀名是 \ttt{.exe}, Linux 系统中链接出的可执行文件后缀名一般是 \ttt{.out}. 广义的编译包括编译和链接. 最后我们需要命令电脑照可执行文件干活儿, 这个过程称为执行/运行 (execution), 我们平常也把执行程序称为跑 (run) 程序. 编译执行全流程如图 \ref{execute_run} 所示.
\begin{figure}[htbp]
    \centering
    \begin{tikzpicture}
        \node [rectangle] (work) at (0,0) {电脑工作};
        \node [rectangle] (exec) at (0,1) {可执行文件};
        \node [rectangle] (obj1) at (-2,2) {目标文件1};
        \node [rectangle] (obj) at (0,2) {\dots{}\dots{}};
        \node [rectangle] (objn) at (2,2) {目标文件n};
        \node [rectangle] (src1) at (-2,3) {源代码文件1};
        \node [rectangle] (src) at (0,3) {\dots{}\dots{}};
        \node [rectangle] (srcn) at (2,3) {源代码文件n};
        \draw [->] (exec.south) --  (work.north);
        \draw [->] (obj1.south) --  (exec.north west);
        \draw [->] (obj.south) --  (exec.north);
        \draw [->] (objn.south) --  (exec.north east);
        \draw [->] (src1.south) --  (obj1.north);
        \draw [->] (src.south) --  (obj.north);
        \draw [->] (srcn.south) --  (objn.north);
        \node [rectangle] (run) at (-4,0.5) {执行};
        \node [rectangle] (link) at (-4,1.5) {链接};
        \node [rectangle] (compile) at (-4,2.5) {编译};
    \end{tikzpicture}
    \caption{编译执行全流程示意图}
    \label{execute_run}
\end{figure}

现在俺们通过一个实例来掌握 CLI 的用法! 我们先在任意一个文件夹里新建两个空白文本文档 (默认的文件名应该是 ``\textsf{新建}\ttt{\ }\textsf{文本文档}\ttt{.txt}''), 分别把文件名改为 \ttt{main.f90} 和 \ttt{helloworld.f90} (注意要把拓展名 \ttt{.txt} 也给改掉, 不要改成 \ttt{main.f90.txt} 和 \ttt{helloworld.f90.txt} 哟).

打开 \ttt{main.f90}, 写入下面的内容并保存.
\begin{lstlisting}
program main
    implicit none
    call helloworld()
end program main
\end{lstlisting}

打开 \ttt{helloworld.f90}, 写入下面的内容并保存.
\begin{lstlisting}
subroutine helloworld()
    implicit none
    print *, 'Hello, world!'
end subroutine helloworld
\end{lstlisting}

请同学们弄出 CLI 框框. CLI 框框中会出现一些文字, 请同学们观察这些文字的最下面一行里包含的文件夹路径, 这个路径对应的文件夹称为当前工作目录 (current working directory). 如果当前工作目录不是 \ttt{main.f90} 和 \ttt{helloworld.f90} 所在的文件夹, 我们最好 ``\ttt{cd}'' 到 \ttt{main.f90} 和 \ttt{helloworld.f90} 所在的文件夹去, 用 Ifx 的同学需要在框框里输入 ``\ttt{cd /D }\textsf{目录}'' 然后按回车键, 用 Gfortran 的同学需要在框框里输入 ``\ttt{cd }\textsf{目录}'' 然后按回车键. 假设 \ttt{main.f90} 和 \ttt{helloworld.f90} 所在的文件夹是 \ttt{C:\bs{}Users\bs{}GasinAn\bs{}Desktop}, 那么我们输入 \ttt{cd /D C:\bs{}Users\bs{}GasinAn\bs{} Desktop} 或 \ttt{cd C:\bs{}Users\bs{}GasinAn\bs{}Desktop}然后按回车键. 这样CLI 框框中的文字就会有变化, 最下面一行里包含的的文件夹路径变成新的当前工作目录 \ttt{C:\bs{}Users\bs{}GasinAn\bs{}Desktop} 了.

然后俺们要编译, 用 Ifx 的同学需要在框框里输入 ``\ttt{ifx /c }\textsf{源代码文件$\!$1}\ttt{ ... }\textsf{源代码文件$\!$n}'' 然后按回车键, 用 Gfortran 的同学需要在框框里输入 ``\ttt{gfortran -c }\textsf{源代码文件$\!$1}\ttt{ ... }\textsf{源代码文件$\!$n}'' 然后按回车键. 所以用 Ifx 的同学需要在框框里输入 \ttt{ifx /c main.f90 helloworld.f90} 然后按回车键, 用 Gfortran 的同学需要在框框里输入 \ttt{gfortran -c main.f90 helloworld.f90} 然后按回车键.

然后俺们要链接, 用 Ifx 的同学需要在框框里输入 ``\ttt{ifx }\textsf{目标文件$\!$1}\ttt{ ... }\textsf{目标文件$\!$n}\ttt{ /o }\textsf{可执行文件}'' 然后按回车键, 用 Gfortran 的同学需要在框框里输入 ``\ttt{gfortran }\textsf{目标文件$\!$1}\ttt{ ... }\textsf{目标文件$\!$n}\ttt{ -o }\textsf{可执行文件}'' 然后按回车键. 所以用 Ifx 的同学可以在框框里输入 \ttt{ifx main.obj helloworld.obj /o a.exe} 然后按回车键, 用 Gfortran 的同学可以在框框里输入 \ttt{gfortran main.o helloworld.o -o a.exe} 然后按回车键, 得到可执行文件 \ttt{a.exe}.

最后我们要执行可执行文件, 需要在框框里输入 ``\textsf{可执行文件}'' 然后按回车键. 所以需要输入 \ttt{a.exe} 然后按回车键, 看到黑框框里蹦出 \ttt{Hello, world!} 就执行成功!

编译和链接的时候我们可以偷懒, 我们可以直接一步进行编译+链接两步, 用 Ifx 的同学需要在框框里输入 ``\ttt{ifx }\textsf{源代码文件$\!$1}\ttt{ ... }\textsf{源代码文件$\!$n}\ttt{ /o }\textsf{可执行文件}'' 然后按回车键, 用 Gfortran 的同学需要在框框里输入 ``\ttt{gfortran }\textsf{源代码文件$\!$1}\ttt{ ... }\textsf{源代码文件$\!$n}\ttt{ -o }\textsf{可执行文件}'' 然后按回车键. 所以用 Ifx 的同学可以在框框里输入 \ttt{ifx main.f90 helloworld.f90 /o a.exe} 然后按回车键, 用 Gfortran 的同学可以在框框里输入 \ttt{gfortran main.f90 helloworld.f90 -o a.exe} 然后按回车键, 即可直接得到可执行文件 \ttt{a.exe}. 同学们肯定要问有偷懒的办法干嘛不早说, 其实是因为同学们如果以后要写超大程序, 里面有成千上万个源代码文件, 这时候分两步编译和链接反而省事. 假设我们已经把成千上万个源代码文件编译+链接过一回了, 我们修改了其中一个源代码文件, 希望重新编译和链接, 如果我们再把成千上万个源代码文件一起编译+链接一回, 是会非常花时间的 (可能会花几个小时), 这时我们可以只把那个被修改了的源代码文件编译了, 然后再把成千上万个目标文件链接起来 (链接比编译快多了), 这样我们就能省下大把时间了呢.

以上内容总结如下.
\begin{table}[htbp]
    \centering
    \begin{tabular}{|p{45pt}|p{275pt}|}
        \hline
        ``\ttt{cd}'' 目录 & \ttt{cd /D }\textsf{目录} \\
        \hline
        编译 & \ttt{ifx /c }\textsf{源代码文件$\!$1}\ttt{ ... }\textsf{源代码文件$\!$n} \\
        \hline
        链接 & \ttt{ifx }\textsf{目标文件$\!$1}\ttt{ ... }\textsf{目标文件$\!$n}\ttt{ /o }\textsf{可执行文件} \\
        \hline
        编译链接 & \ttt{ifx }\textsf{源代码文件$\!$1}\ttt{ ... }\textsf{源代码文件$\!$n}\ttt{ /o }\textsf{可执行文件} \\
        \hline
        执行 & \textsf{可执行文件} \\
        \hline
    \end{tabular}
    \caption{Ifx 编译执行命令}
\end{table}
\begin{table}[htbp]
    \centering
    \begin{tabular}{|p{45pt}|p{275pt}|}
        \hline
        ``\ttt{cd}'' 目录 & \ttt{cd }\textsf{目录} \\
        \hline
        编译 & \ttt{gfortran -c }\textsf{源代码文件$\!$1}\ttt{ ... }\textsf{源代码文件    $\!$n} \\
        \hline
        链接 & \ttt{gfortran }\textsf{目标文件$\!$1}\ttt{ ... }\textsf{目标文件$\!$n}  \ttt  { -o }\textsf{可执行文件} \\
        \hline
        编译链接 & \ttt{gfortran }\textsf{源代码文件$\!$1}\ttt{ ... }\textsf{源代码文件  $\!$n}\ttt{ -o }\textsf{可执行文件} \\
        \hline
        执行 & \textsf{可执行文件} \\
        \hline
    \end{tabular}
  \caption{Gfortran 编译执行命令}
\end{table}

我们还可以偷懒. 首先我们可以用 ``\ttt{.}'' 表示 ``当前文件夹'', ``\ttt{..}'' 表示 ``上一层文件夹''. 所以\ttt{main.f90} 和 \ttt{helloworld.f90} 等价于 \ttt{.\bs{}main.f90} 和 \ttt{.\bs{}helloworld.f90} (虽然没人会自找麻烦这么写), 并且假设我们的当前工作目录是 \ttt{C:\bs{}Users\bs{}GasinAn\bs{}Desktop}, 我们 ``\ttt{cd}'' 到 \ttt{..\bs{}..} 就是 ``\ttt{cd}'' 到 \ttt{C:\bs{}Users}.

然后我们可以用通配符 (wildcard character), ``\ttt{?}'' 表示 ``任意一个不是 \ttt{.} 或 \ttt{\bs{}} 的字符'', ``\ttt{*}'' 表示 ``零个或任意多个不是 \ttt{.} 或 \ttt{\bs{}} 的字符''. 例如 \ttt{?.f?} 表示开头是一个字符, 中间是 \ttt{.f}, 结尾是一个字符的所有文件和文件夹, \ttt{*.f*} 表示开头是零个或任意多个字符, 中间是 \ttt{.f}, 结尾是零个或任意多个字符的所有文件和文件夹. 因此之前的 \ttt{main.f90 helloworld.f90} 我们都可以直接替换成 \ttt{*.f*}, 省大事了.

最后可以只输入文件或文件夹名称的前面几个字符, 然后按 Tab 键来自动补全文件或文件夹名称. 如果补全出的文件或文件夹不是我们想要的, 我们还可以多次按 Tab 键直到补全出的文件或文件夹是我们想要的. 同学们可输入 \ttt{he} 然后多次按 Tab 键查看效果. 

\subsection{使用 GUI}

\subsubsection{Visual Studio (VS)}

打开 Visual Studio, 点 ``创建新项目''.

然后搜索 ``Empty Project'', 找到下面标有 ``Fortran'', ``Windows'', ``控制台'' 的 ``Empty Project'', 选择之, 然后点击 ``下一步''.

然后把 ``项目名称'' 改成 ``HelloWorld'', ``位置'' 选择自己喜欢的文件夹 (比如桌面) 的路径, 点击 ``创建'', 然后就出现了编辑界面, 并且之前选择的文件夹内多出了一个名为 \ttt{HelloWorld} 的文件夹.

默认使用的是 Ifort\footnote{Intel${}^\r$ Fortran Compiler Classic, 这玩意儿 Intel 不想玩儿了, 要用 Ifx 来代替.}. 欲用 Ifx, 右键右边 ``解决方案资源管理器'' 里的 ``Console1 (Ifx)'',点最下面的 ``属性'', 左边选 ``配置属性'' $\rightarrow$ ``General'' (应已自动选上), 点 ``Use Compiler'' 右边的 ``Ifx Intel$\,\r$ Fortran Compiler Classic'', 点最右边的带向下标志的按钮, 改选成``IFX Intel$\,\r$ Fortran Compiler'', 点 ``应用'', 点 ``确定'',看到右边 ``Console1 (Ifx)'' 变成 ``Console1 (IFX)'' 即成功.

64 位系统, 若上面 Debug 后是 x86, 则可能需要将上面 Debug 后的 x86 改成 x64 (如不需要, 也最好改改). 点 x86 右边的向下箭头可以改, 若没有 x64, 可以点 ``配置管理器\dots{}'' 后尝试把 x64 调出来.

右击右边 ``解决方案资源管理器'' 中的 ``Source Files'', 选择 ``添加'' $\rightarrow$ ``现有项\dots{}'', 然后把之前的 \ttt{main.f90} 和 \ttt{helloworld.f90} 添加进来. 然后双击文件名即可打开文件.

点击上面的 ``调试'', 然后点 ``开始执行 (不调试)'', 看到下面框框里蹦出 \ttt{Hello, world!} 就用 Ifx 编译执行成功!

右击右边 ``解决方案资源管理器'' 中的 ``Source Files'', 选择 ``添加'' $\rightarrow$ ``新建项\dots{}'', 可以新建文件, 默认在 \ttt{HelloWorld} 文件夹里的 \ttt{HelloWorld} 文件夹里. 右击任意一个文件的文件名后, 可以点击 ``删除'' 或 ``重命名'' 进行删除或重命名操作.

关掉 Visual Studio, 重新打开, 左边多出了个 \ttt{HelloWorld.sln}, 点它就能回到编辑界面了.

\subsubsection{Visual Studio Code (VS Code)}

用 Visual Studio Code 打开 \ttt{main.f90}\footnote{之后同学们学 \ref{program_unit} 节, 会明白 \ttt{main.f90} 里写的是``主程序'', 所以打开它.}, 然后点右上方的白色三角儿就用 Gfortran 编译执行成功!
