ofsp2024-00 基本实现和开发

Created time
Jul 10, 2025 10:54 AM
type
Post
status
Published
date
Jul 10, 2025
slug
ofsp2024-00
summary
tags
2024
ofs
ofsp2024
OpenFOAM
category
post
icon
password
Place
Last edited time
Mar 27, 2026 01:05 AM
😀
前言: 访问 https://aerosand.cc 以获取最近更新。
 
 
参考:
感谢原作者们的无私引路和宝贵工作。
前置:
强烈建议在学习过计算流体力学基础以及有限体积法之后再开始本系列学习。至少也要同时开始,不然最后可能很难理解 OpenFOAM 求解器标准算法。
OpenFOAM 是什么呢?引用 wiki 解释如下
OpenFOAM (for "Open-source Field Operation And Manipulation") is a C++ toolbox for the development of customized numerical solvers, and pre-/post-processing utilities for the solution of continuum mechanics problems, most prominently including computational fluid dynamics (CFD).
我们从简单的 C++ 程序实现开始,简单了解编译原理,通过 makefile 逐渐掌控我们的项目,过渡到了解 OpenFOAM 的 Make 实现方式,然后认识 OpenFOAM 的基本程序,最后逐渐深入 OpenFOAM 的程序开发。
鉴于 OpenFOAM 的使用环境,我们选择在 ubuntu 24.04 系统环境中,基于 OpenFOAM 2306 版本进行开发,方便起见使用 vscode 工具。
OpenFOAM 的安装,vscode 的安装,快捷命令的自定义等讨论参见 OpenFOAM 环境准备 | 𝓐𝓮𝓻𝓸𝓼𝓪𝓷𝓭 (aerosand.cn)

1. 原生实现

我们使用 C++ 写一段简单的 “hello world” 程序。

1.1. hello world

对于 OpenFOAM 来说,不管是求解器还是算例,放在任何一个文件夹都可以。放在 $FOAM_RUN 路径下也是为了方便管理。
比如,此系列讨论中,我们把项目放在自建文件夹 /userPath/ofsp 之下(/userPath/ 即用户自定义的文件夹路径,用户替换成自己的路径),并定义了快捷命令 ofsp 快速跳转到该路径下。快捷命令的自定义使用请参考 OpenFOAM 环境准备 | 𝓐𝓮𝓻𝓸𝓼𝓪𝓷𝓭 (aerosand.cn)
我们使用如下约定
  • userPath/:用户指定路径,该路径下再新建例如 userPath/ofsp/ 文件夹,ofsp/ 下再新建各个项目
  • userProject/:用户指定项目路径,在 userPath/ofsp/userProject/ 文件下存放具体的项目文件
