CMake: インポートされたターゲットがシステム ライブラリではないことを示す IMPORTED_NO_SYSTEM プロパティ

2024-06-09

CMake の "Properties: Targets" における "IMPORTED_NO_SYSTEM" の詳細解説

"IMPORTED_NO_SYSTEM" は、CMake の "Properties: Targets" におけるターゲット プロパティであり、インポートされたターゲットがシステム ライブラリではないことを示します。これは、CMake がターゲットのインクルード ディレクトリを処理する方法に影響を与えます。

影響

"IMPORTED_NO_SYSTEM" プロパティを設定すると、以下の影響が発生します。

  • インクルード ディレクトリの処理:

    • インポートされたターゲットの INTERFACE_INCLUDE_DIRECTORIES プロパティで指定されたインクルード ディレクトリは、デフォルトではシステム インクルード ディレクトリとして扱われます。しかし、IMPORTED_NO_SYSTEM プロパティが設定されている場合、これらのインクルード ディレクトリはシステム インクルード ディレクトリとして扱われなくなります。
    • INTERFACE_SYSTEM_INCLUDE_DIRECTORIES プロパティで指定されたインクルード ディレクトリは、IMPORTED_NO_SYSTEM プロパティの影響を受けません。これらのインクルード ディレクトリは常にシステム インクルード ディレクトリとして扱われます。
  • install(EXPORT) コマンドと export() コマンド:

    • IMPORTED_NO_SYSTEM プロパティが設定されているインポートされたターゲットを install(EXPORT) コマンドまたは export() コマンドでエクスポートする場合、エクスポートされたターゲットも IMPORTED_NO_SYSTEM プロパティが設定されます。

補足

  • IMPORTED_NO_SYSTEM プロパティは、インポートされたターゲットだけでなく、非インポートされたターゲットにも設定できます。ただし、非インポートされたターゲットにこのプロパティを設定しても、ビルドシステムには影響しません。影響を受けるのは、install(EXPORT) コマンドまたは export() コマンドでエクスポートされたターゲットのみです。
  • NO_SYSTEM_FROM_IMPORTED ターゲット プロパティを使用すると、インポートされたターゲットのインクルード ディレクトリをシステム インクルード ディレクトリとして扱うかどうかを、ターゲットを消費する側で制御できます。

# インポートされたターゲットに IMPORTED_NO_SYSTEM プロパティを設定する
target_properties(importedTarget PROPERTIES IMPORTED_NO_SYSTEM TRUE)

# インポートされたターゲットをエクスポートする
install(EXPORT MyTargets TARGETS importedTarget)

