cmake:设置多个项目和它们之间的依赖关系

cmake: setup multiple projects and dependiencies between them

我需要帮助为 C++ 项目编写一个好的 CMakeLists.txt。

我寻找答案,但我找到了任何东西。 这是我的项目结构:

MainProj
|  ProjLib/
|  |  include/
|  |  |  proj_lib.h
|  |  src/
|  |  |  proj_lib.cc
|  |  CMakeLists.txt
|  ProjExec/
|  |  include/
|  |  |  proj_exec.h
|  |  src/
|  |  |  proj_exec.cc
|  |  CMakeLists.txt
|  CMakeLists.txt

主项目CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(MainProj CXX)

# enable C and C++ language
enable_language(C CXX)

# Add sub-directories
add_subdirectory(ProjLib)
add_subdirectory(ProjExec)

ProjLib CMakeLists.txt

set (PROJLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
set (PROJLIB_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)

set(PROJLIB_SRCS 
    ${CMAKE_CURRENT_SOURCE_DIR}/src/proj_lib.cc
)

include_directories("${PROJLIB_SOURCE_DIR}")
include_directories("${PROJLIB_INCLUDE_DIR}")

add_library(ProjLib SHARED ${PROJLIB_SRCS} ${PROJLIB_INCLUDE_DIR})

target_include_directories (ProjLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

ProjExec CMakeLists.txt

set (PROJEXEC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
set (PROJEXEC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)

set(PROJEXEC_SRCS 
    ${PROJEXEC_SOURCE_DIR}/proj_exec.cc
)

include_directories("${PROJEXEC_SOURCE_DIR}")
include_directories("${PROJEXEC_INCLUDE_DIR}")

add_executable(ProjExec ${PROJEXEC_SRCS})

target_link_libraries (ProjExec LINK_PUBLIC ProjLib)

proj_exec.cc

#include "proj_lib.h"
...

并且在 proj_exec.cc 文件中没有找到 proj_lib.h。 如果我需要在某些 cmake 中添加一些额外的条目?

如有任何帮助,我们将不胜感激。 :)

您的 cmake 项目模板看起来不错 self-contained。首先,我假设 GAITPARAMS_SRCS 应该是 PROJEXEC_SRCS 当前指向 proj_exec.cc 包含一个 main() 方法。 (如果你要管理一个 SRCS 列表,注意不要在列表的顶部添加源文件,add_executable 希望主要功能在第一个条目中)

其次,问题出在你的ProjLib/CMakeLists.txt。尝试用此替换您的 target_include_directories 调用:

target_include_directories (ProjLib PUBLIC ${PROJLIB_INCLUDE_DIR})

这将在应用 target_link_libraries 命令时将包含目录信息传播到 ProjExec。如果您不想这样做,我想您可以通过 #include <include/ProjLib.h> 访问,但这只会让人感到困惑。我的建议是在 include 文件夹中添加另一个文件夹(名称与 cmake 文件夹完全相同)并在其中添加您的 headers 。像这样:

MainProj
|  ProjLib/
|  |  include/
|  |  |  ProjLib/
|  |  |  |  proj_lib.h
|  |  src/
|  |  |  proj_lib.cc
|  |  CMakeLists.txt

这使您可以将 headers 包含在文件夹名称中(更不用说防止名称冲突了。)。像这样:

#include <ProjLib/proj_lib.h>

并配置您的 CMakeLists.txt 文件以匹配模式。

以下所有内容均有效,但最佳选项在 中有解释。


您至少有 3 个选项:

1) 在ProjExec/CMakeLists.txt 中添加以下行:

 target_include_directories (ProjExec PUBLIC ${CMAKE_SOURCE_DIR}/ProjLib/include)

2) 您可以通过添加 CACHE INTERNAL 关键字

来扩展变量 PROJLIB_INCLUDE_DIR 的可见性
 set(PROJLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "")

然后在ProjExec/CMakeLists.txt中使用:

 target_include_directories (ProjExec PUBLIC ${PROJLIB_INCLUDE_DIR})

参见 How to set the global variable in a function for cmake?
当然,ProjLib 必须在主 CMakeLists.txt 文件的 add_subdirectory 序列中排在第一位。

3) 我无法测试这个。如果您在 ProjLib 的 CMakeLists.txt 中使用此行:

 target_include_directories (ProjLib PUBLIC ${PROJLIB_INCLUDE_DIR})

然后在 ProjExec 的 CMakeLists.txt 中你可以提取 属性 INTERFACE_INCLUDE_DIRECTORIES,并使用它:

 get_target_property(ProjLib PROJLIB_INCLUDE_DIR INTERFACE_INCLUDE_DIRECTORIES) #Do not use anymore CACHE INTERNAL (Point 2)
 target_include_directories (ProjExec PUBLIC ${PROJLIB_INCLUDE_DIR}) #or PRIVATE

这两行可以压缩成一行,使用cmake-generator-expressions(未测试):

target_include_directories (ProjExec PUBLIC $<TARGET_PROPERTY:ProjLib,INTERFACE_INCLUDE_DIRECTORIES>) #or PRIVATE

另见 target_include_directories and get_target_property


其他说明:

  • 使用 include_directoriestarget_include_directories,不能同时使用。
  • 您通常不需要将源目录作为包含目录,即您可以删除 include_directories("${PROJLIB_SOURCE_DIR}")include_directories("${PROJEXEC_SOURCE_DIR}")

您需要使用 CMake 目标及其属性:

MainProj/CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)
project(MainProj)

# Add sub-directories
add_subdirectory(ProjLib)
add_subdirectory(ProjExec)

ProjLib/CMakeLists.txt

add_library(ProjLib SHARED src/proj_lib.cc)
target_include_directories(ProjLib PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)

ProjExec/CMakeLists.txt

add_executable(ProjExec src/proj_exec.cc)
target_include_directories(ProjExec PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include)
target_link_libraries(ProjExec ProjLib)

target_link_libraries 确保在构建目标时,将正确使用其依赖项的 PUBLIC 和 INTERFACE 包含目录。