利用VSCode阅读C++源码并调试OpenFOAM
创建时间: 2021-01-05 16:52:31
摘要: 本文总结win10系统中利用VS Code连接wsl或远程服务器阅读OpenFOAM源码以及调试OpenFOAM求解器的方法。相关内容对于原生Linux系统也适用。分两篇介绍,阅读源码篇说明如何实现代码提示、跳转,从而高效理解OpenFOAM的代码;调试篇介绍如何利用gdb远程调试OpenFOAM,首先介绍单版本的OpenFOAM,然后说明如何处理多版本的问题。
1 准备工作
win10上安装VSCode
VSCode安装
remote-wsl插件用于连接Linux子系统,remote-ssh插件用于连接远程Linux服务器连接到wsl或远程Linux服务器后,安装
C/C++插件
以上步骤可以自行搜索了解细节。如果是原生Linux系统,则可直接安装VSCode,然后安装C/C++插件即可。
下图展示连接局域网内的Ubuntu服务器(左下角有提示),并且安装了C/C++插件。

2 阅读源码篇
以icoFoam求解器为例。
在VSCode中按
win+`键(左上角同~键)打开集成的终端。
加载OpenFOAM环境,拷贝求解器: 如果终端配置文件中使用的是
source xxx/bashrc或. xxx/bashrc,则不需要额外激活OF环境; 如果是通过alias管理多版本OF,则输入对应的alias激活OF环境,如of6$ mkdir -p $WM_PROJECT_USER_DIR/solver $ cp -r $FOAM_SOLVERS/incompressible/icoFoam $WM_PROJECT_USER_DIR/solver/ $ cd $WM_PROJECT_USER_DIR/solver/icoFoam
修改
Make/files:icoFoam.C EXE = $(FOAM_USER_APPBIN)/myicoFoam
通过
wmake查看真实调用的编译命令,从中提取-I路径用于后续配置:$ wmake | tee log.wmake Making dependency list for source file icoFoam.C g++ -std=c++11 -m64 -Dlinux64 -DWM_ARCH_OPTION=64 -DWM_DP -DWM_LABEL_SIZE=32 -Wall -Wextra -Wold-style-cast -Wnon-virtual-dtor -Wno-unused-parameter -Wno-invalid-offsetof -Wno-attributes -O3 -DNoRepository -ftemplate-depth-100 -I/opt/openfoam6/src/finiteVolume/lnInclude -I/opt/openfoam6/src/meshTools/lnInclude -IlnInclude -I. -I/opt/openfoam6/src/OpenFOAM/lnInclude -I/opt/openfoam6/src/OSspecific/POSIX/lnInclude -fPIC -c icoFoam.C -o Make/linux64GccDPInt32Opt/icoFoam.o g++ -std=c++11 -m64 -Dlinux64 -DWM_ARCH_OPTION=64 -DWM_DP -DWM_LABEL_SIZE=32 -Wall -Wextra -Wold-style-cast -Wnon-virtual-dtor -Wno-unused-parameter -Wno-invalid-offsetof -Wno-attributes -O3 -DNoRepository -ftemplate-depth-100 -g -I/opt/openfoam6/src/finiteVolume/lnInclude -I/opt/openfoam6/src/meshTools/lnInclude -IlnInclude -I. -I/opt/openfoam6/src/OpenFOAM/lnInclude -I/opt/openfoam6/src/OSspecific/POSIX/lnInclude -fPIC -Xlinker --add-needed -Xlinker --no-as-needed Make/linux64GccDPInt32Opt/icoFoam.o -L/opt/openfoam6/platforms/linux64GccDPInt32Opt/lib \ -lfiniteVolume -lmeshTools -lOpenFOAM -ldl \ -lm -o /home/of/OpenFOAM/of-6/platforms/linux64GccDPInt32Opt/bin/myicoFoam $ cat log.wmake | sed 's/ /\n/g' | grep '\-I' | sort | uniq | sed 's/\-I//g' . lnInclude /opt/openfoam6/src/finiteVolume/lnInclude /opt/openfoam6/src/meshTools/lnInclude /opt/openfoam6/src/OpenFOAM/lnInclude /opt/openfoam6/src/OSspecific/POSIX/lnInclude $ pwd /home/of/OpenFOAM/of-6/solver/icoFoam
可以看到,这里的路径主要都是lnInclude,其中的文件都是软链接,指向各个文件的真实路径。
File → Open Folder,打开最后返回的路径:/home/of/OpenFOAM/of-6/solver/icoFoam。按
F1或Ctrl+Shift+p打开命令面板,然后输入C++ UI,找到C/C++ Configurations (UI),打开。在其中的includePath中添加前面得到的-I路径:

至此,就能实现代码提示和跳转了:

3 调试篇
以自定义求解器myicoFoam求解器为例。
3.1 单版本调试
参考视频:VS Code调试OpenFOAM
在VSCode中按
win+`键(左上角同~键)打开集成的终端。
加载OpenFOAM环境,拷贝求解器:
备注
注:假设这里是在
~/.bashrc中直接source来激活OpenFOAM环境;对于多版本OF调试,即通过alias激活对应环境的情况,后面再讨论。# $HOME/.bashrc设置 # alias of6=". /opt/openfoam6/etc/bashrc" source /opt/openfoam6/etc/bashrc #默认打开终端就激活OF环境 alias of8=". /opt/openfoam8/etc/bashrc"
$ mkdir -p $WM_PROJECT_USER_DIR/solver $ cp -r $FOAM_SOLVERS/incompressible/icoFoam $WM_PROJECT_USER_DIR/solver/ $ cd $WM_PROJECT_USER_DIR/solver/icoFoam
修改
Make/files:icoFoam.C EXE = $(FOAM_USER_APPBIN)/myicoFoam
修改
Make/options:EXE_INC = \ -g \ -I$(LIB_SRC)/finiteVolume/lnInclude \ -I$(LIB_SRC)/meshTools/lnInclude EXE_LIBS = \ -lfiniteVolume \ -lmeshTools
备注
注意:这里必须额外添加
-g选项。通过
wmake查看真实调用的编译命令,从中提取-I指向的路径用于后续配置includePath:$ wmake | tee log.wmake Making dependency list for source file icoFoam.C g++ -std=c++11 -m64 -Dlinux64 -DWM_ARCH_OPTION=64 -DWM_DP -DWM_LABEL_SIZE=32 -Wall -Wextra -Wold-style-cast -Wnon-virtual-dtor -Wno-unused-parameter -Wno-invalid-offsetof -Wno-attributes -O3 -DNoRepository -ftemplate-depth-100 -g -I/opt/openfoam6/src/finiteVolume/lnInclude -I/opt/openfoam6/src/meshTools/lnInclude -IlnInclude -I. -I/opt/openfoam6/src/OpenFOAM/lnInclude -I/opt/openfoam6/src/OSspecific/POSIX/lnInclude -fPIC -c icoFoam.C -o Make/linux64GccDPInt32Opt/icoFoam.o g++ -std=c++11 -m64 -Dlinux64 -DWM_ARCH_OPTION=64 -DWM_DP -DWM_LABEL_SIZE=32 -Wall -Wextra -Wold-style-cast -Wnon-virtual-dtor -Wno-unused-parameter -Wno-invalid-offsetof -Wno-attributes -O3 -DNoRepository -ftemplate-depth-100 -g -I/opt/openfoam6/src/finiteVolume/lnInclude -I/opt/openfoam6/src/meshTools/lnInclude -IlnInclude -I. -I/opt/openfoam6/src/OpenFOAM/lnInclude -I/opt/openfoam6/src/OSspecific/POSIX/lnInclude -fPIC -Xlinker --add-needed -Xlinker --no-as-needed Make/linux64GccDPInt32Opt/icoFoam.o -L/opt/openfoam6/platforms/linux64GccDPInt32Opt/lib \ -lfiniteVolume -lmeshTools -lOpenFOAM -ldl \ -lm -o /home/of/OpenFOAM/of-6/platforms/linux64GccDPInt32Opt/bin/myicoFoam $ cat log.wmake | sed 's/ /\n/g' | grep '\-I' | sort | uniq | sed 's/\-I//g' . lnInclude /opt/openfoam6/src/finiteVolume/lnInclude /opt/openfoam6/src/meshTools/lnInclude /opt/openfoam6/src/OpenFOAM/lnInclude /opt/openfoam6/src/OSspecific/POSIX/lnInclude $ pwd /home/of/OpenFOAM/of-6/solver/icoFoam $ which myicoFoam /home/of/OpenFOAM/of-6/platforms/linux64GccDPInt32Opt/bin/myicoFoam
备注
注意wmake实际调用的命令中新增了
-g选项,说明把该选项写在Make/options的EXE_INC中是有效的(虽然EXE_INC的原本目的是用来指定includePath)。这里要用到的路径是后面4个lnInclude路径以及pwd返回的icoFoam求解器路径。此外,通过which命令来获取编译得到的myicoFoam路径,因为调试的时候通常是在算例目录下。
小心
2021-01-08 20:13:05 更新(点击展开)
更准确的做法应该是通过环境变量WM_COMPILE_OPTION来控制。 即在拷贝求解器后只需要修改Make/files更改一下可执行文件的路径以及名称,然后终端运行WM_COMPILE_OPTION=Debug将默认的Opt编译模式切换成Debug模式。然后wmake即可以调试模式编译求解器。
说明:
终端运行echo $WM_COMPILE_OPTION可以发现该变量的值默认为Opt, 其定义的位置在OpenFOAM的环境加载文件中(即$WM_PROJECT_DIR/etc/bashrc中), 可以取值Opt、Debug以及Prof,分别表示优化(optimised),调试(debug)和分析(profiling)。 wmake会根据变量$WM_COMPILE_OPTION的值来加载不同的选项。 $WM_PROJECT_DIR/wmake/rules/linux64Gcc/c++文件中包含语句include $(DEFAULT_RULES)/c++$(WM_COMPILE_OPTION), 分别可能加载c++Opt、c++Debug和c++Prof文件中的选项设置。这3个文件所包含的内容如下:
# $WM_PROJECT_DIR/wmake/rules/linux64Gcc/c++Opt
c++DBUG =
c++OPT = -O3
ROUNDING_MATH = -frounding-math
# $WM_PROJECT_DIR/wmake/rules/linux64Gcc/c++Debug
c++DBUG = -ggdb3 -DFULLDEBUG
c++OPT = -O0 -fdefault-inline
# $WM_PROJECT_DIR/wmake/rules/linux64Gcc/c++Prof
c++DBUG = -pg
c++OPT = -O2
可以看到c++Debug文件中开启了-ggdb3,类似于-g选项,用于开启编译功能。
c++Prof中开启-pg选项,编译后的程序可以使用gperf之类的工具进行性能分析。
而默认的c++Opt中-O3则最大限度地优化程序。
拷贝测试算例,并通过
File → Open Folder在VSCode中打开测试算例:$ mkdir -p $WM_PROJECT_USER_DIR/run $ run $ cp -r $FOAM_TUTORIALS/incompressible/icoFoam/cavity/cavity . $ cd cavity $ pwd /home/of/OpenFOAM/of-6/run/cavity
Ctrl+Shift+D打开左侧的调试面板(Run),点击create a launch.json file创建launch.json文件
修改
launch.json文件:... "program": "/home/of/OpenFOAM/of-6/platforms/linux64GccDPInt32Opt/bin/myicoFoam", ... "stopAtEntry": true,
program的值即为自定义求解器的路径,通过which myicoFoam获得,而stopAtEntry设为true能在main函数处默认设置一个断点。按
F1或Ctrl+Shift+p打开命令面板,然后输入C++ UI,找到C/C++ Configurations (UI),打开。在其中的includePath中添加前面得到的-I路径以及求解器源码路径(注意与前一节有点差别)。
生成网格,按F5键开始调试。

