【问题标题】:CMake and subdirectories depending on parent directoriesCMake 和子目录取决于父目录
【发布时间】:2014-01-16 04:53:00
【问题描述】:

在 CMake 中如何处理这种编译情况?假设我们有一个包含子目录的源代码目录,例如

src:
 helper:
  innerpkg:
   a.cpp
   a.h
  helper.cpp
  helper.h
 main.cpp
 main.h

文件 a.cpp 调用文件 helper.cpp 中的内容,尽管 helper.cpp 可能不会调用 a.cpp 中的任何内容。因此,如果我们将 helper 子目录设为库,而将 innerpkg 设为库,我们会遇到一个问题,即 helper 需要包含 innerpkg,但 innerpkg 也需要 helper——一种循环依赖。处理这个问题的正确方法是什么,并且仍然在帮助程序中留下一些源文件?顺便说一句,我对使用 CMake 还是很陌生。

编辑:innerpkg 中的 CMakeLists.txt 文件可能如下所示:

 include_directories(${CCMBS_SOURCE_DIR})
 set(INNERPKG_SRC a.cpp)
 add_library(innerpkg ${INNKERPKG_SRC})

在助手中:

 include_directories(${PROJ_SOURCE_DIR})
 add_subdirectory(innerpkg)
 set(HELPER_SRC helper.cpp)
 add_library(helper ${HELPER_SRC})

 target_link_libraries(ui "-Wl,--whole-archive")
 target_link_libraries(ui innerpkg)
 target_link_libraries(ui "-Wl,--no-whole-archive")

以防万一。这些需要如何设置才能解决这个问题?

编辑:确切的依赖结构是这样的:innerpkg 中的东西依赖于 helper 中的东西。 innerpkg 由 main 使用。另一种情况是 helper 也依赖于 innerpkg 中的东西,即循环依赖,而 main 使用 helper 或 innerpkg。

【问题讨论】:

  • 如果innerpkg不依赖于helper,为什么它位于helper中?
  • @Patrick B.:正如我所提到的,它调用了 helper.cpp 中的内容。还是您的意思是“助手不依赖于innerpkg”?它也可以在 helper 中实现接口或基类,所以它在它的目录中作为一个特定的实现。
  • 为了更好地理解,也许您可​​以发布一个链接依赖关系图,显示谁需要做什么。或者你的 CMakeLists.txt。
  • 好吧,“真实”程序的 CMakeLists.txt 比上面的插图更复杂,这只是说明了问题,因此需要深入研究“真实程序”的细节。不过,我想我可以为假设的示例程序提供一个虚构的 CMakeLists.txt。但是这个问题的重点是我不确定要放什么来处理我提到的那种依赖关系(子目录取决于父文件中的文件)。不过,我想我可以为目录“helper”提供一个。你想要那个吗?至于图表,我写的内容有什么不清楚的地方?
  • 刚刚给出了简化的 CMakeLists.txt 示例。

标签: cmake


【解决方案1】:

我觉得您假设基于 CMake 的项目中的每个目录都必须包含自己的 CMakeLists.txt 文件并构建自己的库/可执行文件。

这个问题实际上与 CMake 并不完全相关。几乎任何构建系统都会遇到同样的问题。这里的问题是您的依赖关系树不清楚。应不惜一切代价避免循环依赖。

与 Java 及其基于包的系统相反,C++ 应用程序没有强制执行目录布局,甚至 CMake 也没有。
依赖关系只能用库和可执行程序来表示,前者主要用于避免在使用相同功能的不同程序之间重复代码。

在您的具体情况下,尚不清楚谁在使用 helperinnerpkg 库。所以让我们做几个假设。

1。您有多个程序同时使用这两个库

那么,拥有单独的库是非常有意义的,但最好将它们表示为平面目录结构,以便清楚地分离每个库和程序。

