CMake try_compile() を使って特定のライブラリがインストールされているかどうかを確認する方法

2024-04-02

CMake try_compile() コマンドの詳細解説

try_compile() は、CMake の強力なコマンドの一つで、コードを実際にコンパイルすることなく、コンパイルが成功するかどうかを確認することができます。これは、特定のコンパイラやオプションがシステム上で使用可能かどうかをテストしたり、コードの移植性を検証したりする際に非常に便利です。

基本的な使い方

try_compile() は以下の構文で記述します。

try_compile(
  <compileResultVar>
  [COMPILE_DEFINITIONS <definitions>]
  [COMPILE_OPTIONS <options>]
  [SOURCE_DIR <directory>]
  [CODE <source_code>]
)

引数

  • <compileResultVar>: コンパイル結果を格納する変数です。TRUE で成功、FALSE で失敗となります。
  • [COMPILE_DEFINITIONS]: コンパイル時に使用するマクロ定義を指定します。
  • [COMPILE_OPTIONS]: コンパイルオプションを指定します。
  • [SOURCE_DIR]: ソースコードファイルが存在するディレクトリを指定します。
  • [CODE]: テスト用のソースコードを直接記述できます。

詳細な解説

  • COMPILE_DEFINITIONS: 複数のマクロ定義を指定する場合は、 ; で区切ります。例えば、
try_compile(
  COMPILE_DEFINITIONS "FOO=1;BAR=2"
  ...
)
  • COMPILE_OPTIONS: 複数のオプションを指定する場合は、スペースで区切ります。例えば、
try_compile(
  COMPILE_OPTIONS "-Wall -Wextra"
  ...
)
  • SOURCE_DIR: ソースコードファイルが複数存在する場合は、ディレクトリを指定する方が効率的です。
try_compile(
  SOURCE_DIR "src"
  ...
)
  • CODE: ソースコードを直接記述する場合は、シングルクォートで囲みます。例えば、
try_compile(
  CODE """
  int main() {
    return 0;
  }
  """
  ...
)

応用例

  • 特定のコンパイラ機能が使用可能かどうかを確認する
  • 特定のライブラリがシステム上でインストールされているかどうかを確認する
  • コードの移植性を検証する
  • 条件付きでコードをビルドする

補足

  • try_compile() は、あくまでもコンパイルのみをテストするコマンドです。リンケージエラーなどは検出できません。
  • 詳細な情報は、上記の参考資料を参照してください。

注意

  • 上記の解説は、CMake バージョン 3.29.0-rc3 をベースにしています。古いバージョンの CMake では、try_compile() の機能が異なる場合があります。


CMake try_compile() のサンプルコード

特定のコンパイラ機能が使用可能かどうかを確認する

