RDKitでC++/CLIアプリを作成する[Windows編]

# RDKitとは？

化合物情報を扱えるオープンソースソフトウェアで、ケモインフォマティクスなど機械学習の分野で用いられています。
C++とPythonで書かれています。

https://www.rdkit.org/

# モチベーション

色々な環境(ゲームなど)でRDKitを利用したいのでC++部分をネイティブプラグインとしてビルドしたいと考えました。
クロスコンパイルが必要で予想以上に煩雑だったので言語化してフローをまとめたいと考え、各環境に分けて最小アプリ作成の流れを書き残したいと思います。
(WindowsでのコンパイルとAndroidとiOSのクロスコンパイルの予定。一応出来たという記憶はありますがすでに大部分を忘れているので思い出しついでに書こうと思います)

# 開発環境の構築

今回はWindows10でビルドを行っていきます。
以下の開発環境をインストールします。

## 必要なソフトウェア

- Visual Studio 2019
  - ビルドのため
  - Visual Stuio Installerで「C++によるデスクトップ開発」、言語パック「英語」を追加してください。
  - https://visualstudio.microsoft.com/ja/
- CMake
  - Visual Studioプロジェクトの作成のため
  - https://cmake.org/
- vcpkg
  - c++ライブラリをcmakeで統一的に扱うため
  - https://github.com/microsoft/vcpkg
- git
  - bashで実行するためgit同梱のbashを用いる
  - https://git-scm.com/

## C++ライブラリのインストール

C++のライブラリはvcpkgを利用してインストールします。
C:/src/vcpkgにvcpgをインストールした場合、以下のコマンドでインストールできます。

```bash
C:/src/vcpkg/vcpkg.exe install --triplet x64-windows-static eigen3 boost freetype cairo
```

# rdkitライブラリ(static)のビルド

## rdkitのクローン

簡単のためCドライブ直下にクローンします。
別の場所にクローンしたい方は以降の説明やコマンドを適宜読み替えてください。

```bash
cd C:
git clone https://github.com/rdkit/rdkit
# commit bed7eb1eb529be24c6317c62875b9926a948cd5f
```

## rdkitの修正

後述のrdkitライブラリを使ったCLIアプリのビルドの際、Dict.hのstatic_assertの部分でエラーが出るのでこの部分を消します。
assertなら完璧にビルドすれば無くても問題ないだろうという考えです。
(より適切な対応をご存じでしたらコメントください)

```bash
sed -i -e 's|^.*static_assert.*$||g' -e 's|^.*T cannot be string_view.*$||g' Code/RDGeneral/Dict.h
```

## rdkitライブラリのVisual Studioプロジェクト作成

cmakeを利用してwin64フォルダ内にVisual Studioプロジェクト作成を作成します。
不必要そうなオプションを除外してcmakeを実行します。
とりあえず動いたオプションを下に示しています。
Boost系のオプションは後述のビルドでエラーが出がちな気がします(この段階のビルドではエラーは出ません)。
(より適切な対応をご存じでしたらコメントください)

```bash
mkdir win64 ||:
cmake -S. -Bwin64 \
	-DCMAKE_TOOLCHAIN_FILE=c:/src/vcpkg/scripts/buildsystems/vcpkg.cmake \
	-DVCPKG_TARGET_TRIPLET=x64-windows-static \
	-DRDK_BUILD_PYTHON_WRAPPERS=OFF \
	-DRDK_BUILD_MAEPARSER_SUPPORT=OFF \
	-DRDK_TEST_MMFF_COMPLIANCE=OFF \
	-DRDK_BUILD_CPP_TESTS=OFF \
	-DRDK_TEST_MULTITHREADED=OFF \
	-DRDK_BUILD_CAIRO_SUPPORT=OFF 
```

## rdkitライブラリのコンパイル

以下から開発者用のPowerShellを開いてビルドコマンドを実行します。
[Windowsメニュー]>[Visual Studio 2019]>[Developer PowerShell 2019]
ゲーミングノートパソコンで10分程かかります。

```powershell
cd C:\rdkit\win64
msbuild ALL_BUILD.vcxproj /p:Configuration=Release
```

## rdkitのcmake設定ファイルの修正

rdkitをcmakeに読み込ませるためのファイル群が生成されます。
そのままだとライブラリの読み込みが適切に行えないので修正します。

### rdkit-targets群の移動・修正

cmake中間生成フォルダの奥の方に入っているのでwin64フォルダ直下に移動します。
ライブラリの読み込み場所も異なるので修正します。
(より適切な対応を略)

```bash
cp win64/CMakeFiles/Export/C_/rdkit/lib/cmake/rdkit/* win64
sed -i -e 's|C:/rdkit/lib/|C:/rdkit/win64/lib/Release/|g' win64/rdkit-targets-*.cmake
```
### rdkit-config.cmakeの修正

