【OpenFOAM】wmakeって何してるの

このエントリーは[オープンCAE Advent Calendar 2020](https://adventar.org/calendars/5192) の1日目です。

# はじめに

　OpenFOAMのアプリケーションおよびライブラリは`wmake`というコマンドでコンパイルされます。このコマンドの中で何が起きているのか、詳細に把握していなかったので調べて整理してみました。

# 概要

`wmake`では以下の動作を行っているみたいです。

- **`wmake`**を実行すると・・・
- **`make -f wmake/makefiles/general`**が実行される
    -  `wmake/makefiles/general`を`Makefile`として読み込む
        -  コンパイラオプションなどを指定
        -  いくつかの情報を`Make/files`と`Make/options`で補完
    -  `Make/files`を読み込む
        -  コンパイルするファイルを指定
        -  実行ファイル名を指定
    -  `Make/options`を読み込む
        -  includeファイルのあるディレクトリを指定
        -  共有ライブラリ(`lib*.so`)を指定
- 複数回の`g++`が実行される(`Makefile`の内容による)
  - **`g++`でコンパイル** (× オブジェクト数)
      -  オブジェクト(`*.o`)を生成
  - **`g++`でリンク**
      -  生成したオブジェクト(`*.o`)と指定した共有ライブラリ(`lib*.so`)をリンク
      -  実行ファイルを生成

# 実行環境

- **OS** : Ubuntu20.04 LTS / WSL2 Windows10
- **OpenFOAM** : v2006
- **GCC** : Ubuntu 9.3.0-17ubuntu1~20.04

# OpenFOAMのファイル構造

　本題に進む前に軽くOpenFOAMの特徴的なファイル構造について説明します。
　OpenFOAMは多くのクラスと実行ファイルを持つツールボックスです。
『実行ファイル同士で共通した機能が多い』『実行ファイルや継承クラスを自作することをユーザーが前提としている』などの特徴から、クラスと実行ファイルをそれぞれ別でコンパイルする仕組みになっています。実行ファイルの作成の際に必要なクラスをリンクすることになります。

> **OpenFOAM v6 User Guide: 3.2 Compiling applications & libraries**
[cfd.direct/openfoam/user-guide/v6-compiling-applications/](https://cfd.direct/openfoam/user-guide/v6-compiling-applications/)
A class is defined through a set of instructions such as object construction, data storage and class member functions. The file that defines these functions — the class definition — takes a .C extension, e.g.  a class nc would be written in the file nc.C. This file can be compiled independently of other code into a binary executable library file known as a shared object library with the .so file extension, i.e. nc.so. When compiling a piece of code, say newApp.C, that uses the nc class, nc.C need not be recompiled, rather newApp.C calls the nc.so library at runtime. This is known as dynamic linking.
![Figure 3.1: Header files, source files, compilation and linking](https://cdn.cfd.direct/docs/user-guide-v6/img/user252x.png)
Figure 3.1: Header files, source files, compilation and linking

　このように『どのクラスをリンクするか』や『どのファイルをインクルードするか』などの複雑な情報を実行ファイルごとに記述しコンパイルするために、OpenFOAMでは`wmake`というコマンドが用意されています。

# wmakeを実行してみる

　取り合えず`wmake`を実行してみます。今回は例としてpimpleFoamをコピーして`cpPimpleFoam`というソルバーを作成する場合を考えます。

```bash:bash
$ cp -r $FOAM_SOLVERS/incompressible/pimpleFoam ./cpPimpleFoam
$ cd ./cpPimpleFoam
$ sed -i -e "s/APPBIN)\/pimpleFoam/USER\_APPBIN)\/cpPimpleFoam/g" Make/files
$ # 下2行はWSLの場合に必要 (windowsはファイル名の大文字小文字を区別できないのでCorrectPhi.HをcorrectPhi.Hと間違えてしまう)
$ cp $FOAM_SRC/finiteVolume/cfdTools/general/CorrectPhi/CorrectPhi.H cpCorrectPhi.H
$ sed -i -e "s/CorrectPhi.H/cpCorrectPhi.H/" pimpleFoam.C
$ # pimpleFoamと同じ機能のものをコンパイルする
$ wmake > log.wmake
```

出力されたファイルの内容は以下の通りです。

```sh:log.wmake
Making dependency list for source file pimpleFoam.C
g++ -std=c++11 -m64 -pthread \
    -DOPENFOAM=2006 -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 \
    -I/installdir/OpenFOAM-v2006/src/finiteVolume/lnInclude -I/installdir/OpenFOAM-v2006/src/meshTools/lnInclude -I/installdir/OpenFOAM-v2006/src/sampling/lnInclude -I/installdir/OpenFOAM-v2006/src/TurbulenceModels/turbulenceModels/lnInclude -I/installdir/OpenFOAM-v2006/src/TurbulenceModels/incompressible/lnInclude -I/installdir/OpenFOAM-v2006/src/transportModels -I/installdir/OpenFOAM-v2006/src/transportModels/incompressible/singlePhaseTransportModel -I/installdir/OpenFOAM-v2006/src/dynamicMesh/lnInclude \
    -I/installdir/OpenFOAM-v2006/src/dynamicFvMesh/lnInclude -iquote. -IlnInclude -I/installdir/OpenFOAM-v2006/src/OpenFOAM/lnInclude -I/installdir/OpenFOAM-v2006/src/OSspecific/POSIX/lnInclude    \
    -fPIC  \
    -c pimpleFoam.C  \
    -o Make/linux64GccDPInt32Opt/pimpleFoam.o

g++ -std=c++11 -m64 -pthread \
    -DOPENFOAM=2006 -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 \
    -I/installdir/OpenFOAM-v2006/src/finiteVolume/lnInclude -I/installdir/OpenFOAM-v2006/src/meshTools/lnInclude -I/installdir/OpenFOAM-v2006/src/sampling/lnInclude -I/installdir/OpenFOAM-v2006/src/TurbulenceModels/turbulenceModels/lnInclude -I/installdir/OpenFOAM-v2006/src/TurbulenceModels/incompressible/lnInclude -I/installdir/OpenFOAM-v2006/src/transportModels -I/installdir/OpenFOAM-v2006/src/transportModels/incompressible/singlePhaseTransportModel -I/installdir/OpenFOAM-v2006/src/dynamicMesh/lnInclude \
    -I/installdir/OpenFOAM-v2006/src/dynamicFvMesh/lnInclude -iquote. -IlnInclude -I/installdir/OpenFOAM-v2006/src/OpenFOAM/lnInclude -I/installdir/OpenFOAM-v2006/src/OSspecific/POSIX/lnInclude    \
    -fPIC  \
    -Xlinker --add-needed  \
    -Xlinker --no-as-needed   \
    Make/linux64GccDPInt32Opt/pimpleFoam.o \
    -L/installdir/OpenFOAM-v2006/platforms/linux64GccDPInt32Opt/lib   \
    -lfiniteVolume -lfvOptions -lmeshTools -lsampling -lturbulenceModels -lincompressibleTurbulenceModels -lincompressibleTransportModels \
    -ldynamicMesh -ldynamicFvMesh -ltopoChangerFvMesh -latmosphericModels -lOpenFOAM -ldl -lm \
    -o /installdir/inabower-v2006/platforms/linux64GccDPInt32Opt/bin/cpPimpleFoam
```

このうち一行目以外は実際に実行されたコマンドです。
つまり**`wmake`により`g++`がオプションを変えて2回実行された**ことがわかります。

## g++とは
　まず`g++`(GNU C++ Compiler)について少し説明します。
これはGCC ([GNU Compiler Colelction](https://ja.wikipedia.org/wiki/GNUコンパイラコレクション))の一つであり、先述の2つの`g++`はそれぞれ**『コンパイラでオブジェクトファイルを生成』**と**『リンカで実行ファイルを生成』**という動作をしています。これらの説明については以下のサイトがわかりやすかったです。

> **コンパイラは何をしているのか**
http://nenya.cis.ibaraki.ac.jp/TIPS/compiler.html
みなさんがコンパイラだと思っている **gccは、 実は、コンパイラドライバ(compiler driver)と呼ばれるプログラム**であり、 Cなどのプログラミング言語で書かれたソースプログラムから実行形式を 作り出すための処理を行う
gccは、**「必要に応じてコンパイラや アセンブラ、リンケージエディタなどのプログラムを呼び出す」**という 処理を行っている。gccコマンド自体が直接コンパイルを行っているわけではない。

実際にそれぞれの動作を確認してみましょう。

### 1. コンパイラ

　C++で記述されたファイルから機械語に翻訳されたオブジェクトファイルを作成します。
先ほどの`g++`では`pimpleFoam.C`というファイルから`Make/linux64GccDPInt32Opt/pimpleFoam.o`というオブジェクトファイルを生成しています。

```bash:1つ目のg++(log.wmake)
g++ -std=c++11 -m64 -pthread \
-DOPENFOAM=2006 -DWM_DP -DWM_LABEL_SIZE=32 \ # OpenFOAM側で使用するDEFINE
-Wall -Wextra -Wold-style-cast -Wnon-virtual-dtor \ # コンパイル時に表示するエラーの選択
-Wno-unused-parameter -Wno-invalid-offsetof -Wno-attributes -Wno-unknown-pragmas \ # 表示しないエラーの選択
-O3 \ # 最適化オプション
-DNoRepository -ftemplate-depth-100 \ # OpenFOAM側で使用するDEFINEと再帰の上限
-I/installdir/OpenFOAM-v2006/src/finiteVolume/lnInclude -I/installdir/OpenFOAM-v2006/src/meshTools/lnInclude -I/installdir/OpenFOAM-v2006/src/sampling/lnInclude -I/installdir/OpenFOAM-v2006/src/TurbulenceModels/turbulenceModels/lnInclude -I/installdir/OpenFOAM-v2006/src/TurbulenceModels/incompressible/lnInclude -I/installdir/OpenFOAM-v2006/src/transportModels -I/installdir/OpenFOAM-v2006/src/transportModels/incompressible/singlePhaseTransportModel -I/installdir/OpenFOAM-v2006/src/dynamicMesh/lnInclude \
-I/installdir/OpenFOAM-v2006/src/dynamicFvMesh/lnInclude -iquote. -IlnInclude -I/installdir/OpenFOAM-v2006/src/OpenFOAM/lnInclude -I/installdir/OpenFOAM-v2006/src/OSspecific/POSIX/lnInclude    \
-fPIC  \
-c pimpleFoam.C  \
-o Make/linux64GccDPInt32Opt/pimpleFoam.o
```

実際に以下のように`Make`ディレクトリの下に`pimpleFoam.o`が生成されていることを確認できます。

```bash:bash
$ tree
.
├── Make
│   ├── files
│   ├── linux64GccDPInt32Opt
│   │   ├── options
│   │   ├── pimpleFoam.C.dep
│   │   ├── pimpleFoam.o
│   │   ├── sourceFiles
│   │   └── variables
│   └── options
├── UEqn.H
├── correctPhi.H
├── cpCorrectPhi.H
├── createFields.H
├── log.wmake
├── pEqn.H
└── pimpleFoam.C
```

このオブジェクトファイルは実行することはできません。

```bash:bash
$ Make/linux64GccDPInt32Opt/pimpleFoam.o
bash: Make/linux64GccDPInt32Opt/pimpleFoam.o: cannot execute binary file: Exec format error
```

`pimpleFoam`としての動作をしてほしい場合には次の『リンカ』による実行ファイルの作成が必要になります。

### 2. リンカ

　**オブジェクトファイル**をリンクすることで**実行ファイル**を作成します。
先ほどの`Make/linux64GccDPInt32Opt/pimpleFoam.o`(-5行目)を含む多くの**オブジェクトファイル**から`$FOAM_USER_APPBIN/bin/cpPimpleFoam`(最終行)という**実行ファイル**を生成しています。計算時に`cpPimpleFoam`と実行すると、この`$FOAM_USER_APPBIN/bin/cpPimpleFoam`が実行されます。

```bash
g++ -std=c++11 -m64 -pthread \
-DOPENFOAM=2006 -DWM_DP -DWM_LABEL_SIZE=32 \ # OpenFOAM側で使用するDEFINE
-Wall -Wextra -Wold-style-cast -Wnon-virtual-dtor \ # コンパイル時に表示するエラーの選択
-Wno-unused-parameter -Wno-invalid-offsetof -Wno-attributes -Wno-unknown-pragmas \ # 表示しないエラーの選択
-O3 -DNoRepository -ftemplate-depth-100 \
-I/installdir/OpenFOAM-v2006/src/finiteVolume/lnInclude -I/installdir/OpenFOAM-v2006/src/meshTools/lnInclude -I/installdir/OpenFOAM-v2006/src/sampling/lnInclude -I/installdir/OpenFOAM-v2006/src/TurbulenceModels/turbulenceModels/lnInclude -I/installdir/OpenFOAM-v2006/src/TurbulenceModels/incompressible/lnInclude -I/installdir/OpenFOAM-v2006/src/transportModels -I/installdir/OpenFOAM-v2006/src/transportModels/incompressible/singlePhaseTransportModel -I/installdir/OpenFOAM-v2006/src/dynamicMesh/lnInclude \
-I/installdir/OpenFOAM-v2006/src/dynamicFvMesh/lnInclude -iquote. -IlnInclude -I/installdir/OpenFOAM-v2006/src/OpenFOAM/lnInclude -I/installdir/OpenFOAM-v2006/src/OSspecific/POSIX/lnInclude    \
-fPIC  \ # ここまで1つ目のg++と同じ
-Xlinker --add-needed  \ # リンカオプション
-Xlinker --no-as-needed   \ # リンカオプション
Make/linux64GccDPInt32Opt/pimpleFoam.o \
-L/installdir/OpenFOAM-v2006/platforms/linux64GccDPInt32Opt/lib   \
-lfiniteVolume -lfvOptions -lmeshTools -lsampling -lturbulenceModels -lincompressibleTurbulenceModels -lincompressibleTransportModels \
-ldynamicMesh -ldynamicFvMesh -ltopoChangerFvMesh -latmosphericModels -lOpenFOAM -ldl -lm \
-o $FOAM_USER_APPBIN/bin/cpPimpleFoam
```

　なおここでリンクしている`pimpleFoam.o`**以外の**オブジェクトファイルは**共有ライブラリ(shared objerct)**と呼ばれ、`lib*.so`というファイル名で作成されています。これらは主に`$FOAM_SRC`ディレクトリの`*.C`ファイルからコンパイルされたものになります。

　以下のように実行ファイルが生成されていることがわかります。

```sh:bash
$ ls $FOAM_USER_APPBIN
cpPimpleFoam
```

　また、以下のように実行することができます。

```bash:bash
$ cpPimpleFoam
/*---------------------------------------------------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  v2006                                 |
|   \\  /    A nd           | Website:  www.openfoam.com                      |
|    \\/     M anipulation  |                                                 |
(略 : 以下OpenFOAMのエラーメッセージ)
```

# Makeディレクトリについて

　`wmake`の際の設定を`Make`ディレクトリの中身で記述をします。

```bash:bash
$ tree
.
├── Make
│   ├── files
│   └── options
├── UEqn.H
├── correctPhi.H
├── createFields.H
├── pEqn.H
└── pimpleFoam.C
```

この中には以下のような二つのファイルが入っています。

## Make/files

```Makefile:Make/files
pimpleFoam.C # 最初のg++でどのファイルをコンパイルするか

EXE = $(FOAM_USER_APPBIN)/cpPimpleFoam # 最後のg++で生成する実行ファイルのパス
```

　最初の行では**『どのファイルをコンパイルするか』**を指定しています。
ここではオブジェクトファイルにコンパイルするファイルは`pimpleFoam.C`のみですので、今回は`pimpleFoam.o`のみが生成されたということになります。

　ここには**複数の**境界条件や乱流モデルなどに関する`*.C`を列挙することもできます。例えば`incomprssible/adjointShapeOptimizationFoam`の`Make/files`は以下のようになっています。

```MakeFile:$FOAM_SOLVERS/incomprssible/adjointShapeOptimizationFoam/Make/files
adjointOutletPressure/adjointOutletPressureFvPatchScalarField.C # 1回目のg++でコンパイル
adjointOutletVelocity/adjointOutletVelocityFvPatchVectorField.C # 2回目のg++でコンパイル
adjointShapeOptimizationFoam.C # 3回目のg++でコンパイル

EXE = $(FOAM_APPBIN)/adjointShapeOptimizationFoam # 4回目のg++でリンク
```

　この場合は`wmake`の際に`g++`は4回実行されることになります。これらの境界条件はこのソルバーでのみ使用するものであるため、ここでオブジェクトファイルにしているようです。
　ただし通常OpenFOAMでは一つの境界条件を複数のソルバーで使用できるように境界条件などについては**共有ライブラリ**という形で別々にコンパイルされ、適宜リンクされることが多いです。どれをリンクするかについては次の`Make/options`に記載されます。

## Make/options

```Makefile:Make/options
EXE_INC = \
    -I$(LIB_SRC)/finiteVolume/lnInclude \
    -I$(LIB_SRC)/meshTools/lnInclude \
    -I$(LIB_SRC)/sampling/lnInclude \
    -I$(LIB_SRC)/TurbulenceModels/turbulenceModels/lnInclude \
    -I$(LIB_SRC)/TurbulenceModels/incompressible/lnInclude \
    -I$(LIB_SRC)/transportModels \
    -I$(LIB_SRC)/transportModels/incompressible/singlePhaseTransportModel \
    -I$(LIB_SRC)/dynamicMesh/lnInclude \
    -I$(LIB_SRC)/dynamicFvMesh/lnInclude

EXE_LIBS = \
    -lfiniteVolume \
    -lfvOptions \
    -lmeshTools \
    -lsampling \
    -lturbulenceModels \
    -lincompressibleTurbulenceModels \
    -lincompressibleTransportModels \
    -ldynamicMesh \
    -ldynamicFvMesh \
    -ltopoChangerFvMesh \
    -latmosphericModels
```

### EXE_INC：#includeするファイル

　最初の`EXE_INC = `では**『インクルードする`*.H`ファイルの場所』**を列挙していきます。
例えば今回コンパイルする`pimpleFoam.C`の最初の行は以下のようになっています。

```c++:pimpleFoam.C
#include "fvCFD.H"
#include "dynamicFvMesh.H"
#include "singlePhaseTransportModel.H"
#include "turbulentTransportModel.H"
#include "pimpleControl.H"
#include "cpCorrectPhi.H"
#include "fvOptions.H"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
(以下略)
```

　この最初の`fvCFD.H`は以下のように`/installdir/OpenFOAM-v2006/src/finiteVolume/lnInclude/`つまり`$(LIB_SRC)/finiteVolume/lnInclude`にあることが分かります。

```bash:bash
$ find $FOAM_SRC -name fvCFD.H
/installdir/OpenFOAM-v2006/src/finiteVolume/lnInclude/fvCFD.H # ↓と同じもの（正確にはシンボリックリンク）
/installdir/OpenFOAM-v2006/src/finiteVolume/cfdTools/general/include/fvCFD.H # オリジナル
```

　このように、`wmake`でコンパイルするファイルの中の全ての`#include "*.H"`がどれを指すかが分かるようにする必要があります。なお複数ディレクトリで重複ファイル名のものがある場合は`EXE_INC = `の順番がそのまま検索優先順位になります。

### EXE_LIBS：リンクする共有ライブラリの名前

　次の`EXE_LIBS = `では**『リンクする共有ライブラリの名前』**を指定しています。検索ディレクトリはデフォルトで`$FOAM_LIBBIN`になりますので、例えば`-lfiniteVolume`は`/installdir/OpenFOAM-v2006/platforms/linux64GccDPInt32Opt/lib/libfiniteVolume.so`を指すことになります。
もし他のディレクトリのライブラリを指定したい場合は以下のよう追加すればOKです。

```Makefile:Make/options
(略)
EXE_LIBS = \
    -lfiniteVolume \
    -lfvOptions \
    -lmeshTools \
    -lsampling \
    -lturbulenceModels \
    -lincompressibleTurbulenceModels \
    -lincompressibleTransportModels \
    -ldynamicMesh \
    -ldynamicFvMesh \
    -ltopoChangerFvMesh \
    -latmosphericModels \
    -L/home/myLib \
    -lmyModel1 \
    -lmyModel2
```

# もう一度2つのg++を見てみる

　というわけで、`Make`ディレクトリの中では以下のコメントアウトしていない内容について指定したことが分かります。

```sh:log.wmake
# g++ -std=c++11 -m64 -pthread \
# -DOPENFOAM=2006 -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 \
#### includeするファイルのある場所 (Make/options前半) ####
-I/installdir/OpenFOAM-v2006/src/finiteVolume/lnInclude \
-I/installdir/OpenFOAM-v2006/src/meshTools/lnInclude \
-I/installdir/OpenFOAM-v2006/src/sampling/lnInclude \
-I/installdir/OpenFOAM-v2006/src/TurbulenceModels/turbulenceModels/lnInclude \
-I/installdir/OpenFOAM-v2006/src/TurbulenceModels/incompressible/lnInclude \
-I/installdir/OpenFOAM-v2006/src/transportModels \
-I/installdir/OpenFOAM-v2006/src/transportModels/incompressible/singlePhaseTransportModel \
-I/installdir/OpenFOAM-v2006/src/dynamicMesh/lnInclude \
-I/installdir/OpenFOAM-v2006/src/dynamicFvMesh/lnInclude
# -iquote. \
# -IlnInclude \
# -I/installdir/OpenFOAM-v2006/src/OpenFOAM/lnInclude \
# -I/installdir/OpenFOAM-v2006/src/OSspecific/POSIX/lnInclude    \
# -fPIC  \
#### コンパイルする.Cファイル (Make/files前半) ####
-c pimpleFoam.C  \
#### 生成するオブジェクトファイル ####
-o Make/linux64GccDPInt32Opt/pimpleFoam.o

# g++ -std=c++11 -m64 -pthread \
# -DOPENFOAM=2006 -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 \
#### includeするファイルのある場所 (Make/options前半) ####
-I/installdir/OpenFOAM-v2006/src/finiteVolume/lnInclude \
-I/installdir/OpenFOAM-v2006/src/meshTools/lnInclude \
-I/installdir/OpenFOAM-v2006/src/sampling/lnInclude \
-I/installdir/OpenFOAM-v2006/src/TurbulenceModels/turbulenceModels/lnInclude \
-I/installdir/OpenFOAM-v2006/src/TurbulenceModels/incompressible/lnInclude \
-I/installdir/OpenFOAM-v2006/src/transportModels \
-I/installdir/OpenFOAM-v2006/src/transportModels/incompressible/singlePhaseTransportModel \
-I/installdir/OpenFOAM-v2006/src/dynamicMesh/lnInclude \
-I/installdir/OpenFOAM-v2006/src/dynamicFvMesh/lnInclude
# -iquote. -IlnInclude \
# -I/installdir/OpenFOAM-v2006/src/OpenFOAM/lnInclude \
# -I/installdir/OpenFOAM-v2006/src/OSspecific/POSIX/lnInclude \
# -fPIC  \
# -Xlinker --add-needed  \
# -Xlinker --no-as-needed   \
#### 前のg++で生成したオブジェクトファイル (Make/files前半) ####
Make/linux64GccDPInt32Opt/pimpleFoam.o \
# -L/installdir/OpenFOAM-v2006/platforms/linux64GccDPInt32Opt/lib \
#### 共有ライブラリのリスト (Make/options後半 EXE_LIBS) ####
-lfiniteVolume \ 
-lfvOptions \
-lmeshTools \
-lsampling \
-lturbulenceModels \
-lincompressibleTurbulenceModels \
-lincompressibleTransportModels \
-ldynamicMesh \
-ldynamicFvMesh \
-ltopoChangerFvMesh \
-latmosphericModels \
# -lOpenFOAM -ldl -lm \
#### 実行ファイルの名前 (Make/files後半 EXE) ####
-o /installdir/inabower-v2006/platforms/linux64GccDPInt32Opt/bin/cpPimpleFoam
```

　それでは最後にこれらのg++オプションがどういう仕組みで生成されているかについて見ていきます。

# makefileとmakeコマンド

　`wmake`と実行すると`wmake`というスクリプトが実行されます。
これは以下のように`which`コマンドで確認することができます。

```bash
$ which wmake
/installdir/OpenFOAM-v2006/wmake/wmake
```

　その中身を見てみます。

```bash:/installdir/OpenFOAM-v2006/wmake/wmake
Script="${0##*/}"                   # Need 'Script' for wmakeFunctions messages
scriptsDir="${0%/*}"/scripts        # wmake/scripts directory
. "$scriptsDir"/wmakeFunctions      # Source wmake functions

(略)

# Default make is the "make" in the path
make="make"

(略)

exec $make -f $WM_DIR/makefiles/general \
     ${optDebug:+c++DBUG="$optDebug"} \
     MAKE_DIR=$MakeDir OBJECTS_DIR=$objectsDir $targetType

exit 0 # clean exit
```

　最後の`exec`により実行される内容は私の環境では以下のようになります。

```bash
make -f /installdir/OpenFOAM-v2006/wmake/makefiles/general \
  MAKE_DIR=Make OBJECTS_DIR=Make/linux64GccDPInt32Opt
```

　というわけで、`wmake`では**『`wmake/makefiles/general`というmakefileについて`make`を実行している』**ことが分かります。このmakefileの中にこの記事で説明してきた**2つのg++**に関する内容が記述されることが予想されます。

## makefiles/general

　このファイルは多くのファイルを経由して変数をセットした上でmakefileとして機能する雛型のようなファイルです。
例えば先述の`Make/options`で指定した`EXE_INC`や`EXE_LIBS`は以下のように組み込まれます。半永久的に追加したいライブラリなどがある場合はここに追加してもよいかもしれません。

```Makefile:wmake/makefiles/general
(略)
#------------------------------------------------------------------------------
# Include paths, use -iquote to ensure that (.) is searched first
#------------------------------------------------------------------------------

LIB_HEADER_DIRS = \
    $(EXE_INC) \
    -iquote. \
    -IlnInclude \
    $(PROJECT_INC) \
    $(GINC) \
    $(SYS_INC)
(略)
#------------------------------------------------------------------------------
# Define link statements for executables
#------------------------------------------------------------------------------
(略)
$(EXE)$(EXT_EXE): $(OBJECTS)
	@$(WM_SCRIPTS)/makeTargetDir $(EXE)
	$(call QUIET_MESSAGE,ld,$(EXE)$(EXT_EXE))
	$E $(LINKEXE) $(OBJECTS) -L$(LIB_PLATFORMS) \
	    $(EXE_LIBS) $(PROJECT_LIBS) $(SYS_LIBS) \
	    $(LINK_LIBS) $(GLIBS) -o $(EXE)$(EXT_EXE)
(略)
```

　そのため、以下ではwmakeの際のオプションをどこで指定しているかについて軽く紹介します。
各自でコンパイル時の設定を変更したい場合の参考にしてください。

## コンパイラ

　ここまでg++でコンパイルする前提で紹介してきましたが他のコンパイラを指定することもできます。これは大本の`/installdir/OpenFOAM-v2006/etc/bashrc`で指定します。それぞれの好みに合わせて指定するとよいかと思います。

```bash:/installdir/OpenFOAM-v2006/etc/bashrc
# [WM_COMPILER] - Compiler:
# = Gcc | Clang | Icc | Cray | Amd | Arm | Pgi | Fujitsu |
#   Gcc<digits> | Clang<digits>
export WM_COMPILER=Gcc
```

　以降もここまでと同様にGccを指定したという前提で紹介していきます。

## コンパイラオプション

① 一般設定
　まず`/installdir/OpenFOAM-v2006/wmake/rules/General/Gcc/c++`が読み込まれます。
例えばC++17でコンパイルしたい場合などはここで`-std=c++11`を`-std=c++17`に変更したりします。
また、`c++WARN`はコンパイル時に出力するエラーの種類です。動作は問題ないけど警告するエラーなどについてデバッグ時の妨げになるようであればここでオプションを追加して非表示にしたりします。

```Makefile:/installdir/OpenFOAM-v2006/wmake/rules/General/Gcc/c++
SUFFIXES += .C .cc .cpp .cxx

CC          = g++ -std=c++11

c++ARCH     =
c++DBUG     =
c++OPT      = -O2
ptFLAGS     = -DNoRepository -ftemplate-depth-100

# - Standard warnings
# - Less restrictive warnings (may be needed for flex++, CGAL, etc.)

c++WARN     = \
    -Wall -Wextra -Wold-style-cast \
    -Wnon-virtual-dtor -Wno-unused-parameter -Wno-invalid-offsetof \
    -Wno-attributes -Wno-unknown-pragmas \
    $(FOAM_EXTRA_CXXFLAGS)

c++LESSWARN = \
    -Wno-old-style-cast -Wno-unused-local-typedefs -Wno-array-bounds \
    -Wno-deprecated-declarations \
    -fpermissive
```

② アーキテクチャ個別の設定
　①の設定はここで読み込まれることになります。①と②で、最初に示したg++のオプションの前半が網羅されているかと思います。

```Makefile:/installdir/OpenFOAM-v2006/wmake/rules/linux64Gcc/c++
include $(GENERAL_RULES)/Gcc/c++

c++ARCH     = -m64 -pthread

include $(DEFAULT_RULES)/c++$(WM_COMPILE_OPTION)

c++FLAGS    = $(c++ARCH) $(GFLAGS) $(c++WARN) $(c++OPT) $(c++DBUG) $(ptFLAGS) $(LIB_HEADER_DIRS) -fPIC

Ctoo        = $(WM_SCHEDULER) $(CC) $(c++FLAGS) -c $< -o $@
cxxtoo      = $(Ctoo)
cctoo       = $(Ctoo)
cpptoo      = $(Ctoo)

include $(GENERAL_RULES)/Gcc/link-c++
```

## 最適化オプション

　最適化オプション`-O3`はここで指定されています。

```Makefile:/installdir/OpenFOAM-v2006/wmake/rules/linux64Gcc/c++Opt
c++DBUG     =
c++OPT      = -O3

ROUNDING_MATH = -frounding-math
```

　環境変数`$WM_COMPILE_OPTION=Opt`がデフォルトであるため通常は`-O3`となります。もしこれが原因と思われるエラーに遭遇した場合にはここを変更してもよいかもしれません。

> **GCCの最適化 / gentoo linux wiki**
[wiki.gentoo.org/wiki/GCC_optimization](https://wiki.gentoo.org/wiki/GCC_optimization/ja#-O)
`-O3`: これは取りうる最も高い最適化レベルです。コンパイル時間とメモリ使用量を犠牲にして最適化を実施します。ただし`-O3`は性能を改善する保証がありません。実際多くのケースで、バイナリサイズが大きくなり、メモリ使用量が増えることで逆にシステムが遅くなります。`-O3`はいくつかのパッケージを壊すことがわかっています。これらの理由により`-O3`は推奨されません。一方、このレベルはコード内のループをベクトル化する`-ftree-vectorize`を有効化し、AVX YMMレジスタも利用されます。

# まとめ

`wmake`では以下の動作を行っているみたいです。

- **`wmake`**を実行すると・・・
- **`make -f wmake/makefiles/general`**が実行される
    -  `wmake/makefiles/general`を`Makefile`として読み込む
        -  コンパイラオプションなどを指定
        -  いくつかの情報を`Make/files`と`Make/options`で補完
    -  `Make/files`を読み込む
        -  コンパイルするファイルを指定
        -  実行ファイル名を指定
    -  `Make/options`を読み込む
        -  includeファイルのあるディレクトリを指定
        -  共有ライブラリ(`lib*.so`)を指定
- 複数回の`g++`が実行される(`Makefile`の内容による)
  - **`g++`でコンパイル** (× オブジェクト数)
      -  オブジェクト(`*.o`)を生成
  - **`g++`でリンク**
      -  生成したオブジェクト(`*.o`)と指定した共有ライブラリ(`lib*.so`)をリンク
      -  実行ファイルを生成

# 最後に

　間違っている点等がございましたら指摘いただけると助かります。