src
├─ helper
│  ├─ helper.cpp
│  └─ helper.h
├─ innerpkg
│  ├─ a.cpp
│  └─ a.h
├─ main
│  ├─ main.cpp
│  └─ main.h
└─ main2
   ├─ main2.cpp
   └─ main2.h

显然,既然你说helper.cpp不需要调用a.cpp中定义的东西,那么helper库不依赖innerpkg,因此不存在循环依赖。

就 CMake 而言,您将在每个目录(包括根目录)中拥有一个 CMakeLists.txt 文件,总共五个。
最上面的将只包含每个子目录,而剩下的四个将负责构建每个二进制文件。 只有mainmain2 中的CMake 列表实际上会调用target_link_libraries()

2。源码只编译了一个程序,而且只用到了两个库

那你为什么首先需要库呢?

由于只有一个可执行程序main,因此没有重复代码和功能。

这种情况下的解决方案是保留当前目录结构,其中子目录不是libraries,而是topics
我所说的主题是指最终程序功能的一个子集,为了便于维护而明确分开,但它暗示与其他主题的依赖关系。

在这种情况下为什么不关心依赖关系?仅仅是因为您不需要创建库。只需将每个 cpp 文件添加为 main 程序的源代码,这样依赖关系就会在链接时一次性自动解决。

在 CMake 方面,你只需要一个 CMakeLists.txt 文件在顶部,它只会构建一个程序并列出每个子目录中的每个 cpp 文件,如下所示:

add_executable(main
    main.cpp
    helper/helper.cpp
    helper/innerpkg/a.cpp
)

3。主程序使用一个库,每个库使用另一个

这也是假设您确实需要生成一个库,该库将作为您项目安装部分的一部分,以供第三方应用程序使用。

在这种情况下,通过使helperinnerpkg 只使用一个库来解决循环依赖问题。
然后,您应该有一个如下所示的目录结构:

src
├─ helper
│  ├─ helper.cpp
│  ├─ helper.h
│  └─ innerpkg
│     ├─ a.cpp
│     └─ a.h
└─ main
   ├─ main.cpp
   └─ main.h

和上一点一样,helper 下的目录结构没有暗示依赖关系,因为只会编译一个库。

此外,即使main 使用来自innerpkg 的功能,它也只是作为helper 的一部分透明地公开。

就 CMake 而言,您将拥有一个顶级 CMakeLists.txt,其中包括两个子目录,一个在 helper 中列出了 helper 和 innerpkg 中的每个 cpp 文件以构建一个库,一个在 main 中列出了 main 中的每个文件,并与帮助程序库链接。

【讨论】:

  • 我添加了一个注释,提到了什么使用 helper/innerpkg。这有帮助吗?此外,这应该是一个程序,而不是多个程序。我还认为您需要制作它们库,因为我正在阅读以尝试熟悉 CMake 的一些材料说您制作子目录库,并且每个子目录都需要一个 CMakeLists.txt 文件。所以是的,这就是我所做的假设,因为这就是我使用的材料似乎暗示的“正确”方法。
  • 所以我们在我回答的第 2 部分的范围内。我对你的参考资料很感兴趣,因为正如我所说,C++ 和 CMake 不强制执行任何特定的目录布局。
  • 嗯,我没有我使用的所有引用的列表,但这里有一个可能是我使用过的东西的例子,它暗示一个子目录“等于”一个库:stackoverflow.com/questions/5628927/… (见最佳答案)
  • 我也发现了这个,这是我使用的东西之一,因为它仍然在我的浏览器上突出显示:cs.swarthmore.edu/~adanner/tips/cmake.php“你项目中的每个目录都应该有一个 CMakeLists.txt 文件。”并将子目录的 CMakeLists.txt 显示为构建库。
猜你喜欢
  • 2011-10-25
  • 1970-01-01
  • 1970-01-01
  • 2015-05-25
  • 1970-01-01
  • 1970-01-01
  • 2021-09-27
  • 2018-07-15
  • 1970-01-01
相关资源
最近更新 更多