web-dev-qa-db-ja.com

CMake:外部プロジェクトを構築し、そのターゲットを含める方法

ターゲットとして静的ライブラリをエクスポートするプロジェクトAがあります。

install(TARGETS alib DESTINATION lib EXPORT project_a-targets)
install(EXPORT project_a-targets DESTINATION lib/alib)

次に、プロジェクトAをプロジェクトBの外部プロジェクトとして使用し、ビルドされたターゲットを含めます。

ExternalProject_Add(project_a
  URL ...project_a.tar.gz
  PREFIX ${CMAKE_CURRENT_BINARY_DIR}/project_a
  CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
)

include(${CMAKE_CURRENT_BINARY_DIR}/lib/project_a/project_a-targets.cmake)

問題は、プロジェクトBのCMakeListsを実行したときにインクルードファイルがまだ存在しないことです。

インクルードをビルド中の外部プロジェクトに依存させる方法はありますか?

Update:短い CMake by Example tutorial これに基づいて書いたそして私が遭遇した他の一般的な問題。

86
mirkokiefer

ここでは、2つの異なるパラダイムを混在させていると思います。

既に述べたように、非常に柔軟な ExternalProject モジュールはビルド時にコマンドを実行するため、プロジェクトAがインストールされた後にのみ作成されるため、プロジェクトAのインポートファイルを直接使用することはできません。

includeプロジェクトAのインポートファイルが必要な場合は、haveを使用して、プロジェクトBのCMakeLists.txtを呼び出す前にプロジェクトAを手動でインストールします。 -party依存関係は、この方法またはfind_file/find_library/find_packageを介して追加されました。

ExternalProject_Addを使用する場合は、次のようなものをCMakeLists.txtに追加する必要があります。

ExternalProject_Add(project_a
  URL ...project_a.tar.gz
  PREFIX ${CMAKE_CURRENT_BINARY_DIR}/project_a
  CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
)

include(${CMAKE_CURRENT_BINARY_DIR}/lib/project_a/project_a-targets.cmake)

ExternalProject_Get_Property(project_a install_dir)
include_directories(${install_dir}/include)

add_dependencies(project_b_exe project_a)
target_link_libraries(project_b_exe ${install_dir}/lib/alib.lib)
56
Fraser

この投稿 には合理的な答えがあります:

CMakeLists.txt.in

cmake_minimum_required(VERSION 2.8.2)

project(googletest-download NONE)

include(ExternalProject)
ExternalProject_Add(googletest
  GIT_REPOSITORY    https://github.com/google/googletest.git
  GIT_TAG           master
  SOURCE_DIR        "${CMAKE_BINARY_DIR}/googletest-src"
  BINARY_DIR        "${CMAKE_BINARY_DIR}/googletest-build"
  CONFIGURE_COMMAND ""
  BUILD_COMMAND     ""
  INSTALL_COMMAND   ""
  TEST_COMMAND      ""
)

CMakeLists.txt

# Download and unpack googletest at configure time
configure_file(CMakeLists.txt.in
               googletest-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
execute_process(COMMAND ${CMAKE_COMMAND} --build .
  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )

# Prevent GoogleTest from overriding our compiler/linker options
# when building with Visual Studio
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)

# Add googletest directly to our build. This adds
# the following targets: gtest, gtest_main, gmock
# and gmock_main
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
                 ${CMAKE_BINARY_DIR}/googletest-build)

# The gtest/gmock targets carry header search path
# dependencies automatically when using CMake 2.8.11 or
# later. Otherwise we have to add them here ourselves.
if (CMAKE_VERSION VERSION_LESS 2.8.11)
  include_directories("${gtest_SOURCE_DIR}/include"
                      "${gmock_SOURCE_DIR}/include")
endif()

# Now simply link your own targets against gtest, gmock,
# etc. as appropriate

しかし、それはかなりハックのように見えます。代替ソリューションを提案したいと思います-Gitサブモジュールを使用します。

cd MyProject/dependencies/gtest
git submodule add https://github.com/google/googletest.git
cd googletest
git checkout release-1.8.0
cd ../../..
git add *
git commit -m "Add googletest"

次に、MyProject/dependencies/gtest/CMakeList.txtで次のようなことができます。

cmake_minimum_required(VERSION 3.3)

if(TARGET gtest) # To avoid diamond dependencies; may not be necessary depending on you project.
    return()
endif()

add_subdirectory("googletest")

私はまだこれを広範囲に試したことはありませんが、よりきれいに見えます。

編集:このアプローチには欠点があります。サブディレクトリは、不要なinstall()コマンドを実行する可能性があります。 この投稿にはそれらを無効にするアプローチがあります しかしバグがあり、私にとってはうまくいきませんでした。

編集2:add_subdirectory("googletest" EXCLUDE_FROM_ALL)を使用する場合、サブディレクトリ内のinstall()コマンドはデフォルトでは使用されないようです。

17
Timmmm

セカンダリメイクプロセスで依存ターゲットのビルドを強制することもできます

関連トピックの my answer を参照してください。

4
David

試すことができるのは、project_a内でcmakeの export コマンドを使用することです。 cmakeの実行時にEXPORT optionファイルを生成するという点で、project_a-targets.cmakeとともにinstallコマンドを使用した場合と少し異なります。 project_a-targets.cmakeファイル内で生成されたインポートターゲットは、ビルドコマンドを実行した後にのみ生成されるプロジェクトのバイナリディレクトリ内の既存のライブラリファイルを最初に指しません。

私が話していることをよりよく理解するには、単純なライブラリを作成する小さなcmakeプロジェクトを作成し、その後にエクスポートコマンドを続けます(以下のコードはテストされていません)。

add_library (project_a lib.cpp)
export (
  TARGETS 
    project_a
  FILE
    project_a-targets.cmake
)

単純な例でcmakeコマンドを実行すると、バイナリディレクトリ内(またはその子フォルダーのいずれか)でproject_a-targets.cmakeを見つけることができるはずです。ファイルを調べると、現在存在しないライブラリファイルを指していることがわかります。ビルドコマンドを実行した後にのみ、ライブラリが存在します。

問題に戻ると、project-aCMakeLists.txtを更新してexportコマンドを含める必要があります。次に、ExternalProject_Addが処理された後、project_a-targets.cmakeを生成する構成ステップを呼び出してから、動作するinclude(.../project_a-targets.cmake)を呼び出すことができることを確認する必要があります。最後に、project_bproject_aの間に依存関係を追加して、project_aをビルドする前にproject_bを強制的にビルドする必要があります。

0