03_wmake
0. 前言
在理解了 C++ 项目的 make 实现方式之后,我们现在可以更加容易的明白 OpenFOAM 提供的 wmake 实现方式。
本文主要
- 简单理解 wmake
- wmake 实现直接链接
- wmake 实现动态库链接
- 理解 Make 文件
- 编译运行 wmake 项目
1. 理解 wmake
OpenFOAM 中的 wmake 是一个基于 make 的构建工具,本质上是专门为 OpenFOAM 项目设计的一组脚本和配置文件。它简化了 OpenFOAM 的编译过程,并自动处理一些特定的依赖和路径设置。
- wmake 是一个包装了 make 的脚本,它设置了 OpenFOAM 编译所需的环境变量和规则
- wmake 会自动查找 OpenFOAM 的特定目录结构,并设置相应的编译选项(如包含路径、库路径等)
- wmake 提供了与 make 相似的接口,但针对 OpenFOAM 进行了优化
OpenFOAM 使用 Make/files
和 Make/options
实现 wmake
的编译管理。
Tip
可以简单理解为,Make 文件夹下的 files 和 options 两个文件一起承担了 makefile 的功能。
OpenFOAM 约定源文件后缀为 .C
,头文件后缀为 .H
。
为了让读者不要对文件架构感到困扰,这里作了不严谨的区分。OpenFOAM “项目层面” 的 .H
文件更多只是为了对主源码按功能进行拆分,方便代码阅读和维护,很多并不是类的头文件。这和 C++ 开发层面的头文件以及 OpenFOAM “源码层面”的头文件(如 $FOAM_SRC/OpenFOAM/dimensionSet/dimensionSet.H
)有些不同。
Tip
OpenFOAM 中,应用(application)包括
- 求解器(Solvers)
- 工具程序(Utilities)
- 预处理程序(Pre-processing Applications)
- 后处理程序(Post-processing Applications)
在本系列讨论中,我们所说的 “项目 Project” 是完整解决某个问题的所有内容,包括
- 求解器
- 调试算例
- 调用库
- 工具程序
- 等等
本文下面讨论的是简单的“源码层面”头文件。
2. 项目
终端输入命令,建立本文项目
ofsp
mkdir ofsp_04_wmake
code ofsp_04_wmake
继续使用终端命令或者使用 vscode 界面创建其他文件,最终文件结构如下
tree
.
├── Aerosand
│ ├── Aerosand.C
│ └── Aerosand.H
├── Make
│ ├── files
│ └── options
└── ofsp_04_wmake.C
库 Aerosand 的声明 Aerosand.H
如下
|
|
Warning
注意每个代码文件的最后都需要留个一个空白行,否则编译时 OpenFOAM 会警告 parse error
库 Aerosand 的定义 Aerosand.C
如下
|
|
应用主源码 ofsp_04_wmake.C
如下
|
|
OpenFOAM 提供了 Make 文件来帮助开发,其中
/Make/files
文件用于指定要编译的源文件以及生成的目标文件的名称和位置/Make/options
文件用于指定编译和链接选项,包括头文件路径和需要链接的库
注意,#include "Aerosand.H"
无需指定路径,这是因为我们将在 Make 文件中处理路径问题。
下面将讨论不同连接方式以及 Make 文件的细节。
3. 直接链接
类似于 02_helloWorld/3.4.链接
文中讨论的直接链接,OpenFOAM 中也可以实现。
3.1. 配置 Make
文件 ofsp_04_wmake/Make/files
内容如下
|
|
- 源文件为
Aerosand.C
和ofsp_04_wmake.C
- 生成目标文件的位置为
$(FOAM_USER_APPBIN)
- 生成目标文件的名称为
ofsp_04_wmake
文件 ofsp_04_wmake/Make/options
内容如下
|
|
- 前缀 EXE 表示这是可执行文件的配置(前缀 LIB 表示是库文件的配置)
- 后缀 INC 表示包含路径
- 使用
-I
标志指定头文件搜索路径 - 通常指向 OpenFOAM 模块的
lnInclude
目录(链接包含目录) - 可以包含系统头文件路径或第三方库头文件路径
- 使用
- 后缀 LIBS 表示库链接(直接链接无需链接任何库,可以留空不写)
- 使用
-l
标志指定需要链接的库 - 库名称不需要前缀
lib
和后缀.so
(如-lfiniteVolume
对应libfiniteVolume.so
) - 使用
-L
标志指定库搜索路径
- 使用
终端输入命令,执行编译
wclean
wmake
3.2. 编译
终端输出信息有三段,对应着应用编译的三个过程。
第一段是自定义的 Aerosand 类编译得到目标文件 Aerosand.o
(见输出信息的末尾处)
g++ -std=c++14 -m64 -pthread -DOPENFOAM=2406 -DWM_DP -DWM_LABEL_SIZE=32 -Wall
-Wextra -Wold-style-cast -Wnon-virtual-dtor -Wno-unused-parameter -Wno-invalid
-offsetof -Wno-attributes -Wno-unknown-pragmas -O3 -DNoRepository -ftemplate
-depth-100 -IAerosand -iquote. -IlnInclude
-I/usr/lib/openfoam/openfoam2406/src/OpenFOAM/lnInclude
-I/usr/lib/openfoam/openfoam2406/src/OSspecific/POSIX/lnInclude -fPIC
-c Aerosand/Aerosand.C -o Make/linux64GccDPInt32Opt/Aerosand/Aerosand.o
第二段是主源码编译得到目标文件 ofsp_04_wmake.o
(见输出信息的末尾处)
g++ -std=c++14 -m64 -pthread -DOPENFOAM=2406 -DWM_DP -DWM_LABEL_SIZE=32 -Wall
-Wextra -Wold-style-cast -Wnon-virtual-dtor -Wno-unused-parameter -Wno-invalid
-offsetof -Wno-attributes -Wno-unknown-pragmas -O3 -DNoRepository -ftemplate
-depth-100 -IAerosand -iquote. -IlnInclude
-I/usr/lib/openfoam/openfoam2406/src/OpenFOAM/lnInclude
-I/usr/lib/openfoam/openfoam2406/src/OSspecific/POSIX/lnInclude -fPIC
-c ofsp_04_wmake.C -o Make/linux64GccDPInt32Opt/ofsp_04_wmake.o
第三段是链接的过程,此处就是上述两个目标文件的直接链接,最终生成可执行文件(见输出信息的末尾处)
g++ -std=c++14 -m64 -pthread -DOPENFOAM=2406 -DWM_DP -DWM_LABEL_SIZE=32 -Wall
-Wextra -Wold-style-cast -Wnon-virtual-dtor -Wno-unused-parameter -Wno-invalid
-offsetof -Wno-attributes -Wno-unknown-pragmas -O3 -DNoRepository -ftemplate
-depth-100 -IAerosand -iquote. -IlnInclude
-I/usr/lib/openfoam/openfoam2406/src/OpenFOAM/lnInclude
-I/usr/lib/openfoam/openfoam2406/src/OSspecific/POSIX/lnInclude
-fPIC -Xlinker --add-needed -Xlinker --no-as-needed
Make/linux64GccDPInt32Opt/Aerosand/Aerosand.o
Make/linux64GccDPInt32Opt/ofsp_04_wmake.o
-L/usr/lib/openfoam/openfoam2406/platforms/linux64GccDPInt32Opt/lib \
-lOpenFOAM -ldl \
-lm -o /home/aerosand/OpenFOAM/aerosand
-v2406/platforms/linux64GccDPInt32Opt/bin/ofsp_04_wmake
编译的过程文件在 ofsp_04_wmake/Make/linux64GccDPInt32Opt/
文件夹下(根据平台可能会有所不同)。编译形成的可执行程序在 $FOAM_USER_APPBIN
文件夹下(上文在 Make/files
中指定)。
终端输入命令,可以找到所有生成成功的可执行程序
tree $FOAM_USER_APPBIN
3.3. 运行
这个可执行程序是个独立的程序,不需要从任何外部文件读取参数。得益于 OpenFOAM 环境变量,我们可以在任何路径下,都可以通过终端命令直接运行编译成功的程序。
终端输入命令
ofsp_04_wmake
可以看到运行结果
Hi, OpenFOAM! Here we are.
1 + 3.14159 = 4.14159
1 * 3.14159 = 3.14159
Current time step is : 0.2
4. 动态库链接
在实际的开发中,我们还是要使用动态库来保证内存和效率。
调整文件结构如下
.
├── Aerosand
│ ├── Aerosand.C
│ ├── Aerosand.H
│ └── Make
│ ├── files
│ └── options
├── Make
│ ├── files
│ └── options
└── ofsp_04_wmake.C
4.1. 库 Make
为库创建 Make 文件
文件 /Aerosand/Make/files
内容如下
Aerosand.C
LIB = $(FOAM_USER_LIBBIN)/libAerosand
- 注意库使用
LIB
而不是EXE
- 库的目标路径结尾是
LIBBIN
而不是APPBIN
- 目标文件需要加
lib
因为这个 Aerosand 库的实现不再进一步需要链接其他库,所以 /Aerosand/Make/options
直接空置即可。
终端输入命令,在根目录下编译这个库
wmake Aerosand
终端输出信息有两段,对应着编译的过程。
第一段是自定义的 Aerosand 库编译得到目标文件 Aerosand.o
(见输出信息的末尾处)
g++ -std=c++14 -m64 -pthread -DOPENFOAM=2406 -DWM_DP -DWM_LABEL_SIZE=32 -Wall
-Wextra -Wold-style-cast -Wnon-virtual-dtor -Wno-unused-parameter -Wno-invalid
-offsetof -Wno-attributes -Wno-unknown-pragmas -O3 -DNoRepository -ftemplate
-depth-100 -iquote. -IlnInclude
-I/usr/lib/openfoam/openfoam2406/src/OpenFOAM/lnInclude
-I/usr/lib/openfoam/openfoam2406/src/OSspecific/POSIX/lnInclude -fPIC
-c Aerosand.C -o Make/linux64GccDPInt32Opt/Aerosand.o
第二段将目标文件 Aerosand.o
编译成动态库 Aerosand.so
(见输出信息的末尾处)
g++ -std=c++14 -m64 -pthread -DOPENFOAM=2406 -DWM_DP -DWM_LABEL_SIZE=32 -Wall
-Wextra -Wold-style-cast -Wnon-virtual-dtor -Wno-unused-parameter -Wno-invalid
-offsetof -Wno-attributes -Wno-unknown-pragmas -O3 -DNoRepository -ftemplate
-depth-100 -iquote. -IlnInclude
-I/usr/lib/openfoam/openfoam2406/src/OpenFOAM/lnInclude
-I/usr/lib/openfoam/openfoam2406/src/OSspecific/POSIX/lnInclude -fPIC -shared
-Xlinker --add-needed -Xlinker
--no-as-needed Make/linux64GccDPInt32Opt/Aerosand.o
-L/usr/lib/openfoam/openfoam2406/platforms/linux64GccDPInt32Opt/lib \
-o /home/aerosand/OpenFOAM/aerosand
-v2406/platforms/linux64GccDPInt32Opt/lib/libAerosand.so
编译的过程文件在 ofsp_04_wmake/Aerosand/Make/linux64GccDPInt32Opt/
文件夹下(根据平台可能会有所不同)。编译形成的可执行程序在 $FOAM_USER_LIBBIN
文件夹下(上文在 Make/files
中指定)。
终端输入命令,可以找到所有生成成功的动态库
tree $FOAM_USER_LIBBIN
库内的类可能会有多个,甚至还有其他子库。库编译后会同时在库的路径下生成 lnInclude
文件夹,lnInclude
包含了该库所有类(/子库)的声明( .H
文件)或者实现 .C文件
的软链接目录(暂时可以简单理解成快捷方式),方便后续链接的时候可以提供统一简单路径。可以参考 OpenFOAM 的 $FOAM_SRC/OpenFOAM
库,可以看到根目录下有 lnInclude
文件夹,其中包含了此库内的所有类(/子库)的快捷方式。
终端输入命令,查看 Aerosand 库编译后的文件结构
Aerosand
├── Aerosand.C
├── Aerosand.H
├── lnInclude
│ ├── Aerosand.C -> ../Aerosand.C
│ └── Aerosand.H -> ../Aerosand.H
└── Make
├── files
├── linux64GccDPInt32Opt
│ ├── Aerosand.C.dep
│ ├── Aerosand.o
│ ├── options
│ ├── sourceFiles
│ └── variables
└── options
4.2. 项目 Make
因为 Aerosand 库已经被编译成了动态库,所以我们需要在项目的 Make 文件中进行指定。
修改 /Make/files
文件
ofsp_04_wmake.C
EXE = $(FOAM_USER_APPBIN)/ofsp_04_wmake
修改 /Make/options
文件
EXE_INC = \
-IAerosand/lnInclude
EXE_LIBS = \
-L$(FOAM_USER_LIBBIN) \
-lAerosand
- 前缀 EXE 表示这是可执行文件的配置(前缀 LIB 表示是库文件的配置)
- 后缀 INC 表示包含路径
- 使用
-I
标志指定头文件搜索路径 - 通常指向 OpenFOAM 模块的
lnInclude
目录(链接包含目录) - 可以包含系统头文件路径或第三方库头文件路径
- 使用
- 后缀 LIBS 表示库链接(直接链接无需链接任何库,可以留空不写)
- 使用
-l
标志指定需要链接的库 - 库名称不需要前缀
lib
和后缀.so
(如-lAerosand
对应libAerosand.so
) - 使用
-L
标志指定库搜索路径
- 使用
- 注意最后空置一行,避免 OpenFOAM 编译警告
Tip
我们常见的 OpenFOAM 求解器的 Make/options
中没有 -L
指定只有 -l
指定,这是因为那些求解器中使用的都是原生库,链接路径已经得到配置,无需进行 -L
路径指定,仅进行 -l
名称指定即可。如果是用户自定义库,编译结果在其他文件位置,当然就需要进行 -L
路径指定。
一定要注意路径,路径对于成功编译非常重要。一般指定的路径都是从项目根目录出发的(可以从根目录出发,定义其他库的绝对路径,见下文演示)。
4.3. 编译
终端输入命令,执行编译过程
wclean
wmake
终端输出信息有两段,对应着编译的过程。
第一段是主源码编译得到目标文件 ofsp_04_wmake.o
(见输出信息的末尾处)
g++ -std=c++14 -m64 -pthread -DOPENFOAM=2406 -DWM_DP -DWM_LABEL_SIZE=32 -Wall
-Wextra -Wold-style-cast -Wnon-virtual-dtor -Wno-unused-parameter -Wno-invalid
-offsetof -Wno-attributes -Wno-unknown-pragmas -O3 -DNoRepository -ftemplate
-depth-100 -IAerosand/lnInclude -iquote. -IlnInclude
-I/usr/lib/openfoam/openfoam2406/src/OpenFOAM/lnInclude
-I/usr/lib/openfoam/openfoam2406/src/OSspecific/POSIX/lnInclude -fPIC
-c ofsp_04_wmake.C -o Make/linux64GccDPInt32Opt/ofsp_04_wmake.o
第二段链接动态库到应用,并生成可执行文件 ofsp_04_wmake
(见输出信息的末尾处)
g++ -std=c++14 -m64 -pthread -DOPENFOAM=2406 -DWM_DP -DWM_LABEL_SIZE=32 -Wall
-Wextra -Wold-style-cast -Wnon-virtual-dtor -Wno-unused-parameter -Wno-invalid
-offsetof -Wno-attributes -Wno-unknown-pragmas -O3 -DNoRepository -ftemplate
-depth-100 -IAerosand/lnInclude -iquote. -IlnInclude
-I/usr/lib/openfoam/openfoam2406/src/OpenFOAM/lnInclude
-I/usr/lib/openfoam/openfoam2406/src/OSspecific/POSIX/lnInclude -fPIC -Xlinker
--add-needed -Xlinker --no-as-needed Make/linux64GccDPInt32Opt/ofsp_04_wmake.o
-L/usr/lib/openfoam/openfoam2406/platforms/linux64GccDPInt32Opt/lib \
-L/home/aerosand/OpenFOAM/aerosand-v2406/platforms/linux64GccDPInt32Opt/lib
-lAerosand -lOpenFOAM -ldl \
-lm -o /home/aerosand/OpenFOAM/aerosand
-v2406/platforms/linux64GccDPInt32Opt/bin/ofsp_04_wmake
同样,编译形成的可执行程序在 $FOAM_USER_APPBIN
文件夹下(上文在 Make/files
中指定)。
4.4. 运行
终端输入命令
ofsp_04_wmake
可以看到运行结果
Hi, OpenFOAM! Here we are.
1 + 3.14159 = 4.14159
1 * 3.14159 = 3.14159
Current time step is : 0.2
5. 小结
本文完成讨论
- 简单理解 wmake
- wmake 实现直接链接
- wmake 编译动态库
- 理解 Make 文件
- 编译运行 wmake 项目