3.2 多版本调试
以上是单OpenFOAM版本,实际场景中经常会安装多个版本,通过alias在各个版本之间切换,那以上调试方法还适用吗?
通过各种尝试折腾,终于想到了一个巧妙的解决方案,即通过包装一个新的gdb脚本来实现,具体方案如下。
讨论两个版本的情况:
$HOME/.bashrc配置如下:alias of6=". /opt/openfoam6/etc/bashrc" alias of8=". /opt/openfoam8/etc/bashrc"
创建一个目录专门用于存放脚本,比如
~/OFdebug:$ mkdir -p ~/OFdebug $ cd OFdebug $ touch of6-gdb.sh && chmod +x of6-gdb.sh $ touch of8-gdb.sh && chmod +x of8-gdb.sh
两个脚本的内容分别为:
of6-gdb.sh:#!/bin/bash . /opt/openfoam6/etc/bashrc /usr/bin/gdb "$@" # 将脚本接受的参数传给gdb命令
of8-gdb.sh:#!/bin/bash . /opt/openfoam8/etc/bashrc /usr/bin/gdb "$@" # 将脚本接受的参数传给gdb命令
修改
launch.json文件,通过miDebuggerPath指定编译器自定义的gdb脚本路径,比如使用of6来调试:... "miDebuggerPath": "/home/of/OFdebug/of6-gdb.sh", ...
调试cavity算例:
of6 # 激活环境 run cd cavity foamCleanTutorials # 清理算例 blockMesh # 生成网格 # ... 开始调试
4 相关参考
在研究gdb调试之前,主要尝试的就是gdbOF[1],能方便地将求解过程中的变量导出到文件,具体应用可以看知乎-陈与论[2]的介绍。目前OpenFOAMwiki上介绍适配的最高版本是OF5.x。
gdbOF is an attachable to GNU debugger (gdb) tool that includes macros to debug OpenFOAM’s solvers and applications in an easier way.
另一个角度,OpenFOAM成长之路[3]介绍了如何使用gdbserver调试。
使用 VS Code 调试远程服务器上的 OpenFOAM 代码。
5 结语
花了不少时间折腾,写作不易,希望能帮到学习OpenFOAM的小伙伴!