CMake ExternalProject:如何指定根目录 CMakeLists.txt 的相对路径?
CMake ExternalProject: how to specify relative path to the root CMakeLists.txt?
似乎 CMake ExternalProject
总是假定根目录
外部项目的源目录。但如果那不是呢
案子?
考虑以下示例:
外部项目使用此目录布局:
libfoo.git <--- ExternalProject assumes this as source dir.
├── ...
└── libfoo <--- However, the actual source directory is this!
├── CMakeLists.txt
└── ...
在依赖项目中libfoo
配置如下:
ExternalProject_Add( libfoo
PREFIX "${CMAKE_CURRENT_BINARY_DIR}/EP_libfoo"
GIT_REPOSITORY "<link to remote which hosts libfoo.git>"
GIT_TAG "<some hash>"
)
然后构建失败并显示以下错误消息:
$ cmake -H/path/to/source-dir -B/path/to/build-dir
...
$ cmake --build /path/to/build-dir/ --target all
...
CMake Error: The source directory "/path/to/build-dir/EP_libfoo/src/libfoo" does not appear to contain CMakeLists.txt.
...
$
因此,正如上面目录布局中指出的那样,CMake 认为根
外部项目是
/path/to/build-dir/EP_libfoo/src/libfoo
实际上是
/path/to/build-dir/EP_libfoo/src/libfoo/libfoo
我解决这个问题的尝试:
不幸的是,更改 ExternalProject
的参数 SOURCE_DIR
确实
不起作用,因为此变量的值用作
libfoo
的 git 存储库被克隆到其中。这导致无法打破的递归依赖地狱。
正在更改 libfoo
的目录布局以符合 ExternalProject
。
显然,这可行,但可能不适用于其他(只读)
第三方库。
滥用 ExternalProject
的 update/patch 步骤,例如通过指定
set( EP_LIBFOO_DIR "${CMAKE_CURRENT_BINARY_DIR}/EP_libfoo" )
ExternalProject_Add( libfoo
PREFIX "${EP_LIBFOO_DIR}"
GIT_REPOSITORY "<link to remote which hosts libfoo.git>"
GIT_TAG "<some hash>"
# Copy the content of `<...>/libfoo/libfoo` into `<...>/libfoo`.
# Note to self: using symlinks instead copying is too platform-specific.
PATCH_COMMAND ${CMAKE_COMMAND} -E copy_directory "${EP_LIBFOO_DIR}/src/libfoo/libfoo" "${EP_LIBFOO_DIR}/src/libfoo"
)
这行得通,但它很老套,而且很容易与其他外部项目一起失败。
建立在solution to another problem:添加一个临时
CMakeLists.txt
在 CMake 假定的位置。这个临时文件
然后包括实际的 CMakeLists.txt
:
set( EP_LIBFOO_DIR "${CMAKE_CURRENT_BINARY_DIR}/EP_libfoo" )
set( GENERATED_DIR "${CMAKE_BINARY_DIR}/generated" )
file( MAKE_DIRECTORY ${GENERATED_DIR} )
file( WRITE ${GENERATED_DIR}/CMakeLists.txt
"cmake_minimum_required( VERSION 3.0 )\n"
"add_subdirectory( libfoo )\n"
)
ExternalProject_Add( libfoo
PREFIX "${EP_LIBFOO_DIR}"
GIT_REPOSITORY "<link to remote which hosts libfoo.git>"
GIT_TAG "<some hash>"
# Copy the
UPDATE_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/generated/CMakeLists.txt ${EP_LIBFOO_DIR}/src/libfoo
)
这也比以前的解决方案更有效,感觉更好。
但是,是否存在 更优雅 来做同样的事情?
您可以使用
SOURCE_DIR /path/to/build-dir/EP_libfoo/src/libfoo/libfoo
ExternalProject_Add来电。这指定了实际的源目录。
我一直在努力解决我正在处理的项目中的相同问题,这是我能够提出的解决方案。它导致不使用 ExternalProject 进行 git 处理,但据我所知导致相同的行为。
CMakeLists.txt
include(ExternalProject)
set(libfoo_prefix ${CMAKE_HOME_DIRECTORY}/libfoo)
# during generation remove any previous repo and clone.
file(REMOVE_RECURSE ${libfoo_prefix})
execute_process(
COMMAND git clone <link to remote which hosts libfoo.git>
WORKING_DIRECTORY ${CMAKE_HOME_DIRECTORY})
# Add the external project.
ExternalProject_Add(libfoo
PREFIX ${libfoo_prefix}
SOURCE_DIR ${libfoo_prefix}/libfoo)
# As part of the pre-build step update the git repo.
add_custom_command(
TARGET libfoo
PRE_BUILD
COMMAND ${CMAKE_COMMAND} -P GitPull.cmake)
GitPull.cmake
execute_process(
COMMAND git pull origin master
WORKING_DIRECTORY ${CMAKE_SOURCE_DIRECTORY}/libfoo)
这是一个简单的解决方案
set(EXTERNAL_PROJECTS "")
set(EXTERNAL_LIBS "")
include(ExternalProject)
# Set compiler(s) per project as required to CMAKE_ARGS in ExternalProject_Add(..).
# -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
# -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
set(EXTERNAL_CMAKE_ARGS -D CMAKE_SYSROOT=${CMAKE_SYSROOT}
-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=${CMAKE_FIND_ROOT_PATH_MODE_PROGRAM}
-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=${CMAKE_FIND_ROOT_PATH_MODE_LIBRARY}
-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=${CMAKE_FIND_ROOT_PATH_MODE_INCLUDE}
-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}
)
set(AIOUSB aiousb)
set(AIOUSB_SRC aiousb_src)
set(EXTERNAL_PROJECTS ${EXTERNAL_PROJECTS} ${AIOUSB_SRC} ${AIOUSB})
set(AIOUSB_SRC_GIT_BRANCH "master")
ExternalProject_Add(${AIOUSB_SRC}
PREFIX ${AIOUSB_SRC}
GIT_REPOSITORY "https://github.com/accesio/AIOUSB.git"
GIT_TAG ${AIOUSB_SRC_GIT_BRANCH}
UPDATE_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
BUILD_BYPRODUCTS ${CMAKE_BINARY_DIR}/${AIOUSB_SRC}/src/${AIOUSB_SRC}/AIOUSB/CMakeLists.txt
INSTALL_COMMAND ""
)
set(AIOUSB_LIBRARY ${CMAKE_BINARY_DIR}/${AIOUSB}/src/${AIOUSB}-build/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${AIOUSB}${CMAKE_STATIC_LIBRARY_SUFFIX})
set(AIOUSBCPP_LIBRARY ${CMAKE_BINARY_DIR}/${AIOUSB}/src/${AIOUSB}-build/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${AIOUSB}cpp${CMAKE_STATIC_LIBRARY_SUFFIX})
ExternalProject_Add(${AIOUSB}
DEPENDS ${AIOUSB_SRC}
PREFIX ${AIOUSB}
DOWNLOAD_COMMAND ""
SOURCE_DIR ${CMAKE_BINARY_DIR}/${AIOUSB_SRC}/src/${AIOUSB_SRC}/AIOUSB
CMAKE_ARGS ${EXTERNAL_CMAKE_ARGS} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DBUILD_SAMPLES:BOOL=OFF -DBUILD_AIOUSB_SHARED:BOOL=OFF -DBUILD_AIOUSBDBG_SHARED:BOOL=OFF -DBUILD_AIOUSBCPP_SHARED:BOOL=OFF
-DBUILD_AIOUSBCPPDBG_SHARED:BOOL=OFF
BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/src/lib/include/${AIOUSB} ${CMAKE_BINARY_DIR}/${AIOUSB}/src/${AIOUSB}-build/lib/libaiousb.a
${CMAKE_BINARY_DIR}/${AIOUSB}/src/${AIOUSB}-build/lib/libaiousbcpp.a
INSTALL_COMMAND rm -rf ${CMAKE_SOURCE_DIR}/src/lib/include/${AIOUSB} && mkdir -p ${CMAKE_SOURCE_DIR}/src/lib/include/${AIOUSB} &&
echo "ln -sr ${CMAKE_BINARY_DIR}/${AIOUSB_SRC}/src/${AIOUSB_SRC}/AIOUSB/lib/*.h ${CMAKE_SOURCE_DIR}/src/lib/include/${AIOUSB}" | bash
)
set(LIBAIOUSB libaiousb)
add_library(${LIBAIOUSB} STATIC IMPORTED)
set_property(TARGET ${LIBAIOUSB} PROPERTY IMPORTED_LOCATION ${AIOUSB_LIBRARY})
add_dependencies(${LIBAIOUSB} ${AIOUSB})
set(EXTERNAL_LIBS ${EXTERNAL_LIBS} ${LIBAIOUSB})
set(LIBAIOUSBCPP libaiousbcpp)
add_library(${LIBAIOUSBCPP} STATIC IMPORTED)
set_property(TARGET ${LIBAIOUSBCPP} PROPERTY IMPORTED_LOCATION ${AIOUSBCPP_LIBRARY})
add_dependencies(${LIBAIOUSBCPP} ${AIOUSB})
set(EXTERNAL_LIBS ${EXTERNAL_LIBS} ${LIBAIOUSBCPP})
...
add_dependencies(${PROJECT_NAME} ${EXTERNAL_PROJECTS})
...
also add
target_link_libraries(${PROJECT_NAME} ${EXTERNAL_LIBS} ...)
基本上你把它分成两部分。第一个只是为了获取源代码,第二个是构建软件。我手动创建指向 headers 的链接,因此 kdevelop 的解析器不必解析整个项目。
我已提交 a merge request 添加一个 SOURCE_SUBDIR
选项到 ExternalProject_Add
来解决这个用例。希望它将在 CMake 3.7 中可用。 (您也可以将 ExternalProject*.cmake
本地复制到您自己的项目中以立即利用该功能。)
对于那些仍在寻找答案的人:尝试指定 CONFIGURE_COMMAND
:
ExternalProject_Add(libfoo
GIT_REPOSITORY "<link to remote which hosts libfoo.git>"
GIT_TAG "<some hash>"
SOURCE_DIR "where to put the source"
CONFIGURE_COMMAND
"${CMAKE_COMMAND}"
"-HPathToDirectoryWhereTheCMakeListsAre"
"-BWhereToBuild"
BUILD_COMMAND
"${CMAKE_COMMAND}" --build "Path to the directory where you are building (specified with -B flag in CONFIGURE_COMMAND)"
)
您可以简单地将 cmake 命令蚂蚁设置路径手动覆盖到 CMakeLists.txt。例如
ExternalProject_Add(libfoo
PREFIX "${EP_LIBFOO_DIR}"
GIT_REPOSITORY "<link to remote which hosts libfoo.git>"
GIT_TAG "<some hash>"
CONFIGURE_COMMAND ${CMAKE_COMMAND} -G${CMAKE_GENERATOR} "${EP_LIBFOO_DIR}/src/libfoo/libfoo")
似乎 CMake ExternalProject
总是假定根目录
外部项目的源目录。但如果那不是呢
案子?
考虑以下示例:
外部项目使用此目录布局:
libfoo.git <--- ExternalProject assumes this as source dir.
├── ...
└── libfoo <--- However, the actual source directory is this!
├── CMakeLists.txt
└── ...
在依赖项目中libfoo
配置如下:
ExternalProject_Add( libfoo
PREFIX "${CMAKE_CURRENT_BINARY_DIR}/EP_libfoo"
GIT_REPOSITORY "<link to remote which hosts libfoo.git>"
GIT_TAG "<some hash>"
)
然后构建失败并显示以下错误消息:
$ cmake -H/path/to/source-dir -B/path/to/build-dir
...
$ cmake --build /path/to/build-dir/ --target all
...
CMake Error: The source directory "/path/to/build-dir/EP_libfoo/src/libfoo" does not appear to contain CMakeLists.txt.
...
$
因此,正如上面目录布局中指出的那样,CMake 认为根 外部项目是
/path/to/build-dir/EP_libfoo/src/libfoo
实际上是
/path/to/build-dir/EP_libfoo/src/libfoo/libfoo
我解决这个问题的尝试:
不幸的是,更改
ExternalProject
的参数SOURCE_DIR
确实 不起作用,因为此变量的值用作libfoo
的 git 存储库被克隆到其中。这导致无法打破的递归依赖地狱。正在更改
libfoo
的目录布局以符合ExternalProject
。 显然,这可行,但可能不适用于其他(只读) 第三方库。滥用
ExternalProject
的 update/patch 步骤,例如通过指定set( EP_LIBFOO_DIR "${CMAKE_CURRENT_BINARY_DIR}/EP_libfoo" ) ExternalProject_Add( libfoo PREFIX "${EP_LIBFOO_DIR}" GIT_REPOSITORY "<link to remote which hosts libfoo.git>" GIT_TAG "<some hash>" # Copy the content of `<...>/libfoo/libfoo` into `<...>/libfoo`. # Note to self: using symlinks instead copying is too platform-specific. PATCH_COMMAND ${CMAKE_COMMAND} -E copy_directory "${EP_LIBFOO_DIR}/src/libfoo/libfoo" "${EP_LIBFOO_DIR}/src/libfoo" )
这行得通,但它很老套,而且很容易与其他外部项目一起失败。
建立在solution to another problem:添加一个临时
CMakeLists.txt
在 CMake 假定的位置。这个临时文件 然后包括实际的CMakeLists.txt
:set( EP_LIBFOO_DIR "${CMAKE_CURRENT_BINARY_DIR}/EP_libfoo" ) set( GENERATED_DIR "${CMAKE_BINARY_DIR}/generated" ) file( MAKE_DIRECTORY ${GENERATED_DIR} ) file( WRITE ${GENERATED_DIR}/CMakeLists.txt "cmake_minimum_required( VERSION 3.0 )\n" "add_subdirectory( libfoo )\n" ) ExternalProject_Add( libfoo PREFIX "${EP_LIBFOO_DIR}" GIT_REPOSITORY "<link to remote which hosts libfoo.git>" GIT_TAG "<some hash>" # Copy the UPDATE_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/generated/CMakeLists.txt ${EP_LIBFOO_DIR}/src/libfoo )
这也比以前的解决方案更有效,感觉更好。
但是,是否存在 更优雅 来做同样的事情?
您可以使用
SOURCE_DIR /path/to/build-dir/EP_libfoo/src/libfoo/libfoo
ExternalProject_Add来电。这指定了实际的源目录。
我一直在努力解决我正在处理的项目中的相同问题,这是我能够提出的解决方案。它导致不使用 ExternalProject 进行 git 处理,但据我所知导致相同的行为。
CMakeLists.txt
include(ExternalProject)
set(libfoo_prefix ${CMAKE_HOME_DIRECTORY}/libfoo)
# during generation remove any previous repo and clone.
file(REMOVE_RECURSE ${libfoo_prefix})
execute_process(
COMMAND git clone <link to remote which hosts libfoo.git>
WORKING_DIRECTORY ${CMAKE_HOME_DIRECTORY})
# Add the external project.
ExternalProject_Add(libfoo
PREFIX ${libfoo_prefix}
SOURCE_DIR ${libfoo_prefix}/libfoo)
# As part of the pre-build step update the git repo.
add_custom_command(
TARGET libfoo
PRE_BUILD
COMMAND ${CMAKE_COMMAND} -P GitPull.cmake)
GitPull.cmake
execute_process(
COMMAND git pull origin master
WORKING_DIRECTORY ${CMAKE_SOURCE_DIRECTORY}/libfoo)
这是一个简单的解决方案
set(EXTERNAL_PROJECTS "")
set(EXTERNAL_LIBS "")
include(ExternalProject)
# Set compiler(s) per project as required to CMAKE_ARGS in ExternalProject_Add(..).
# -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
# -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
set(EXTERNAL_CMAKE_ARGS -D CMAKE_SYSROOT=${CMAKE_SYSROOT}
-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=${CMAKE_FIND_ROOT_PATH_MODE_PROGRAM}
-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=${CMAKE_FIND_ROOT_PATH_MODE_LIBRARY}
-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=${CMAKE_FIND_ROOT_PATH_MODE_INCLUDE}
-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}
)
set(AIOUSB aiousb)
set(AIOUSB_SRC aiousb_src)
set(EXTERNAL_PROJECTS ${EXTERNAL_PROJECTS} ${AIOUSB_SRC} ${AIOUSB})
set(AIOUSB_SRC_GIT_BRANCH "master")
ExternalProject_Add(${AIOUSB_SRC}
PREFIX ${AIOUSB_SRC}
GIT_REPOSITORY "https://github.com/accesio/AIOUSB.git"
GIT_TAG ${AIOUSB_SRC_GIT_BRANCH}
UPDATE_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
BUILD_BYPRODUCTS ${CMAKE_BINARY_DIR}/${AIOUSB_SRC}/src/${AIOUSB_SRC}/AIOUSB/CMakeLists.txt
INSTALL_COMMAND ""
)
set(AIOUSB_LIBRARY ${CMAKE_BINARY_DIR}/${AIOUSB}/src/${AIOUSB}-build/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${AIOUSB}${CMAKE_STATIC_LIBRARY_SUFFIX})
set(AIOUSBCPP_LIBRARY ${CMAKE_BINARY_DIR}/${AIOUSB}/src/${AIOUSB}-build/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${AIOUSB}cpp${CMAKE_STATIC_LIBRARY_SUFFIX})
ExternalProject_Add(${AIOUSB}
DEPENDS ${AIOUSB_SRC}
PREFIX ${AIOUSB}
DOWNLOAD_COMMAND ""
SOURCE_DIR ${CMAKE_BINARY_DIR}/${AIOUSB_SRC}/src/${AIOUSB_SRC}/AIOUSB
CMAKE_ARGS ${EXTERNAL_CMAKE_ARGS} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DBUILD_SAMPLES:BOOL=OFF -DBUILD_AIOUSB_SHARED:BOOL=OFF -DBUILD_AIOUSBDBG_SHARED:BOOL=OFF -DBUILD_AIOUSBCPP_SHARED:BOOL=OFF
-DBUILD_AIOUSBCPPDBG_SHARED:BOOL=OFF
BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/src/lib/include/${AIOUSB} ${CMAKE_BINARY_DIR}/${AIOUSB}/src/${AIOUSB}-build/lib/libaiousb.a
${CMAKE_BINARY_DIR}/${AIOUSB}/src/${AIOUSB}-build/lib/libaiousbcpp.a
INSTALL_COMMAND rm -rf ${CMAKE_SOURCE_DIR}/src/lib/include/${AIOUSB} && mkdir -p ${CMAKE_SOURCE_DIR}/src/lib/include/${AIOUSB} &&
echo "ln -sr ${CMAKE_BINARY_DIR}/${AIOUSB_SRC}/src/${AIOUSB_SRC}/AIOUSB/lib/*.h ${CMAKE_SOURCE_DIR}/src/lib/include/${AIOUSB}" | bash
)
set(LIBAIOUSB libaiousb)
add_library(${LIBAIOUSB} STATIC IMPORTED)
set_property(TARGET ${LIBAIOUSB} PROPERTY IMPORTED_LOCATION ${AIOUSB_LIBRARY})
add_dependencies(${LIBAIOUSB} ${AIOUSB})
set(EXTERNAL_LIBS ${EXTERNAL_LIBS} ${LIBAIOUSB})
set(LIBAIOUSBCPP libaiousbcpp)
add_library(${LIBAIOUSBCPP} STATIC IMPORTED)
set_property(TARGET ${LIBAIOUSBCPP} PROPERTY IMPORTED_LOCATION ${AIOUSBCPP_LIBRARY})
add_dependencies(${LIBAIOUSBCPP} ${AIOUSB})
set(EXTERNAL_LIBS ${EXTERNAL_LIBS} ${LIBAIOUSBCPP})
...
add_dependencies(${PROJECT_NAME} ${EXTERNAL_PROJECTS})
...
also add
target_link_libraries(${PROJECT_NAME} ${EXTERNAL_LIBS} ...)
基本上你把它分成两部分。第一个只是为了获取源代码,第二个是构建软件。我手动创建指向 headers 的链接,因此 kdevelop 的解析器不必解析整个项目。
我已提交 a merge request 添加一个 SOURCE_SUBDIR
选项到 ExternalProject_Add
来解决这个用例。希望它将在 CMake 3.7 中可用。 (您也可以将 ExternalProject*.cmake
本地复制到您自己的项目中以立即利用该功能。)
对于那些仍在寻找答案的人:尝试指定 CONFIGURE_COMMAND
:
ExternalProject_Add(libfoo
GIT_REPOSITORY "<link to remote which hosts libfoo.git>"
GIT_TAG "<some hash>"
SOURCE_DIR "where to put the source"
CONFIGURE_COMMAND
"${CMAKE_COMMAND}"
"-HPathToDirectoryWhereTheCMakeListsAre"
"-BWhereToBuild"
BUILD_COMMAND
"${CMAKE_COMMAND}" --build "Path to the directory where you are building (specified with -B flag in CONFIGURE_COMMAND)"
)
您可以简单地将 cmake 命令蚂蚁设置路径手动覆盖到 CMakeLists.txt。例如
ExternalProject_Add(libfoo
PREFIX "${EP_LIBFOO_DIR}"
GIT_REPOSITORY "<link to remote which hosts libfoo.git>"
GIT_TAG "<some hash>"
CONFIGURE_COMMAND ${CMAKE_COMMAND} -G${CMAKE_GENERATOR} "${EP_LIBFOO_DIR}/src/libfoo/libfoo")