コンパイルしたrdkitライブラリを外部から使う際はrdkit-config.cmakeを読み込ませることになります。
ただファイル読み込みの位置が適切に行えないので修正します。
正直ここの設定がどこまで必要なのか判断がつかないです。
(より適切な略)

```bash
# インクルードフォルダの修正？
sed -i -e 's|${CMAKE_CURRENT_LIST_DIR}/../../..|C:/rdkit|' -e 's|${CMAKE_CURRENT_LIST_DIR}|C:/rdkit/win64|' win64/rdkit-config.cmake
# ライブラリフォルダの修正？
sed -i -e 's|C:/rdkit/lib/|C:/rdkit/win64/lib/Release/|g' win64/rdkit-targets-*.cmake
```

# C++/CLIアプリのビルド

前節でコンパイルしたrdkitライブラリを使ってコマンドラインアプリを作成します。
例として、smilesを標準入力するとsvgが標準出力されるアプリを作成します。
フォルダ構成は以下の通りです。
例のごとくこのフォルダをCドライブ直下に配置します。

## フォルダ構成

rdkit_cli
├─ CMakeLists.txt
└─ main.cpp

### CMakeLists.txt

cmakeでVisual Studioプロジェクトを作成するための設定ファイルです。
この設定ファイルを用いてRDKitCliプロジェクトを作成し実行ファイルをビルドします。
この際、RDKitCliプロジェクトにincludeフォルダやlibフォルダ、ライブラリを設定します。
フォントが入っていないと文字が描画されないのでFreetypeライブラリを利用しています。
rdkitライブラリの作成の際、オプションから除外したはずなのになぜかCairoのincludeが必要なので、vcpkgのフォルダを直接参照させます。
(より略)

```cmake:CMakeLists.txt
cmake_minimum_required(VERSION 3.22)
project(RDKitCli)
set(RDKit_DIR ${RDKit_ROOT_DIR})

add_executable(RDKitCli main.cpp)
find_package(Freetype REQUIRED)
find_package(RDKit REQUIRED)
target_include_directories(RDKitCli
    PRIVATE
    ${RDKit_INCLUDE_DIRS}
    C:/src/vcpkg/installed/x64-windows-static/include/cairo
)
target_link_directories(RDKitCli
    PRIVATE
    C:/rdkit/win64/lib/Release
)
target_link_libraries(RDKitCli
    ChemReactions
    DataStructs
    Depictor
    FileParsers
    GenericGroups
    GraphMol
    MolDraw2D
    MolTransforms
    RDGeneral
    RDGeometryLib
    RingDecomposerLib
    SmilesParse
    SubstructMatch
    coordgen
    ${FREETYPE_LIBRARIES}
)

```

### main.cpp

メイン関数です。
標準入力をsmilesとしてMolインスタンスを作成、水素付加を行いSVGとして出力しています。
なぜか\</svg>が出力されないので自前で足しています。

```cpp:main.cpp
#include <iostream>
#include <GraphMol/SmilesParse/SmilesParse.h>
#include <GraphMol/MolOps.h>
#include <GraphMol/MolDraw2D/MolDraw2DSVG.h>
#include <GraphMol/Depictor/RDDepictor.h>
#include <GraphMol/FileParsers/MolFileStereochem.h>


int main(int argc, char **argv){
    std::string smiles;
    std::cin >> smiles;
    auto mol = RDKit::SmilesToMol(smiles);
    RDKit::MolOps::addHs(*mol);
    auto drawer = new RDKit::MolDraw2DSVG(300, 300, -1, -1, true);
    drawer->drawMolecule(*mol);
    std::string text = drawer->getDrawingText() + "</svg>\n";
    drawer->finishDrawing();
    std::cout << text;
    return 0;
}

```

## プロジェクトの生成

以下のコマンドでプロジェクトを生成します。

```bash
cd C:/rdkit_cli
mkdir win64 ||:
cmake -S. -Bwin64 \
	-DRDKit_ROOT_DIR=C:/rdkit/win64 \
	-DCMAKE_TOOLCHAIN_FILE=C:/src/vcpkg/scripts/buildsystems/vcpkg.cmake \
	-DVCPKG_TARGET_TRIPLET=x64-windows-static \
	-DVCPKG_APPLOCAL_DEPS=OFF
```


## プロジェクトのビルド

例のごとく開発者用のPowerShellを開いてビルドコマンドを実行します。
[Windowsメニュー]>[Visual Studio 2019]>[Developer PowerShell 2019]

```powershell
cd C:\rdkit_cli\win64
msbuild ALL_BUILD.vcxproj /p:Configuration=Release
```

## 完成

C:/rdkit_cli/win64/ReleaseにRDKitCli.exeが生成されているはずです。
出来た実行ファイルを使ってsvgファイルを生成します。

```
echo c1ccccc1 | ./RDKitCli.exe > benzen.svg
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158368/9da1b9b9-dc09-3a1f-d376-50153799914f.png)

# 次回

正直これだけだとminicondaでrdkitをインストールした方が早いです。
折角なので次はC#で使えるように書き直してみたいと思います。