C/C++用パッケージマネージャのconanを使ってみた

# はじめに

C/C++用パッケージマネージャのconanを使ってみます。

## C/C++用パッケージマネージャの比較

有名なC/C++用パッケージマネージャを調べたところ、次の3つが見つかりました。

https://conan.io/

https://hunter.readthedocs.io/en/latest/

https://vcpkg.io/en/index.html

比較してみましょう。

**表. C/C++用パッケージマネージャ比較表**

| 項目                 | conan                          | vcpkg             | hunter |
| -------------------- | ------------------------------ | ----------------- | ------ |
| pakcage数            | 1,212,203 Versions Indexed     | 1732 packages     | 不明   |
| artifactマネージャー     | JFrog Artifactory              | なし              | なし   |
| 主要開発者         | JFrog                            | Microsoft             | 不明    |
| サポートするbuild system | 29(cmake, msbuild, gmake, gcc) | 2(cmake, msbuild) | 不明   |
| GitHub start         | 5,220                          | 13,587            | 366    |
| GiHub watch          | 130                            | 399               | 22     |
| GitHub forks         | 654                            | 3,909             | 582    |

conanかvcpkgが良さそうですね。

artifactマネージャーと連携させてpipelineへ組み込むことや、様々なプロジェエクトに流用することを考えると、conanが良さそうです。

## conan とは

conanは、C/C++のパッケージマネージャーです。

conan には次のような特長があります。

1. エコシステム上のツールがすべて無料かつオープンソース
1. マルチプラットフォームに対応(Windows、Linux、OSX、FreeBSD、Solarisなど)
1. マルチターゲット環境に対応(組み込み、モバイル（iOS、Android）、ベアメタル)
1. マルチビルドシステムに対応(CMake、Visual Studio（MSBuild）、Makefiles、SConsなど)

conan のエコシステムは、以下の3つツールやサービスで構成されます。

1. Clientで動作するCLIツールの conan 
1. JFrog社が提供する無料アーティファクトマネージャの JFrog ARTIFACTORY CE for C/C++ 
1. オンラインでOSSパッケージを提供するサービス JFrog CONAN CENTER

> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114392/cdc883c3-7ed5-cba9-3330-6126f467c19b.png)
> 
> 出典：[はじめに— conan1.39.0ドキュメント](https://docs.conan.io/en/latest/introduction.html)

# インストール

## インストール

pipでインストールします。

```bash
$ sudo pip install conan
```

## 動作確認

動作確認します。

```bash
$ conan

Consumer commands
  install    Installs the requirements specified in a recipe (conanfile.py or conanfile.txt).
  config     Manages Conan configuration.
  get        Gets a file or list a directory of a given reference or package.
  info       Gets information about the dependency graph of a recipe.
  search     Searches package recipes and binaries in the local cache or a remote. Unless a
             remote is specified only the local cache is searched.
Creator commands
  new        Creates a new package recipe template with a 'conanfile.py' and optionally,
             'test_package' testing files.
  create     Builds a binary package for a recipe (conanfile.py).
  upload     Uploads a recipe and binary packages to a remote.
  export     Copies the recipe (conanfile.py & associated files) to your local cache.
  export-pkg Exports a recipe, then creates a package from local source and build folders.
  test       Tests a package consuming it from a conanfile.py with a test() method.
Package development commands
  source     Calls your local conanfile.py 'source()' method.
  build      Calls your local conanfile.py 'build()' method.
  package    Calls your local conanfile.py 'package()' method.
  editable   Manages editable packages (packages that reside in the user workspace, but are
             consumed as if they were in the cache).
  workspace  Manages a workspace (a set of packages consumed from the user workspace that
             belongs to the same project).
Misc commands
  profile    Lists profiles in the '.conan/profiles' folder, or shows profile details.
  remote     Manages the remote list and the package recipes associated with a remote.
  user       Authenticates against a remote with user/pass, caching the auth token.
  imports    Calls your local conanfile.py or conanfile.txt 'imports' method.
  copy       Copies conan recipes and packages to another user/channel.
  remove     Removes packages or binaries matching pattern from local cache or remote.
  alias      Creates and exports an 'alias package recipe'.
  download   Downloads recipe and binaries to the local cache, without using settings.
  inspect    Displays conanfile attributes, like name, version, and options. Works locally,
             in local cache and remote.
  help       Shows help for a specific command.
  lock       Generates and manipulates lock files.
  frogarian  Conan The Frogarian

Conan commands. Type "conan <command> -h" for help
```

## プロファイル設定

コンパイラとして、gcc >= 5.1 を使っている場合には、conanのプロファイルの更新が必要です。
次のコマンドを実行してプロファイルを更新しましょう。

```bash
$ conan profile new default --detect  # Generates default profile detecting GCC and sets old ABI
$ conan profile update settings.compiler.libcxx=libstdc++11 default  # Sets libcxx to C++11 ABI
```

詳細：[Getting Started — conan 1.39.0 documentation](https://docs.conan.io/en/latest/getting_started.html#an-md5-hash-calculator-using-the-poco-libraries)

# Getting Start

Getting Startedをやってみましょう。

https://docs.conan.io/en/latest/getting_started.html

## サンプルプログラムのクローン

サンプルプログラムをクローンします。

```bash
$ git clone https://github.com/conan-io/examples.git && cd examples/libraries/poco/md5
```

コンパイルするソースコードを確認します。

```bash
$ cat md5.cpp 
#include "Poco/MD5Engine.h"
#include "Poco/DigestStream.h"

#include <iostream>


int main(int argc, char** argv)
{
    Poco::MD5Engine md5;
    Poco::DigestOutputStream ds(md5);
    ds << "abcdefghijklmnopqrstuvwxyz";
    ds.close();
    std::cout << Poco::DigestEngine::digestToHex(md5.digest()) << std::endl;
    return 0;
```

これは、[poco](https://pocoproject.org/) という著名なC++ライブラリを使用してMD5を計算するプログラムです。

Pocoのバイナリファイルは、JFrog CONAN CENTER で公開されています。

https://conan.io/center/poco

## パッケージインストール

conan コマンドを使ってpocoのバージョン1.9.4 の情報を確認してみましょう。

conan inspect コマンドでパッケージの情報を閲覧できます。

```bash
$ conan inspect poco/1.9.4
WARN: Remotes registry file missing, creating default one in /home/kannkyo/.conan/remotes.json
poco/1.9.4: Not found in local cache, looking in remotes...
poco/1.9.4: Trying with 'conancenter'...
Downloading conanmanifest.txt completed [0.74k]                                          
Downloading conanfile.py completed [14.36k]                                              
Downloading conan_export.tgz completed [0.30k]                                           
Decompressing conan_export.tgz completed [0.00k]                                         
poco/1.9.4: Downloaded recipe revision 0
name: poco
version: 1.9.4
url: https://github.com/conan-io/conan-center-index
homepage: https://pocoproject.org
license: BSL-1.0
author: None
description: Modern, powerful open source C++ class libraries for building network- and internet-based applications that run on desktop, server, mobile and embedded systems.
topics: ('conan', 'poco', 'building', 'networking', 'server', 'mobile', 'embedded')
generators: ('cmake', 'cmake_find_package')
exports: None
exports_sources: ('CMakeLists.txt', 'patches/**')
short_paths: False
apply_env: True
build_policy: None
revision_mode: hash
settings: ('os', 'arch', 'compiler', 'build_type')
options:
    enable_active_record: [True, False]
    enable_apacheconnector: [True, False]
    enable_cppparser: [True, False]
    enable_crypto: [True, False]
    enable_data: [True, False]
    enable_data_mysql: [True, False]
    enable_data_odbc: [True, False]
    enable_data_postgresql: [True, False]
    enable_data_sqlite: [True, False]
    enable_encodings: [True, False]
    enable_fork: [True, False]
    enable_json: [True, False]
    enable_jwt: [True, False]
    enable_mongodb: [True, False]
    enable_net: [True, False]
    enable_netssl: [True, False]
    enable_netssl_win: [True, False]
    enable_pagecompiler: [True, False]
    enable_pagecompiler_file2page: [True, False]
    enable_pdf: [True, False]
    enable_pocodoc: [True, False]
    enable_redis: [True, False]
    enable_sevenzip: [True, False]
    enable_util: [True, False]
    enable_xml: [True, False]
    enable_zip: [True, False]
    fPIC: [True, False]
    shared: [True, False]
default_options:
    enable_active_record: True
    enable_apacheconnector: False
    enable_cppparser: False
    enable_crypto: True
    enable_data: True
    enable_data_mysql: True
    enable_data_odbc: False
    enable_data_postgresql: True
    enable_data_sqlite: True
    enable_encodings: True
    enable_fork: True
    enable_json: True
    enable_jwt: True
    enable_mongodb: True
    enable_net: True
    enable_netssl: True
    enable_netssl_win: False
    enable_pagecompiler: False
    enable_pagecompiler_file2page: False
    enable_pdf: False
    enable_pocodoc: False
    enable_redis: True
    enable_sevenzip: False
    enable_util: True
    enable_xml: True
    enable_zip: True
    fPIC: True
    shared: False
deprecated: None
```

この`poco/1.9.4` をconanで使用するために必要なパッケージ管理ファイル `conanfile.txt`を見てみましょう。

```bash
$ cat conanfile.txt 
[requires]
poco/1.9.4

[generators]
cmake
```

この例では、コンパイルに必要なパッケージ`requires`は`poco/1.9.4`のみで、コンパイルを実行する`generator`としてcmakeを指定しています。

conan はcmake以外にも以下のgeneratorに対応しています。

- cmake
- cmake_multi
- cmake_paths
- cmake_find_package
- cmake_find_package_multi
- msbuild
- visual_studio
- visual_studio_multi
- visual_studio_legacy
- xcode
- compiler_args
- gcc
- boost-build
- b2
- qbs
- qmake
- scons
- pkg_config
- virtualenv
- virtualenv_python
- virtualbuildenv
- virtualrunenv
- youcompleteme
- txt
- json
- premake
- make
- markdown
- deploy

conan で`poco/1.9.4`をダウンロードして、cmake用のファイルを生成してみましょう。

```bash
$ mkdir build && cd build
$ conan install ..
```

`build/`フォルダにはcmakeとconanのための管理ファイルが生成されます。

```bash
$ ll
conan.lock
conanbuildinfo.cmake
conanbuildinfo.txt
conaninfo.txt
graph_info.json
```

## ビルド

次に、生成された`conanbuildinfo.cmake`を呼び出す独自のCMakeLists.txtを作成しましょう。

```bash
$ cd ../
$ cat CMakeLists.txt 
cmake_minimum_required(VERSION 2.8.12)
project(MD5Encrypter)

if(CMAKE_VERSION VERSION_LESS 3.0.0)
    include(CheckCXXCompilerFlag)
    check_cxx_compiler_flag(-std=c++11 COMPILER_SUPPORTS_CXX11)
    check_cxx_compiler_flag(-std=c++0x COMPILER_SUPPORTS_CXX0X)
    if(COMPILER_SUPPORTS_CXX11)
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
    elseif(COMPILER_SUPPORTS_CXX0X)
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
    endif()
else()
    SET(CMAKE_CXX_STANDARD 11)
    SET(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()

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

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

CMakeLists.txtを使ってビルドしてみましょう。

```bash
$ cd build/
$ cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Conan: Adjusting output directories
-- Conan: Using cmake global configuration
-- Conan: Adjusting default RPATHs Conan policies
-- Conan: Adjusting language standard
-- Current conanbuildinfo.cmake directory: /tmp/conan/examples/libraries/poco/md5/build
-- Conan: Compiler GCC>=5, checking major version 9
-- Conan: Checking correct version: 9
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/conan/examples/libraries/poco/md5/build

$ cmake --build .
Scanning dependencies of target md5
[ 50%] Building CXX object CMakeFiles/md5.dir/md5.cpp.o
[100%] Linking CXX executable bin/md5
[100%] Built target md5
+ bin/md5
c3fcd3d76192e4007dfb496cca67e13b
```

ビルドできました。

## 依存関係管理

インストールされたパッケージを確認しましょう。

```bash
$ conan search "*"
Existing package recipes:

bzip2/1.0.8
expat/2.4.1
openssl/1.1.1k
pcre/8.45
poco/1.9.4
sqlite3/3.36.0
zlib/1.2.11
```

pocoだけでなく、pocoが依存するパッケージもインストールされています。

パッケージ間の依存関係はhtml形式で可視化できます。

```bash
$ cd build/
$ conan info .. --graph=file.html
```

![Screenshot from 2021-09-05 16-14-58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114392/8b1d254d-29e4-c7c6-845a-698e23044ab2.png)