この例では、importedTarget というインポートされたターゲットに IMPORTED_NO_SYSTEM プロパティが設定され、MyTargets という名前でエクスポートされます。MyTargets を消費するターゲットは、importedTarget のインクルード ディレクトリをシステム インクルード ディレクトリとして扱いません。

    "IMPORTED_NO_SYSTEM" プロパティは、CMake における重要なターゲット プロパティであり、インポートされたターゲットがシステム ライブラリではないことを示すために使用されます。このプロパティは、インクルード ディレクトリの処理方法や、install(EXPORT) コマンドと export() コマンドの動作に影響を与えます。



    # ライブラリ "importedLib" をインポートする
    find_package(importedLib REQUIRED)
    
    # インポートされたターゲット "importedTarget" に IMPORTED_NO_SYSTEM プロパティを設定する
    target_properties(importedTarget PROPERTIES IMPORTED_NO_SYSTEM TRUE)
    
    # ターゲット "myApp" をビルドする
    add_executable(myApp main.cpp)
    target_link_libraries(myApp importedLib)
    

    この例では、importedLib というライブラリがインポートされ、そのインポートされたターゲット importedTargetIMPORTED_NO_SYSTEM プロパティが設定されます。その後、myApp というターゲットがビルドされ、importedLib にリンクされます。

    例2: IMPORTED_NO_SYSTEM プロパティと NO_SYSTEM_FROM_IMPORTED ターゲット プロパティ

    # ライブラリ "importedLib" をインポートする
    find_package(importedLib REQUIRED)
    
    # インポートされたターゲット "importedTarget" に IMPORTED_NO_SYSTEM プロパティを設定する
    target_properties(importedTarget PROPERTIES IMPORTED_NO_SYSTEM TRUE)
    
    # ターゲット "myApp" をビルドする
    add_executable(myApp main.cpp)
    target_link_libraries(myApp importedLib)
    
    # ターゲット "myOtherApp" をビルドする
    add_executable(myOtherApp otherMain.cpp)
    target_link_libraries(myOtherApp importedLib)
    
    # ターゲット "myOtherApp" が "importedTarget" のインクルード ディレクトリをシステム インクルード ディレクトリとして扱わないようにする
    target_properties(myOtherApp PROPERTIES NO_SYSTEM_FROM_IMPORTED TRUE)
    

    この例では、importedLib というライブラリがインポートされ、そのインポートされたターゲット importedTargetIMPORTED_NO_SYSTEM プロパティが設定されます。その後、myAppmyOtherApp というターゲットがビルドされ、importedLib にリンクされます。myOtherApp ターゲットには NO_SYSTEM_FROM_IMPORTED プロパティが設定されているため、importedTarget のインクルード ディレクトリはシステム インクルード ディレクトリとして扱われなくなります。

    補足

    これらの例はあくまでもサンプルであり、実際の使用状況に合わせて調整する必要があります。



      以下に、"IMPORTED_NO_SYSTEM" の代替方法として検討すべきいくつかの方法をご紹介します。

      インクルード ディレクトリを明示的に指定する

      "IMPORTED_NO_SYSTEM" プロパティを使用する代わりに、インポートされたターゲットのインクルード ディレクトリを INTERFACE_INCLUDE_DIRECTORIES ターゲット プロパティを使用して明示的に指定することができます。

      # ライブラリ "importedLib" をインポートする
      find_package(importedLib REQUIRED)
      
      # インポートされたターゲット "importedTarget" のインクルード ディレクトリを指定する
      target_properties(importedTarget PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${importedLib_INCLUDE_DIRS}")
      
      # ターゲット "myApp" をビルドする
      add_executable(myApp main.cpp)
      target_link_libraries(myApp importedLib)
      

      この例では、importedLib ライブラリがインポートされ、そのインポートされたターゲット importedTarget のインクルード ディレクトリが importedLib_INCLUDE_DIRS 変数を使用して明示的に指定されます。

      NO_SYSTEM_FROM_IMPORTED ターゲット プロパティを使用する

      インポートされたターゲットのインクルード ディレクトリをシステム インクルード ディレクトリとして扱うかどうかを、ターゲットを消費する側で制御したい場合は、NO_SYSTEM_FROM_IMPORTED ターゲット プロパティを使用することができます。

      # ライブラリ "importedLib" をインポートする
      find_package(importedLib REQUIRED)
      
      # インポートされたターゲット "importedTarget" に IMPORTED_NO_SYSTEM プロパティを設定する
      target_properties(importedTarget PROPERTIES IMPORTED_NO_SYSTEM TRUE)
      
      # ターゲット "myApp" をビルドする
      add_executable(myApp main.cpp)
      target_link_libraries(myApp importedLib)
      
      # ターゲット "myOtherApp" をビルドする
      add_executable(myOtherApp otherMain.cpp)
      target_link_libraries(myOtherApp importedLib)
      
      # ターゲット "myOtherApp" が "importedTarget" のインクルード ディレクトリをシステム インクルード ディレクトリとして扱わないようにする
      target_properties(myOtherApp PROPERTIES NO_SYSTEM_FROM_IMPORTED TRUE)
      

      この例では、importedLib ライブラリがインポートされ、そのインポートされたターゲット importedTargetIMPORTED_NO_SYSTEM プロパティが設定されます。その後、myAppmyOtherApp というターゲットがビルドされ、importedLib にリンクされます。myOtherApp ターゲットには NO_SYSTEM_FROM_IMPORTED プロパティが設定されているため、importedTarget のインクルード ディレクトリはシステム インクルード ディレクトリとして扱われなくなります。

      カスタム CMake モジュールを使用する

      より複雑なケースでは、カスタム CMake モジュールを使用して、インポートされたターゲットのインクルード ディレクトリ処理を制御することができます。

      CMake バージョンをアップグレードする

      CMake の新しいバージョンでは、"IMPORTED_NO_SYSTEM" プロパティの代替となる新しい機能が導入されている場合があります。CMake の最新バージョンを使用していることを確認してください。

      補足

      上記の代替方法はそれぞれ長所と短所があります。最適な方法は、具体的な状況によって異なります。