CMakeでパスを比較する3つの方法:PATH_EQUAL オペレーター vs FILE_PATH_SAME 関数 vs CMAKE_MATCH_PATH マクロ


CMakeポリシー CMP0139 は、if() コマンドにおけるパス比較において PATH_EQUAL オペレーターの利用を制御します。このポリシーは CMake 3.24 で導入され、デフォルトでは無効化されています。

旧動作と新動作

ポリシーが有効化されていない場合 (OLD 動作)、if() コマンドは PATH_EQUAL オペレーターを無視し、従来の動作に従います。一方、ポリシーが有効化されている場合 (NEW 動作)、if() コマンドは PATH_EQUAL オペレーターを認識し、パスの一致に基づいて条件分岐を実行します。

具体的な影響

以下の例は、ポリシーが有効化されていない場合と有効化されている場合の動作の違いを示しています。

# ポリシーが無効化されている場合 (OLD 動作)
if(PATH_EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}")
  message(STATUS "ソースディレクトリとバイナリディレクトリは同じです")
else()
  message(STATUS "ソースディレクトリとバイナリディレクトリは異なります")
endif()

この例では、たとえ CMAKE_SOURCE_DIRCMAKE_BINARY_DIR が同じパスを指し示していても、常に "ソースディレクトリとバイナリディレクトリは異なります" というメッセージが出力されます。これは、ポリシーが無効化されているため、PATH_EQUAL オペレーターが無視されるからです。

一方、以下の例は、ポリシーが有効化されている場合の動作を示しています。

# ポリシーが有効化されている場合 (NEW 動作)
if(PATH_EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}")
  message(STATUS "ソースディレクトリとバイナリディレクトリは同じです")
else()
  message(STATUS "ソースディレクトリとバイナリディレクトリは異なります")
endif()

この例では、CMAKE_SOURCE_DIRCMAKE_BINARY_DIR が同じパスを指し示している場合、 "ソースディレクトリとバイナリディレクトリは同じです" というメッセージが出力されます。これは、ポリシーが有効化されているため、PATH_EQUAL オペレーターが認識され、パスの一致に基づいて条件分岐が実行されるからです。

利点

PATH_EQUAL オペレーターを使用することで、パスの比較をより直感的に記述することができます。従来のパス比較方法では、FILE_PATH_SAME 関数などを利用する必要があり、コードが煩雑になりがちでした。

注意点

このポリシーは、CMake 3.24 以降でのみ使用可能です。古いバージョンの CMake を使用している場合は、PATH_EQUAL オペレーターを使用する代わりに、FILE_PATH_SAME 関数などの従来のパス比較方法を使用する必要があります。



cmake_minimum_required(VERSION 3.24)

cmake_policy(CMP0139 NEW)

set(CMAKE_SOURCE_DIR "/home/user/source")
set(CMAKE_BINARY_DIR "/home/user/build")

if(PATH_EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}")
  message(STATUS "ソースディレクトリとバイナリディレクトリは同じです")
else()
  message(STATUS "ソースディレクトリとバイナリディレクトリは異なります")
endif()

この例では、まず cmake_minimum_required コマンドを使用して、必要な CMake バージョンを 3.24 以上に設定します。次に、cmake_policy コマンドを使用して、CMP0139 ポリシーを NEW 動作に設定します。その後、CMAKE_SOURCE_DIRCMAKE_BINARY_DIR 変数にそれぞれソースディレクトリとバイナリディレクトリのパスを設定します。最後に、if() コマンドを使用して、PATH_EQUAL オペレーターでパスを比較します。パスが一致する場合、"ソースディレクトリとバイナリディレクトリは同じです" というメッセージが出力されます。そうでない場合は、"ソースディレクトリとバイナリディレクトリは異なります" というメッセージが出力されます。

例2:パス存在チェック

以下の例は、if() コマンドを使用して、PATH_EXISTS オペレーターでパスの存在をチェックする方法を示しています。

cmake_minimum_required(VERSION 3.24)

cmake_policy(CMP0139 NEW)

set(CMAKE_MY_DIR "/home/user/mydir")

if(PATH_EXISTS "${CMAKE_MY_DIR}")
  message(STATUS "ディレクトリ ${CMAKE_MY_DIR} は存在します")
