Ubuntu20.04 LTS上で、TensorFlow 2.3.1をソースからビルドし、C++言語の共有ライブラリを作成する

## 事のきっかけ
前回の記事から1年が経ち、情報が古くなってきたので更新。
特にPV数とか増えないけどね:frowning2:

## 更新履歴

 - 2020/11/18: Ubuntu20.04 LTS & TensorFlow 2.3.1として再投稿
 - 同日: ライブラリのコマンドが不足していたので追記

## 使用PC
```shell
cat /etc/lsb-release

DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.1 LTS"

gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

```

## 事前準備
以降のコマンドでは、特段明記しない限り、上から一行ずつ実行。

- 前提素材のインストール

```shell
sudo apt install -y build-essential 
sudo apt install -y libffi-dev
sudo apt install -y libssl-dev 
sudo apt install -y zlib1g-dev
sudo apt install -y liblzma-dev
sudo apt install -y libbz2-dev libreadline-dev libsqlite3-dev 
sudo apt install -y git
sudo apt install -y openjdk-11-jdk
```
- pyenvのインストール

```shell
git clone https://github.com/pyenv/pyenv.git ~/.pyenv

# bash派の人は、「.zshrc」を「.bashrc」へ変更
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc
source ~/.zshrc
```
- python 3.9.0のインストール

```shell
pyenv install 3.9.0
pyenv global 3.9.0
python -V # 3.9.0が出ればOK
```
- virtualenvのインストール

```shell
pip install virtualenv
mkdir virtualEnv # (任意)
cd virtualEnv # (任意)
virtualenv py3.9.0 # 「py3.9.0」の所は任意の文字列
source py3.9.0/bin/activate # 「py3.9.0」は上の任意文字列
# 環境から抜ける時は、「deactivate」と打つだけ
```
## ビルド準備

- ビルド用のpythonにパッケージをインストール

```
# virtualenvの環境を読み込んでから実行すること

pip install -U pip numpy wheel

pip install -U keras_preprocessing --no-deps
```

- ビルドツールbazelのインストール

```shell
sudo apt install curl gnupg
curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor > bazel.gpg
sudo mv bazel.gpg /etc/apt/trusted.gpg.d/
echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
sudo apt update
sudo apt install -y bazel-3.1.0
sudo ln -s /usr/bin/bazel-3.1.0 /usr/bin/bazel
bazel --version  # 3.1.0
```

## ビルド

```shell
git clone --recursive https://github.com/tensorflow/tensorflow.git
git checkout v2.3.1
./configure 
# Yes or No形式は、全てNo
# [Default...]のディレクトリ選択は、最初のpythonディレクトリ(今回はvirtualEnv)のみしっかりと確認し、違っていれば正しいディレクトリを指定する。それ以外はエンターキーを押す。

# virtualenvの環境を読み込んでから実行すること
bazel build --verbose_failures --config=v2 //tensorflow:libtensorflow_cc.so
bazel build --verbose_failures --config=v2 //tensorflow:libtensorflow_framework.so
```

## ライブラリ準備
- C++プロジェクトのディレクトリ階層

```
[Project Folder]<-今回は「tf」
  |-include/
  |   |- tensorflow/
  |-lib/
  |-CMakeLists.txt
  |-main.cpp
```

- tensorflowからコピー

※下記のコマンドは、git cloneしてきた時に出来るtensorflowフォルダにcdコマンドで移動して行っています。
※必要なライブラリは、各自異なると思いますので、その都度追加していただければと思います。今回は、簡単な動作確認のため、この辺は雑です。

```shell
cp bazel-bin/tensorflow/libtensorflow_cc.so ~/CLionProjects/tf/lib
cp bazel-bin/tensorflow/libtensorflow_cc.so.2 ~/CLionProjects/tf/lib
cp bazel-bin/tensorflow/libtensorflow_cc.so.2.3.1 cp -r third_party ~/CLionProjects/tf/include
cp bazel-bin/tensorflow/libtensorflow_framework.so ~/CLionProjects/tf/lib
cp bazel-bin/tensorflow/libtensorflow_framework.so.2 ~/CLionProjects/tf/lib
cp bazel-bin/tensorflow/libtensorflow_framework.so.2.3.1 ~/CLionProjects/tf/lib
cp -r tensorflow/c ~/CLionProjects/tf/include/tensorflow
cp -r tensorflow/cc ~/CLionProjects/tf/include/tensorflow
cp -r tensorflow/core ~/CLionProjects/tf/include/tensorflow
cp -r third_party ~/CLionProjects/tf/include                                   
cp -r bazel-tensorflow/external/eigen_archive/Eigen ~/CLionProjects/tf/include
cp -r bazel-tensorflow/external/eigen_archive/unsupported ~/CLionProjects/tf/include
cp -r third_party ~/CLionProjects/tf/include                                   
```

## 動作確認

```cmake:CmakeLists.txt
cmake_minimum_required(VERSION 3.17)
project(tf)

set(CMAKE_CXX_STANDARD 20)

link_directories(lib) <- 追記
include_directories(include) <- 追記

add_executable(tf main.cpp)

target_link_libraries(tf tensorflow_cc tensorflow_framework) <- 追記
```

```c++:main.cpp
#include <iostream>
#include "tensorflow/c/c_api.h"

int main() {
    printf("TensorFlow Ver. %s\n", TF_Version());
    return 0;
}
```

```terminal:output
TensorFlow Ver. 2.3.1
```
## 感想
Ubuntuで実行できたということは、Unix系なら問題ないので、CentOSやmacOSでも出来るはず。(知らんけど)


# 参考資料
- CMakeLists.txt

「cmake チートシート」
https://www.qoosky.io/techs/814fda555d)

- tensorflow

「tensorflowをソースからコンパイルしてインストールする」
https://memo.saitodev.com/home/tensorflow/build/

「tensorflow source build」
https://www.tensorflow.org/install/source

- bazel

「bazel」
https://docs.bazel.build/versions/master/install-ubuntu.html

- pyenv

「ubuntu 20.04 に pyenv をインストールする話【2020/07/18更新】」
https://qiita.com/neruoneru/items/1107bcdca7fa43de673d