例如,新建总项目文件夹(// terminal 表示下面命令需要在终端输入执行)
ofsp 即 OpenFoam sharing programming 的缩写
在用户路径下,建立本章节的项目文件夹。
详细终端命令演示如下
通过 vscode 打开项目后,可以使用 ctrl + ~ 唤出 vscode 的终端控制台,快捷进行命令操作。
终端中使用命令新建文件
终端中可以使用 tree 命令查看文件树状结构(命令参考 OpenFOAM 常用指令 | 𝓐𝓮𝓻𝓸𝓼𝓪𝓷𝓭 (aerosand.cn)
最后,我们能看到文件结构为
我们约定在文件表示中,名称后加了 / 的表示文件夹,没有的表示文件。
我们分别写入示例代码,内容如下
类的声明 Aerosand.h
代码风格:
本系列讨论的代码尽量贴近 OpenFOAM 的代码风格,比如私有成员变量名称尾缀下划线。
类的定义 Aerosand.cpp
主源码 main.cpp
虽然我们笼统的把代码到程序的整个过程称为“编译”,实际上,在 Linux 系统下,C++ 程序的编译过程分为四个过程。
我们将逐步拆解并实现各个环节。

1.2. 预处理

将程序代码中包含的 #include 文件插入替换到原文件中,在 Linux 系统下生成中间预处理输出文件(后缀 .i 文件)。
我们在终端里通过命令执行这一过程
g++ 的 -E 标识指定编译器进行预处理g++ 的 -o (小写)标识指定编译器生成文件的名称
结果生成 Aerosand.imain.i 文件。
后缀 .i 表示 intermediate preprocessor output 中间预处理输出

1.3. 编译

编译器对预处理后的中间预处理输出文件进一步语法分析,在 Linux 系统下生成汇编语言形式的源文件(后缀 .s 文件)。
终端中执行编译过程
g++ 的 -S 标识指定编译器进行编译(大写 S )
结果生成 Aerosand.smain.s 文件。
后缀 .s (小写)表示 source code written in assembly 汇编语言形式的源文件

1.4. 汇编

编译器把编译后的汇编语言形式的源文件转换成可执行机器指令,在 Linux 系统下生成目标文件
终端中执行汇编过程
g++ 的 -c (小写)标识指定编译器进行汇编
结果生成 Aerosand.oof00_0.o 文件。
后缀 .o (小写)表示 object file 目标文件

1.5. 动态库

当项目中有大量“类”的时候,我们希望某些“类”能固定下来提供某种“方法”,这种“方法”就形成一个可以重复使用的“库”(library)。当其他项目使用这个库的时候,库本身无需再次“预处理”,“编译”以及“汇编”,仅仅和这个项目链接即可。
因为静态库开销大,浪费空间,更新维护困难,所以 OpenFOAM 大量使用动态库,我们这里也只以动态库为例。
动态库在程序编译时并不链接到目标代码,而仅仅在程序运行时才被链接载入。不同的程序如果调用相同的库,那么内存里只需要一份该动态库的可分享实例,这样就大大减少了空间浪费。此外,因为动态库仅在程序运行时才被链接载入,所以库的单独维护更新也十分方便。
编译器可以对汇编后的 .o 目标文件进行整理形成动态库,在 Linux 系统下生成 .so 文件。
终端中执行生成动态库命令
g++ 的 -shared 标识指定生成动态链接库g++ 的 -fPIC 标识指定创建与地址无关的编译程序,f 即 file,PIC 即 position independent code动态库文件以 lib 开头
生成 Aerosand.so 文件,该文件就是可链接的动态库。
后缀 .so 代表着 shared object 共享目标

1.6. 链接

编译器把所有的目标文件以及库文件都组织成一个可以执行的二进制文件。
使用 echo 命令查看原本动态库链接路径,可以发现并不是项目本地路径。临时指定动态库路径为当前文件夹(不要担心,临时指定不影响 OpenFOAM 动态库路径的环境配置)。
终端中将主源码目标文件和动态库链接,生成可执行文件
g++ 的 -L 标识紧跟指定的库的路径, 使用 -L. 表示动态库在当前路径g++ 的 -l 标识紧跟指定的库的名称,使用时省略 lib 字段
最终生成 main 可执行程序。
注意,上面指定的动态库路径是临时的,如果重启计算机,想要再次运行 main 程序,必须要再次指定动态库路径。
需要知道的是,无论是把新开发的库放在本项目下,或是其他特定路径下,每个项目都可以链接使用这个动态库,只要指定正确的链接路径。这也是动态库“相对独立”“自由链接”的意义所在。

1.7. 运行

总结整个过程如下
 
运行该先项目
运行结果为

2. make 实现

上一节的编译过程虽然清晰,但是一步一步的执行十分繁琐。
为了简化项目编译,以及兼顾理解编译细节,我们采用 make 工具来管理我们的开发项目。很多人也会使用 cmake 来构建项目,cmake 更加简洁高效,不过本质上也是基于 makefile 的。
我们可以为项目提供 makefile 文件通用的描述所有执行步骤。这样只需要简单执行 makefile 文件就可以编译整个项目,大大方便调试运行。此外,上面项目的所有代码文件都放在一起,十分不方便,所以我们对代码进行分类管理。

2.1 项目准备

我们建立新项目 ofsp_00_helloWorld_make
文件结构如下:
在我们早期开发的很多情况下,开发的库只是某个项目的特定库。所以,我们仍然把包含众多 形成的 开发库 作为一个文件夹放进开发项目内。项目根目录下有项目主源码, 项目的 项目 makefile ,以及开发库文件夹。开发库文件夹内有库自己的 库 makefile。文件结构清晰,层次明确。
因为头文件路径有变化,主源码头文件包含修改为
其他代码的内容保持不变。
Loading...