else()
  message(STATUS "ディレクトリ ${CMAKE_MY_DIR} は存在しません")
endif()

この例では、まず cmake_minimum_required コマンドを使用して、必要な CMake バージョンを 3.24 以上に設定します。次に、cmake_policy コマンドを使用して、CMP0139 ポリシーを NEW 動作に設定します。その後、CMAKE_MY_DIR 変数にチェック対象のディレクトリのパスを設定します。最後に、if() コマンドを使用して、PATH_EXISTS オペレーターでディレクトリが存在するかどうかをチェックします。ディレクトリが存在する場合、"ディレクトリ ${CMAKE_MY_DIR} は存在します" というメッセージが出力されます。そうでない場合は、"ディレクトリ ${CMAKE_MY_DIR} は存在しません" というメッセージが出力されます。

これらの例は、CMakeポリシー CMP0139 と PATH_EQUAL および PATH_EXISTS オペレーターをどのように使用できるかを示すほんの一例です。これらのオペレーターを組み合わせることで、さまざまなパス関連の条件分岐を記述することができます。



代替方法

CMP0139 ポリシーが利用できない場合、以下の方法でパス比較を行うことができます。

FILE_PATH_SAME 関数

FILE_PATH_SAME 関数は、2つのパスの文字列表現が同じかどうかを比較します。この関数は、CMP0139 ポリシーが導入されるよりも前に存在しており、ポリシーの代替手段として使用することができます。

if(FILE_PATH_SAME "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}")
  message(STATUS "ソースディレクトリとバイナリディレクトリは同じです")
else()
  message(STATUS "ソースディレクトリとバイナリディレクトリは異なります")
endif()

REALPATH マクロ

REALPATH マクロは、パスのシンボリックリンクを解決し、実在するパスを取得します。このマクロを使用して、2つのパスの実在パスを取得し、文字列比較を行うことで、パスの一致を確認することができます。

set(REAL_SOURCE_DIR ${CMAKE_SOURCE_DIR})
real_path(${REAL_SOURCE_DIR})

set(REAL_BINARY_DIR ${CMAKE_BINARY_DIR})
real_path(${REAL_BINARY_DIR})

if(STREQUAL "${REAL_SOURCE_DIR}" "${REAL_BINARY_DIR}")
  message(STATUS "ソースディレクトリとバイナリディレクトリは同じです")
else()
  message(STATUS "ソースディレクトリとバイナリディレクトリは異なります")
endif()

CMAKE_MATCH_PATH マクロ

CMAKE_MATCH_PATH マクロは、指定されたパスが特定のリストに含まれているかどうかを判断します。このマクロを使用して、2つのパスのいずれかが特定のディレクトリツリーに属しているかどうかを確認することができます。

set(POSSIBLE_DIRS "/home/user/source" "/home/user/build")

if(CMAKE_MATCH_PATH "${CMAKE_SOURCE_DIR}" "${POSSIBLE_DIRS}")
  message(STATUS "ソースディレクトリは ${POSSIBLE_DIRS} のいずれかに存在します")
else()
  message(STATUS "ソースディレクトリは ${POSSIBLE_DIRS} のいずれにも存在しません")
endif()

if(CMAKE_MATCH_PATH "${CMAKE_BINARY_DIR}" "${POSSIBLE_DIRS}")
  message(STATUS "バイナリディレクトリは ${POSSIBLE_DIRS} のいずれかに存在します")
else()
  message(STATUS "バイナリディレクトリは ${POSSIBLE_DIRS} のいずれにも存在しません")
endif()

注意点

これらの代替方法は、CMP0139 ポリシーと同等の機能を提供しますが、それぞれ異なる利点と欠点があります。

  • CMAKE_MATCH_PATH マクロは、特定のディレクトリツリー内のパスを比較するのに適していますが、より複雑なパス比較には使用できません。
  • REALPATH マクロはシンボリックリンクを考慮することができますが、コードが煩雑になりがちです。
  • FILE_PATH_SAME 関数は最もシンプルですが、シンボリックリンクを考慮しないため、状況によっては誤った結果を返す可能性があります。