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


概要

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

参考にしたリポジトリ

個人的にキャッチアップする際にGithubのトレンドに入ってるリポジトリを色々眺めて
キャッチしていくスタイルなので今回も同様の方法で試してみたいと思います。

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

参考にしたリポジトリ同様Dockerを使ってコンパイルする

LLVM + clang のDockerイメージを有志が作成していたのでそちらを使用してみたいと思います。
https://hub.docker.com/r/silkeh/clang/

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++
docker-compose.yml
version: "3.3"

services:
  llvm:
    build: .
    command: clang++
    volumes:
      - .:/usr/src/app
    environment:
      APP_ENV: development
    working_dir: /usr/src/app
test.cpp
#include <iostream>

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

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

$ docker-compose run --rm llvm clang++ test.cpp -o test
$ docker-compose run --rm llvm ./test
$ > Hello World!

無事実行するまでできました

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

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

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

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

> 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
↑こちらの記事を参考にpipsetuptools を最新に更新したら上手く通りました

conanが使える様に 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です。

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

パッケージを導入してみる

今回はlogging libraryの spdlog を導入してみたいと思います。

コンテナ内で作業する為に docker-compose.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 でパッケージを検索します。

$ 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 を以下の内容で作成します。

[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 の様なリンクエラーが出ました。

[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++

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

$ 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"

何かエラーが出てしまいました
エラーの内容をみると fmt も一緒にビルドしてやる必要がありそうです。

$ conan install .. --build=fmt --build=spdlog -pr=../clang_profile

エラー出ず最後まで実行されました
この時に生成されたファイルは↓になります。

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

早速作成した test.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})

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

$ cd build
$ cmake ..
$ make

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

$ ./bin/test 
[2020-07-02 14:46:27.156] [console] [info] Hello world!

参考URL