【问题标题】:cmake: setup multiple projects and dependiencies between themcmake:设置多个项目和它们之间的依赖关系
【发布时间】:2017-03-06 18:10:06
【问题描述】:

我需要帮助才能为 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

MainProj 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 中需要一些额外的条目?

任何帮助将不胜感激。 :)

【问题讨论】:

  • ProjExec/CMakeLists.txt 中包含目录ProjExec/srcProjExec/include。您的库目标带有包含目录(添加有target_include_directoriesProjLib,它被传播到可执行文件。但是这些目录都不等于ProjLib/include 标头proj_lib.h 所在的位置。那么,您为什么期望找到标头?

标签: c++ cmake multiple-projects


【解决方案1】:

您需要使用 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 包含目录。

【讨论】:

  • 有趣:所以OP只需要将ProjLib的CMakeLists.txt中的include_directories("${PROJLIB_INCLUDE_DIR}")改成target_include_directories (ProjLib PUBLIC ${PROJLIB_INCLUDE_DIR})?这种行为记录在哪里?
  • @Antonio:page on target_include_directories 谈论PUBLIC 填充the INTERFACE_INCLUDE_DIRECTORIES property,当您调用target_link_libraries 时使用:“当使用target_link_libraries() 指定目标依赖项时,CMake 将读取此内容来自所有目标依赖项的属性,以确定使用者的构建属性。”
  • 简而言之,如果您没有使用这些功能,那么您做错了。在非常有用的极端情况下仍然存在一些恕我直言的愚蠢限制,但我仍然认为 CMake 做得最好,即使它们的语法很糟糕。
  • 谢谢,藏得真好!确实,这是最好的方法!
  • 我已经添加了答案here
【解决方案2】:

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

其次,问题出在您的ProjLib/CMakeLists.txt。尝试用以下代码替换您的 target_include_directories 电话:

target_include_directories (ProjLib PUBLIC ${PROJLIB_INCLUDE_DIR})

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

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

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

#include <ProjLib/proj_lib.h>

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

【讨论】:

  • 因为找不到 ProjLib 的头文件而失败。它找不到 ProjLib 标头,因为 ProjLib 没有正确配置它的包含目录路径。我已经创建了文件夹结构并对其进行了测试。你也可以自己试试,很简单。
  • 我建议你通读我的回答。我已经给出了解决方案,然后是我的建议。就像我说的,你自己试试吧。
  • 这越来越荒谬了。我建议您在此处查看 target_include_directories 文档。 cmake.org/cmake/help/v3.0/command/… 。它在这里充当提示,作为将 ProjLib 链接到其中的其他目标的提示,并制作包含语句,而 ProjExec 不知道要包含什么。所以,这是 ProjLib 的问题。问题不是 ProjLib 的编译。它没有正确配置以帮助未来的目标包含它的标题。这就是该功能的目的。我再次建议您尝试一下。
  • 我现在有点明白你的意思了。如果您改写一下,这个答案可能会更清楚您正在尝试包含目录本身(具体在哪里?),cmake 无法解决链接到的位置(我们是在谈论链接还是包含?)。
  • 对不起,我以前不可能这样做。你的回答很好,但 rubenvb 更好地解释了一切。但是 +1 ☺
【解决方案3】:

以下所有选项均有效,但最佳选项在 rubenvb's answer 中进行了说明。


您至少有 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_directoriesget_target_property


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

【讨论】:

  • 感谢所有注释 :) 非常有帮助
猜你喜欢
  • 2011-12-19
  • 2012-02-22
  • 1970-01-01
  • 1970-01-01
  • 2015-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-24
相关资源
最近更新 更多