Docker+LLVM+Clangの構成で色々試す (パッケージマネージャはConanを使って)

## 概要
LLVM + Clangやパッケージマネージャー辺りを試してみたいと思います。

## 参考にしたリポジトリ
個人的にキャッチアップする際にGithubの[トレンド](https://github.com/trending/c++?since=daily)に入ってるリポジトリを色々眺めて
キャッチしていくスタイルなので今回も同様の方法で試してみたいと思います。

<a href="https://github.com/minetest/minetest"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299271/11ade9c8-800e-869e-bd31-cb5d1799f39f.png" width="460px"></a>

今回参考にさせて頂いたのは、有志が作ったマインクラフト?みたいなゲームのリポジトリでした。

- Docker使ってコンパイルしている?
- cmakeは今も健在な様子
- `.clang-format` でフォーマットを行っている
- `.clang-tidy` ファイルがあったけど、これは一体...?
    - `> コーディングをチェックしたりするツールです. ` 調べてlinterみたいなものという事がわかりました
    - [冬休み到来! clang-tidy で安心安全な C/C++ コーディングを極めよう! - Qiita](https://qiita.com/syoyo/items/0e75410c44ed73d4bdd7)

## 参考にしたリポジトリ同様Dockerを使ってコンパイルする
LLVM + clang のDockerイメージを有志が作成していたのでそちらを使用してみたいと思います。
https://hub.docker.com/r/silkeh/clang/

```Dockerfile
FROM silkeh/clang:latest

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

RUN apt-get update && \
    apt-get install -y \
      vim \
      cmake \
      --no-install-recommends && \
    rm -rf /var/lib/apt/lists/*

ADD . /usr/src/app

CMD clang++
```

```yml:docker-compose.yml
version: "3.3"

services:
  llvm:
    build: .
    command: clang++
    volumes:
      - .:/usr/src/app
    environment:
      APP_ENV: development
    working_dir: /usr/src/app
```

```cpp:test.cpp
#include <iostream>

int main() {
    std::cout << "Hello World!";
    return 0;
}
```

ビルドして実行してみます。

```sh
$ docker-compose run --rm llvm clang++ test.cpp -o test
$ docker-compose run --rm llvm ./test
$ > Hello World!
```
無事実行するまでできました :sparkles: 

## clang-tidy でチェックを行ってみる

事前に `compile_commands.json` を正しい内容で作成しておきます。
※正しい内容でないと、`Skipping xxx. Compile command not found.` という様なエラーがで続けます :warning: 

```json
[
  { "directory": "/usr/src/app",
    "command": "/usr/local/bin/clang++ -Weverything test.cpp",
    "file": "test.cpp"
  }
]
```

上記設定で実行してみると以下のチェックが出力されました :sparkles: 

```sh
> docker-compose run --rm llvm clang-tidy test.cpp           
1 warning generated.
/usr/src/app/test.cpp:6:2: warning: C++98 requires newline at end of file [clang-diagnostic-c++98-compat-pedantic]
}
 ^
```
全てOKな場合、何も表示されません。

## パッケージマネージャ
ちらほら調べてみたら **Conan** というのが良い感じらしい。
https://conan.io/

`pip` でインストール中以下のエラーが発生

```
Command “python setup.py egg_info” failed with error code 1 in …
```
[【Python】「Command "python setup.py egg_info" failed with error code 1 in ...」の対処法 - Knowhow,Nohow](https://keymaso.com/programemory/python/pip-error-1/)
↑こちらの記事を参考に`pip` と `setuptools` を最新に更新したら上手く通りました :sparkles: 

conanが使える様に `Dockerfile` を以下に修正します。

```dockerfile
FROM silkeh/clang:latest

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

RUN apt-get update && \
    apt-get install -y \
      vim \
      cmake \
      python-pip \
      --no-install-recommends && \
    rm -rf /var/lib/apt/lists/*

RUN pip install --upgrade pip setuptools && pip install conan

ADD . /usr/src/app

CMD clang++
```

conanが使えるか確認します。versionが表示されればOKです。

```sh
$ docker-compose run --rm llvm conan --version
Conan version 1.27.0
```

### パッケージを導入してみる
今回はlogging libraryの `spdlog` を導入してみたいと思います。
<a href="https://github.com/gabime/spdlog"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299271/d282e14a-9189-96ea-5110-6f69efe8e5ab.png" width="460px"></a>

コンテナ内で作業する為に `docker-compose.yml` を少し修正します。

```yml
version: "3.3"

services:
  llvm:
    build: .
    command: /bin/sh
    tty: true
    volumes:
      - .:/usr/src/app
    environment:
      APP_ENV: development
    working_dir: /usr/src/app
```
起動したら、立ち上がりっぱなしにしてコンテナ内で作業していきたいと思います。
まず、`conan search` でパッケージを検索します。

```sh
$ conan search "spdlog" --remote=conan-center
Existing package recipes:

spdlog/0.14.0@bincrafters/stable
spdlog/0.16.3@bincrafters/stable
spdlog/0.17.0@bincrafters/stable
spdlog/1.0.0@bincrafters/stable
spdlog/1.1.0@bincrafters/stable
spdlog/1.2.1@bincrafters/stable
spdlog/1.3.0@bincrafters/stable
spdlog/1.3.1@bincrafters/stable
spdlog/1.4.1@bincrafters/stable
spdlog/1.4.2
spdlog/1.4.2@bincrafters/stable
spdlog/1.5.0
spdlog/1.6.0
spdlog/1.6.1
```

`conanfile.txt` を以下の内容で作成します。

```txt
[requires]
spdlog/1.6.1

[generators]
cmake
```
もし `spdlog` を共有ライブラリ(.so)として取り込みたい場合は
以下のoptionを追加してやります。

```
[options]
spdlog:shared=True
```
また、`Pofile` 用のファイルを作成します。これをやらないと自分の環境では
`clang-10: error: linker command failed with exit code 1` の様なリンクエラーが出ました。

```clang_profile
[settings]
os=Linux
arch=x86_64
compiler=clang
compiler.version=10
compiler.libcxx=libstdc++11

[env]
CC=/usr/local/bin/clang
CXX=/usr/local/bin/clang++
```

いざ、ビルドしてみます。

```sh
$ mkdir build
$ cd build
$ conan install .. --build=spdlog -pr=../clang_profile
...
ERROR: Missing prebuilt package for 'fmt/6.2.0'
Try to build from sources with "--build=fmt"
```
何かエラーが出てしまいました :scream: 
エラーの内容をみると `fmt` も一緒にビルドしてやる必要がありそうです。

```sh
$ conan install .. --build=fmt --build=spdlog -pr=../clang_profile
```
エラー出ず最後まで実行されました :sparkles: 
この時に生成されたファイルは↓になります。

```
conan.lock  conanbuildinfo.cmake  conanbuildinfo.txt  conaninfo.txt  graph_info.json
```

早速作成した `test.cpp` で導入したパッケージを使ってみたいと思います。

```cpp
#include <iostream>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"

int main() {
    auto console = spdlog::stdout_color_mt("console");
    spdlog::get("console")->info("Hello world!");
    return 0;
}
```

`CMakeLists.txt` を以下の内容で作成します。

```
cmake_minimum_required(VERSION 3.13.4)
project(ClangSample)

add_definitions("-std=c++11")

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()

add_executable(test test.cpp)
target_link_libraries(test ${CONAN_LIBS})
```

バイナリを作っていきます。

```sh
$ cd build
$ cmake ..
$ make
```

以下コマンドで `Hello world!` が表示されればOKです :sparkles: 

```sh
$ ./bin/test 
[2020-07-02 14:46:27.156] [console] [info] Hello world!
```
### 参考URL
- [C++初心者がMacでパッケージ管理ツールConanを試してみた - Qiita](https://qiita.com/kai_kou/items/bfe7262fb6e9e571b913)