try_compile(
  HAS_CXX17
  COMPILE_FEATURES cxx17
  CODE """
  #include <iostream>

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

if (HAS_CXX17)
  message(STATUS "C++17 is supported")
else()
  message(STATUS "C++17 is not supported")
endif()

特定のライブラリがシステム上でインストールされているかどうかを確認する

try_compile(
  HAS_LIBPNG
  LINK_LIBRARIES libpng
  CODE """
  #include <png.h>

  int main() {
    png_structp png_ptr;
    png_infop info_ptr;

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    info_ptr = png_create_info_struct(png_ptr);

    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

    return 0;
  }
  """
)

if (HAS_LIBPNG)
  message(STATUS "libpng is installed")
else()
  message(STATUS "libpng is not installed")
endif()

コードの移植性を検証する

try_compile(
  COMPILATION_WORKS
  CODE """
  #include <stdio.h>

  int main() {
    printf("Hello, world!\n");
    return 0;
  }
  """
)

if (COMPILATION_WORKS)
  message(STATUS "Code is portable")
else()
  message(STATUS "Code is not portable")
endif()

条件付きでコードをビルドする

try_compile(
  HAS_OPENMP
  COMPILE_OPTIONS "-fopenmp"
  CODE """
  #include <omp.h>

  int main() {
    #pragma omp parallel
    {
      printf("Hello, world!\n");
    }

    return 0;
  }
  """
)

if (HAS_OPENMP)
  set(BUILD_WITH_OPENMP TRUE)
else()
  set(BUILD_WITH_OPENMP FALSE)
endif()

add_library(mylib ... )

if (BUILD_WITH_OPENMP)
  target_compile_options(mylib PUBLIC "-fopenmp")
endif()


CMake try_compile() の代替方法

  • 実際にコンパイルを実行するため、時間がかかります。
  • リンケージエラーなどの詳細な情報は得られません。

これらの欠点を克服するために、try_compile() の代替方法として以下の方法が考えられます。

CMAKE_CXX_COMPILER_ID などの CMake 変数を使って、コンパイラの種類を判断することができます。例えば、

if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  message(STATUS "Clang compiler is used")
endif()

ただし、この方法はコンパイラのバージョンやオプションまでは判断できません。

ヘッダーファイルの存在を確認する

特定の機能を使うためには、ヘッダーファイルが必要となります。そのため、ヘッダーファイルの存在を確認することで、その機能が使用可能かどうかを判断することができます。例えば、

find_path(PNG_INCLUDE_DIR PNG.h)

if (PNG_INCLUDE_DIR)
  message(STATUS "libpng is installed")
else()
  message(STATUS "libpng is not installed")
endif()

ただし、ヘッダーファイルが存在しても、実際にコンパイルできるかどうかは保証されません。

外部ツールを使う

pkg-config などの外部ツールを使って、ライブラリやコンパイラ機能の存在を確認することができます。例えば、

pkg_check_modules(PNG REQUIRED libpng)

if (PNG_FOUND)
  message(STATUS "libpng is installed")
else()
  message(STATUS "libpng is not installed")
endif()

ただし、外部ツールがインストールされていない場合は、この方法を使用できません。

手動で確認する

どうしても try_compile() 以外の方法が必要な場合は、手動で確認するしかありません。

try_compile() は、コンパイルの可否をテストする便利なコマンドですが、欠点もあります。状況に応じて、上記の代替方法も検討してみてください。




CMake で変数を削除する3つの方法:unset() 以外にも使えるテクニック

<variable_name> は、削除したい変数の名前です。変数の名前は、文字、数字、下線(_)で構成され、先頭に数字以外のアクティブ文字が来る必要があります。変数の削除この例では、MY_VAR という変数を作成し、"Hello, world!" という値を設定します。その後、unset() コマンドを使用して MY_VAR を削除します。2番目の message() コマンドは、MY_VAR が削除されたことを確認するために使用されます。



CMakeのCommandsにおけるuse_mangled_mesa()

use_mangled_mesa() は CMake の Commands における関数で、Mesa ライブラリの mangled シンボル名を解決するために使用されます。Mesa は OpenGL の実装であり、古いバージョンの Mesa ではシンボル名が mangled されるため、use_mangled_mesa() を使用してこれらのシンボル名を解決する必要があります。


CMakeの依存関係を使用したプログラミング

CMakeで依存関係を使用するには、以下の2つの方法があります。find_packageコマンドは、特定のライブラリやフレームワークがインストールされているかどうかを検出し、その場所と設定情報を提供します。外部プロジェクトを参照するadd_subdirectoryコマンドを使用して、外部プロジェクトを現在のプロジェクトに組み込むことができます。外部プロジェクトは、CMakeLists


サブディレクトリ、custom_command、ExternalProject:USE_FOLDERSプロパティの代替手段

USE_FOLDERS プロパティは、CMakeLists. txt ファイル内で以下の方法で設定できます。上記のように ON に設定すると、CMake はソースファイルとヘッダーファイルをフォルダ階層に基づいてグループ化します。デフォルトでは OFF に設定されており、フォルダ階層は考慮されません。


Visual Studioでシェーダーファイルをコンパイルする:CMakeのVS_SHADER_FLAGSオプション

CMake の "Properties: Source Files" に設定できる "VS_SHADER_FLAGS" は、Visual Studio でシェーダーファイルのコンパイル時に渡されるオプションを指定します。このオプションは、シェーダーの動作やコンパイル方法を制御するために使用されます。



CMake find_libraryコマンドとfind_packageモジュールの比較

find_library() コマンドは、CMake で外部ライブラリを見つけるために使用されます。これは、プロジェクトに必要なライブラリを自動的に検出して、ビルドプロセスを簡略化するのに役立ちます。コマンドフォーマット<VAR>: 検索結果を格納する変数名


CMake でできること: 外部ライブラリの利用、サブディレクトリのビルド、クロスコンパイルなど

"VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION" は、CMake の "Properties: Targets" で使用されるターゲット プロパティであり、Windows アプリケーションが実行できる最低限のオペレーティング システム (OS) バージョンを指定します。このプロパティを設定することで、古いバージョンの Windows でアプリケーションが動作しないようにすることができます。


CMakeにおけるVS_WINRT_COMPONENTを使用したサンプルコード

"VS_WINRT_COMPONENT"は、CMakeでWindows向けRTコンポーネントをビルドする際に使用するプロパティです。このプロパティを設定することで、Visual Studioソリューションファイル (.sln) とプロジェクトファイル (.vcxproj) の生成に必要な情報を提供できます。


CMakeでiOSアプリ開発:IOS_INSTALL_COMBINEDとその他の方法を徹底比較

IOS_INSTALL_COMBINED は、CMake のターゲットプロパティであり、iOS デバイスとシミュレータ用のコードを組み合わせて、ユニバーサルバイナリと呼ばれる単一のライブラリを生成するかどうかを制御します。これは、複数のアーキテクチャをサポートする iOS アプリケーションを開発する場合に役立ちます。


CMake: find_library()とtarget_link_directories()の連携

target_link_directories()コマンドは、CMakeプロジェクト内のターゲットに対して、リンカがライブラリを検索するディレクトリを指定するために使用されます。これは、ターゲットがリンクするライブラリが標準の検索パスに存在しない場合に特に重要です。