如何使用cmake结构化我的c++项目?

9

我已经苦苦挣扎了相当长一段时间,我的关于CMake的尝试只带来了一些笨拙的解决方案,我很肯定这些方案是不正确的。

我创建了一个库,包含以下几个文件:

-libfolder
  -codepart1folder
    -CMakeLists.txt
    -codepart1.cpp
    -codepart1.hpp
  -codepart2folder
  -codepart3folder
  -lib.cpp
  -lib.hpp
  -CMakeLists.txt

我写了一个CMakeLists文件来编译库(经过一些实验),我可以生成一个lib.a文件。现在,我想将这个代码作为库包含到其他项目中,并通过lib.hpp中的接口访问它。就目录结构和需要放入根项目的CMakeLists.txt而言,最好的方法是什么?
我当前的尝试是将-libfolder添加为当前项目的子文件夹,并添加以下命令:
include_directories(${PROJECT_SOURCE_DIR}/libfolder)
link_directories(${PROJECT_BINARY_DIR}/libfolder)
add_subdirectory(libfolder)
target_link_libraries(project lib)

当我运行make时,库编译得很好,但是当project.cpp编译时,它抱怨找不到codepart1.hpp(它包含在lib.hpp中,从project.cpp包含)。

我怀疑这样做可能是错误的方式,但我无法浏览CMake文档并找到有关设置此类项目的良好教程。请帮忙,CMake大师们!


或许对于 CMake 并没有太大的帮助,但我建议你看看 Premake。它接近成熟,并且具有许多优点,相对于 CMake 更快更易上手(尤其是如果你已经了解 Lua)。你可以在 http://industriousone.com/what-premake 上查看它。 - Ylisar
1
所以,您想要使您的新项目能够使用先前构建的库,还是想要从某种元项目构建两者? - moooeeeep
4个回答

5
干净的导入一个CMake项目到另一个项目的方法是通过find_package命令。使用export命令声明包。使用find_package的优点是它消除了硬编码包文件路径的需要。
关于缺少hpp文件,你没有包含codepart1folder,所以它不在包含路径中。

好的...从这个答案中,我并不真正清楚find_package和export是否是在这种情况下使用的正确方法,或者我应该如何使用。你能详细说明一下吗? - dlants
使用 include_directories(${PROJECT_SOURCE_DIR}/libfolder/codepart1folder)。 - LeDYoM

2

好的,经过我请教一位熟悉CMake的同事后,似乎CMake不支持我想做的事情,所以只剩下三个选择:

  1. 将所有依赖项添加到父项目的CMakeLists.txt中——这样做并不是很干净,但它可以让东西正常工作。您需要为每个添加代码的项目执行此操作,并在库更改时返回并修复问题。

  2. 清理库头文件。这是通过一些编译器技巧来完成的。其思想是对每个类进行前向声明,并仅使用指针或boost::shared_ptr,然后仅在cpp文件中包含依赖项。这样,您可以使用所有findpackage内容构建cpp文件,并且您可以通过仅包括头文件和链接到库来使用该库。

  3. 研究构建系统。具有可移植性的代码和具有复杂依赖关系的快速代码编译并不是一个解决的问题!从我的调查中发现,这变得非常复杂。最终,我采用了我的同事在CMake中自己创建的构建系统,他从Google中学到了一些东西。


+1,因为清理您的界面以使其不需要第三方包含目录甚至更好。 - André

1
看了你的帖子,似乎没有在任何地方添加'codepart1folder'到包含中。你是如何包含codepart1.hpp的呢?
#include <codepart1.hpp>
#include "codepart1folder/codepart1.hpp"

我认为没有一种标准的方式来构建cmake项目。我看过很多cmake仓库,它们往往存在差异。个人而言,我会按照以下方式进行:

-project
    CMakeLists.txt
    -build
    -cmake
         OptionalCmakeModule.cmake
    -src
        -Main
            Main.cpp
            Main.hpp
        -DataStructs
            SomeTree.hpp
            SomeObject.hpp
        -Debug
            Debug.hpp
        -UI
            Window.hpp
            Window.cpp

基本上,它将所有源代码转储到一个目录中,然后您可以在项目根文件夹中执行外部构建:'mkdir build && cd build && cmake .. && make'

如果您的项目包含单独的库,则可能需要一个单独的库目录,并在其中创建另一个子文件夹以存放特定的库。

我有一些存储在https://github.com/dcbishop/上的仓库,如果您想查看CMakeLists.txt文件。

我的项目结构的主要问题是我使用了FILE_GLOB,这显然是做事情的“错误”方式(如果您在运行'cmake ..'之后添加文件,则在进行'make'时不会被捕获)。我还没有弄清楚正确的方法是什么(据我所见,它涉及保持单独的文件列表),我也只使用了一个CMakeLists.txt文件。

一些项目还选择将他们的cpp和hpp文件分别放置在不同的目录中,这样你就会有一个include和src文件夹(至少对于那些打算被外部使用的hpp文件)。我认为这主要是针对那些主要是大型库的项目。这也将使安装头文件变得更加容易。

codepart1folder已包含在libfolder内的CMakeLists.txt文件中。在项目文件夹的CmakeLists.txt中添加所有子文件夹、包含和链接似乎是错误的,因为project.cpp并不依赖于它们,只有lib.hpp依赖。在您的目录树中,想象一下有一个定义库的project2,我想将project2用作project的子部分。 - dlants
@JohnSavage。但这是正确的方法...我会在lib-project中创建一个LIB_INCLUDE_DIRS变量,将所有必要的依赖包含目录“导出”到CMakeCache中。然后假设在cmake Project时该变量将存在。 - André

0

你可能缺少了

include_directories(${PROJECT_SOURCE_DIR}/libfolder/codepart1folder)

在这种情况下,您可能希望使用set( CMAKE_INCLUDE_CURRENT_DIR on)将所有文件夹添加到包含目录路径变量中。
请检查cmake在命令行上的输出,以确定是否已设置正确的包含文件夹。此外,您始终可以使用message()作为cmake变量的“打印调试”方式。 但是,在包含目录的情况下,您需要读取目录属性,以了解实际上包含了哪些目录。
get_property(inc_dirs DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
message("inc_dirs = ${inc_dirs}")

希望这能帮助你找出缺失了什么。

编辑

我刚看到你的评论,关于在libfolder中添加codepart1folder。它只在libfolder的include_directory路径中可用,而不会传播到根文件夹。 由于include codepart1.hpp存在于lib.hpp中,但是您还需要将其放在项目路径中,否则在构建项目时会出现缺少声明错误。


好的,这是我的问题。我觉得我不应该去重新包含所有子文件夹到父项目中。lib 是一个独立的代码块,有它自己的 CMakeLists.txt,并且可以正常编译成 lib.a。我不想在每个要使用它的项目中都要将它们连接起来。 - dlants
1
然后,您应该正确地接口您的库。 - Bort

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接