conanfile.txtで条件分岐したい場合はconanfile.pyを使う
TL;DR
conan
パッケージに関して環境依存で細かい条件分岐をしたい場合はconanfile.txt
ではなくconanfile.py
を使いましょう。
Pythonコードでやりたい放題です。
導入というかtermuxの話
termux
面白いですね。
普段持ち歩くAndroidでほぼ完璧なLinux環境が作れてしまうワクワク感がたまりません。
最近termux
で開発環境を作るのが楽しいです。
そこで困るのがtermux
の特殊なコンパイル環境です。
最近になってclang version 11が入ってほぼ最新のC++環境が手に入るのですが、微妙にx86_64とは異なる勝手があって困ることがあります。 今日困ったけれどなんとか解決できたものがあったのでメモっておきます。
足りないヘッダファイルがあってboostがコンパイルできない
私はC++のパッケージマネージャーの一つであるConan
を利用しています。
conan.io
Termux
に限らず、色々な環境でビルドする時にライブラリのバージョンを揃えたり、マイナーなライブラリを利用する際にとても便利です。
Termux
でもConan
を使ってboost
ライブラリの最新版を使ってみようと思ったのですが、見事にハマりました。
strfmon()
を定義している monetary.h
というヘッダがないのでboost localeとboost logがビルドできないのです。
libs/locale/src/posix/numeric.cpp:26:10: fatal error: 'monetary.h' file not found #include <monetary.h> ^~~~~~~~~~~~ 1 error generated.
conanでパッケージオプションを指定する方法
boost
のCMakelists.txt
側で認識してくれていないのが謎ですが monetary.h
が無い環境なんてかなりマイナーなのでしょう。
私としてはとにかく今利用できないのが困ります。
幸いboost locale, boost logを使っていないプロジェクトが多いので、そういうプロジェクトだけはTermux
でビルドできるようにしてみたいと思いました。
boost locale, boost logだけをビルドの対象から外すのはconan
コマンドが読み込むconanfile.txt
にパッケージオプションを指定するだけです。
[requires] boost/1.75.0 [generators] cmake [options] boost.without_locale = True boost.without_log = True
monetary.hがない時だけパッケージオプションを指定したい
上の方法でとりあえずコンパイルできるのですが monetary.h
がある環境ではboost locale, boost logもビルドしてほしいのです。
そうしないと~/.conan/data/boost//1.75.0/_/_/package
の下に「全ビルド版」と「locale, log除外版」の複数のバイナリが生成されてしまってboost
の性質上やたらディスク使用量が大きいのが嫌だなぁと。(貧乏性です)
こういう環境などによる条件分岐にconanfile.txt
は対応していません。
幸いconan
のgithub
に同じような質問をしている人がいました。
github.com
なるほどconanfile.txt
と同じようにインストールするパッケージ方法としてconanfile.py
があるんですね。
知らなんだ。
docs.conan.io
conanfile.py
の中では普通にPython
が書けてしまうのでmonetary.h
の存在チェックも可能になります。
ひとまず以下のようなconanfile.py
を書いてやりたいことを実現できるようになりました。
from conans import ConanFile import subprocess class ProjectConan(ConanFile): settings = "os", "arch", "compiler" generators = "cmake" def requirements(self): self.requires("boost/1.75.0") def config_options(self): compiler = str(self.settings.compiler) # check monetary header existance if self.settings.os == "Linux" and (compiler == "gcc" or compiler == "clang"): monetary_check = subprocess.run([compiler, "-E", "-x", "c", "-"], input="#include<monetary.h>", text=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if monetary_check.returncode != 0: self.options["boost"].without_locale = True self.options["boost"].without_log = True