CMake パッケージガイドライン
32ビット – CLR – クロス – Eclipse – Electron – Free Pascal – GNOME – Go – Haskell – Java – KDE – カーネル – Lisp – MinGW – Node.js – ノンフリー – OCaml – Perl – PHP – Python – R – Ruby – Rust – VCS – ウェブ – Wine
この文書は cmake を使うソフトウェアの PKGBUILD を書くための標準とガイドラインをカバーしています。
はじめに
CMake は、ソフトウェアをビルド、テスト、パッケージ化するために設計された、オープンソースでクロスプラットフォームのツールファミリーです。CMake は、プラットフォームやコンパイラに依存しないシンプルな設定ファイルを使ってソフトウェアのコンパイルプロセスを制御し、選択したコンパイラ環境で使用できるネイティブな makefile と workspaces を生成するために使用されます。
典型的な使用方法
典型的な使い方は、cmake
コマンドを実行し、その後に building コマンドを実行することです。cmake
コマンドは通常、いくつかのパラメータを設定し、必要な依存関係をチェックしてビルドファイルを作成し、ソフトウェアを make
や ninja
といった他のツールでビルドできる状態にします。
CMakeの好ましくない動作について
ビルドファイルを生成するための内部特性により、CMake が好ましくない動作をすることがあります。そのため、CMake ベースのソフトウェアのために PKGBUILD を書くときにはいくつかのステップに注意する必要があります。
CMake はデフォルトのコンパイラ最適化フラグを自動的にオーバーライドすることがあります
CMake を -DCMAKE_BUILD_TYPE=Release
オプション付きで動かしている人をよく見かけます。上流のプロジェクトでは、ビルド手順にこのオプションをうっかり入れてしまうこともありますが、これは望ましくない振る舞いを生み出します。
それぞれのビルドタイプは CMake に自動的に CFLAGS
と CXXFLAGS
にフラグのセットを追加させます。一般的な Release
ビルドタイプを使うときは、自動的に -O3
[1] コンパイラ最適化フラグを追加し、これは現在 Arch Linux のデフォルトフラグである -O2
よりも優先されます。(設定ファイル makepkg configuration file で定義されています) これは Arch Linux が目標とする最適化レベルから逸脱しているので望ましくありません。
-O3
に関する注意事項
-O3
を使用したからといって、ソフトウェアのパフォーマンスが向上することを保証するものではなく、時にはプログラムの動作が遅くなることもあります。また、状況によってはソフトウェアを壊してしまうこともあります。Arch Linux の開発者がターゲット最適化レベルとして -O2
を選択したのには理由があり、私たちはそれに従うべきでしょう。あなたが何をしているかを正確に分かっている場合、またはアップストリームが -O3
が必要であると明示的・暗示的に言っている場合以外は、私たちのパッケージで使用するのは避けるべきです。
自動最適化フラグオーバーライドの修正
100%保証された方法で修正することは、CMake の柔軟性により、簡単な問題ではありません。すべてのケースに適用できる標準的な解決策は存在しないことに注意してください。ここでは、考えられる解決策と、守るべきポイントについて説明します。
CMake のデフォルトのビルドタイプは None
であり、デフォルトでは CFLAGS
と CXXFLAGS
にフラグを付加しないため、 CMAKE_BUILD_TYPE
オプションを使用しないだけでもデフォルトが None
となり動作することがあります。しかし、多くのソフトウェアプロジェクトでは、ビルドタイプを自動的に Release
に設定するため、このオプションを省略しても問題が解決する保証はないことに注意してください。コマンドラインで CMAKE_BUILD_TYPE
が設定されていない場合、CMake ファイルで (または他のタイプで) 設定します。
デフォルトの None
ビルドタイプは CFLAGS
と CXXFLAGS
にフラグを付加しないので、 -DCMAKE_BUILD_TYPE=None
オプションも使用可能です。一般的には -DCMAKE_BUILD_TYPE=None
オプションを使う方が CMAKE_BUILD_TYPE
を省略するよりも良いと言われています。これは CMAKE_BUILD_TYPE
が省略されたときにアップストリームが自動的にビルドタイプを Release
に設定する場合をカバーするもので、デフォルトではフラグは付加されず、ビルドタイプ None
に好ましくないフラグを設定するソフトウェアはまず見当たりません。
しかし、残念ながら -DCMAKE_BUILD_TYPE=None
を使えば解決するというような単純なものではありません。-O3
の問題を解決するために None
のビルドタイプを使用する場合、別の問題に陥る可能性があります。多くのソフトウェアプロジェクトでは、CMake ファイルで Release
ビルドタイプに必要なコンパイラフラグを定義するのが一般的です (例えば、CMAKE_C_FLAGS_RELEASE
と CMAKE_CXX_FLAGS_RELEASE
を設定するようなものです) CMake 変数)このようなソフトウェアは、これらの上流で定義されたフラグを使用せずにコンパイルすると、None
ビルドタイプを使用した場合、壊れたり動作がおかしくなったりする可能性があります。フラグが足りないかどうかを判断するには、CMakeファイルを見る必要がありますし make VERBOSE=1
の出力を None
と Release
ビルドタイプで比較することができます。もし、None
ビルドタイプで上流で定義されたフラグが見落とされた場合はどうすればいいのでしょうか?なぜなら、Release
ビルドタイプを使用すると、望ましくない -O3
フラグを使用する可能性があり、None
ビルドタイプを使用すると、いくつかの必要な上流定義フラグを見逃す可能性があるからです。この状況を解決する標準的な方法はありませんので、ケースバイケースで分析する必要があります。もし上流が Release
ビルドタイプに対して -O2
を定義しているなら、 -DCMAKE_BUILD_TYPE=Release
を使用することができます。(後述) それ以外の場合は、CMake ファイルにパッチを当てることで解決できるかもしれません。
いくつかのソフトウェアプロジェクトでは CMake ファイルに -O2
を Release
ビルドタイプとしてハードコードしています。
修正内容の確認
ビルドツールの冗長モードを有効にすることで、CMakeで修正内容が正しく使用されているかどうかを確認することができます。例えば、make
を使っている場合。(CMakeのデフォルトです) に VERBOSE=1
を追加することで実行できます (make VERBOSE=1
のように。) これにより、実行中のコンパイラコマンドを make
が出力するようになります。これで makepkg を実行し、コンパイラが -D_FORTIFY_SOURCE=2
と -O2
フラグを使っているか出力を確認することができます。各コマンドラインで複数の最適化フラグが表示されている場合、その行の最後のフラグがコンパイラによって使用されます(-O2
が有効になるためには、最後の最適化フラグが必要です。)
Prefix とライブラリのインストール先
Arch Linux 標準の /usr
Prefix は -DCMAKE_INSTALL_PREFIX=/usr
CMake のオプションで指定できます。多くのソフトウェアがデフォルトでファイルを /usr/local
という Prefix にインストールするため、これは通常必要です。
一部のアップストリームプロジェクトは、ライブラリを /usr/lib64
ディレクトリにインストールするように CMake ファイルを設定します。この場合、-DCMAKE_INSTALL_LIBDIR=lib
CMake オプションを使用して、ライブラリのインストールディレクトリを /usr/lib
に正しく設定できます。
ヒントとヒントとテクニック
ディレクトリの指定
CMake バージョン 3.13 以降、ビルドディレクトリを自動的に作成する -B
オプションが用意されています。これにより、分離された mkdir
によるビルドディレクトリの作成が不要になりました。(または install
) コマンドを使用します。-S
オプションはソースディレクトリ (CMakeLists.txt
ファイルを検索する場所) を指定し、 cmake
を実行する前にソースツリーに cd
する必要をなくしました。この2つのオプションを組み合わせると、ビルドとソースのディレクトリを指定する便利な方法となります。例えば、foo という名前のプログラムをビルドする場合。
PKGBUILD
build() { cmake -B build -S "foo-${pkgver}" [other_cmake_options] cmake --build build }
不要な出力の可能性を低減する
-Wno-dev
を使用します。CMake オプションは、CMakeLists.txt
ファイルを書いた上流プロジェクトの開発者のみを対象とした警告の出力を抑止します。これらの警告を削除することで、CMake の出力がスムーズになり、それを調べる負担が軽減されます。一般的なルールとして、これらの警告は通常パッケージャが安全に無視できるものです。
バイナリから安全でない RPATH
参照を削除する
作成されたバイナリが RPATH
に安全でない参照を含むことがあります。これはビルドされたパッケージに対して Namcap を実行することで確認でき、修正されるべきセキュリティ問題であることがわかります。この問題は、CMAKE_SKIP_INSTALL_RPATH=YES
を使用することで修正できる可能性が高いです。または CMAKE_SKIP_RPATH=YES
CMake のオプションです。両方を使って実験し、問題のソフトウェアで何がうまくいくかを見る必要があります(両方のオプションを使うことは必要ありません。)
利用可能な全てのCMakeオプションの取得
ソフトウェアプロジェクトで利用可能なすべての「見える」CMakeオプションを取得するには、ソースツリーで cmake -LAH
を実行します(メインの CMakeLists.txt
ファイルがあるところです)。
もし、後で参照するために出力を保存したい場合は、ファイルにリダイレクトすることができます。
$ cmake -LAH >options.txt 2>&1
ビルド中の FetchContent のダウンロードを回避
CMake は、ビルド時に追加のリソースまたはサブプロジェクトを取得できるようにする FetchContent モジュールを提供します。ただし、理想的には、すべてのソースは sources
配列で指定されているため、ビルド前に makepkg によってフェッチされる必要があります。これは、オプション FETCHCONTENT_SOURCE_DIR_<uppercaseName> を使用して実行できます。これにより、ファイルへのパスを指定できます。それ以外の場合は取得されます。さらに、FETCHCONTENT_FULLY_DISCONNECTED=ON を使用すると、FetchContent
宣言を見逃しても、ビルド中にすべてのダウンロードをスキップすることができます。
例
プロジェクトがリソース foo
を取得すると仮定します。
CMakeLists.txt
FetchContent_Declare( foo URL https://example.com/foo.tar.gz URL_HASH SHA256=cf051bf611a94884ba5e4c2d03932d14e83875c5b77f0fdf55c404cad0e4a6e6 ) FetchContent_MakeAvailable(foo)
次に、ビルド中にダウンロードする代わりに、このリソースを sources
配列に追加し、ビルド ファイルの生成時に宣言できます。
PKGBUILD
sources=( ... "https://example.com/foo.tar.gz" ) sha256sums=( ... "cf051bf611a94884ba5e4c2d03932d14e83875c5b77f0fdf55c404cad0e4a6e6" )
$ cmake -B build -S "$pkgname-$pkgver" -DFETCHCONTENT_FULLY_DISCONNECTED=ON -DFETCHCONTENT_SOURCE_DIR_FOO="$srcdir/foo"
テンプレート
ここでは、CMake ベースのパッケージの出発点となる build()
関数の一般的なテンプレートについて説明します。パッケージの名前は foo で、C および C++ ベースであり、CMake ファイルの中で Release
ビルドタイプに必要なコンパイラフラグを定義していないと仮定します。
で使われている場合のみ働きます。
PKGBUILD
build() { cmake -B build -S "foo-${pkgver}" \ -DCMAKE_BUILD_TYPE='None' \ -DCMAKE_INSTALL_PREFIX='/usr' \ -Wno-dev cmake --build build } check() { cd build ctest --output-on-failure } package() { DESTDIR="$pkgdir" cmake --install build }
cmake を makedepends に配置することを忘れないでください。