将CMake子项目与另一个子项目集成

Integrate CMake subproject with another

本文关键字:子项目 集成 另一个 CMake      更新时间:2023-10-16

我已经编写了一个C++库MyLib,我想将它与另一个项目ExternPro集成。所以在ExternPro中,我这样写CMakeLists.txt

add_subdirectory(MyLib)
ADD_EXECUTABLE(test test.cpp)
include_directories(${MyLib_INCLUDE_DIRS})
target_link_libraries(test ${MyLib_LIBRARIES})

为了设置变量MyLib_LIBRARIESMyLib_INCLUDE_DIRS,我写道:

set(MyLib_LIBRARIES ${PROJECT_SOURCE_DIR}/src/MyLib.a CACHE INTERNAL "")
set(MyLib_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/include CACHE INTERNAL "")

但有些错误"没有规则使目标MyLib/src/MyLib.a,测试需要。停止。"

所以我的问题是,我应该如何正确地编写CMakeLists.txt,以便cmake可以帮助我首先构建MyLib,然后处理ExternPro的依赖关系?

如果这是两个独立的项目,我通常使用"CMake find scripts"从另一个库引用一个库:http://www.vtk.org/Wiki/CMake:How_To_Find_Libraries#Writing_find_modules

但我通常使用与上面描述的略有不同的find脚本(FindMyLibrary.cmake):

# Find MyLibrary installation
#
# This module needs following variables specified (e.g. through cmake -Dvar=)
#  MyLibrary_ROOT_DIR         - root directory of the library installation
#
# This module defines the following variables:
#  MyLibrary_INCLUDE_DIRS     - Where to find the public headers
#  MyLibrary_LIBRARIES        - List of mandatory and optional libraries
#  MyLibrary_FOUND            - True if an installation was found
#
# Configuration variables for tis module:
#  MyLibrary_USE_STATIC_LIBS  - Set to ON to force the use of the static
#                               libraries. Default is OFF.
# If MyLibrary_ROOT_DIR was defined in the environment, use it.
if(NOT MyLibrary_ROOT_DIR AND NOT $ENV{MyLibrary_ROOT_DIR} STREQUAL "")
  set(MyLibrary_ROOT_DIR $ENV{MyLibrary_ROOT_DIR})
endif()
if(NOT MyLibrary_ROOT_DIR)
    set(MyLibrary_ROOT_DIR /usr)
endif()
message(STATUS "Using MyLibrary_ROOT_DIR: ${MyLibrary_ROOT_DIR}")
find_path(MyLibrary_INCLUDE_DIRS
          NAMES mylib/mylib.hpp
          PATHS ${MyLibrary_ROOT_DIR}
          PATH_SUFFIXES include)
# Here we set the default components
if(NOT MyLibrary_FIND_COMPONENTS)
  set(MyLibrary_FIND_COMPONENTS mylibrary)
endif()
# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
if(MyLibrary_USE_STATIC_LIBS)
  set(_mylib_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
  if(WIN32)
    set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
  else()
    set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
  endif()
endif()
foreach(COMPONENT ${MyLibrary_FIND_COMPONENTS})
    find_library(MyLibrary_${COMPONENT}_LIBRARY
                 NAMES ${COMPONENT}
                 HINTS ${MyLibrary_ROOT_DIR}
                 PATH_SUFFIXES lib64 lib
                 NO_DEFAULT_PATH)
    set(MyLibrary_LIBRARIES ${MyLibrary_LIBRARIES} ${MyLibrary_${COMPONENT}_LIBRARY})
endforeach()
# Restore the original find library ordering
if(MyLibrary_USE_STATIC_LIBS)
  set(CMAKE_FIND_LIBRARY_SUFFIXES ${_mylib_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
endif()
# handle the QUIETLY and REQUIRED arguments and set MyLibrary_FOUND to
# TRUE if all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
        MyLibrary "Could NOT find MyLibrary: set MyLibrary_ROOT_DIR to a proper location"
        MyLibrary_LIBRARIES
        MyLibrary_INCLUDE_DIRS)
mark_as_advanced(MyLibrary_INCLUDE_DIRS MyLibrary_LIBRARIES)

然后这样使用:

find_package(MyLibrary REQUIRED)
include_directories(SYSTEM ${MyLibrary_INCLUDE_DIRS})
target_link_libraries(${TARGET}
    ${MyLibrary_LIBRARIES}
)

基本上是这样的:

  1. 库被构建并安装(makeinstall)到默认位置(例如/usr)或其他位置(通常在开发中)
  2. FindMyLibrary.cmake是库安装的一部分(对于RPM,为library-devel包),也会安装(例如,安装到${instdir}/share/cmake/Modules中)
  3. 然后,依赖项目将路径添加到CMAKE_MODULE_path,并使用查找脚本查找已安装的公共标头和库

这样做的好处是,您既可以在开发过程中使用它(当您拥有库源代码并构建库时),也可以不使用库源代码(只在系统中安装库和头文件-devel包)。

Boost等通常使用类似的技术(查找脚本已经由CMake提供)。

对于target_link_libraries,使用库目标而不是库的路径。

假设您的图书馆项目包含

add_library(MyLib ...)

主项目中可执行文件的链接应使用进行

target_link_libraries(test MyLib)

首先,这不起作用,因为在子目录中设置的变量不是为父目录设置的。

因此,为了正确解决这个问题,你应该定义MyLib,比如:

add_library(MyLib ...)
target_include_directories(MyLib INTERFACE ${PROJECT_SOURCE_DIR}/include)

对于ExternP,您只需要链接到MyLib:

target_link_libraries(test MyLib)

这将自动将include目录添加到test并正确链接MyLib。