首先,您不能忽略一些常规的目录名称,这些名称是基于 Unix 文件系统的悠久传统。这些是:
trunk
├── bin : for all executables (applications)
├── lib : for all other binaries (static and shared libraries (.so or .dll))
├── include : for all header files
├── src : for source files
└── doc : for documentation
坚持这种基本布局可能是个好主意,至少在顶层是这样。
关于拆分头文件和源文件(cpp),这两种方案都相当普遍。但是,我倾向于将它们放在一起,在日常任务中将文件放在一起更实用。此外,当所有代码都在一个顶级文件夹(即trunk/src/
文件夹)下时,您会注意到所有其他文件夹(bin、lib、include、doc,可能还有一些测试文件夹)都在顶级,除了源外构建的“构建”目录是所有文件夹,其中仅包含构建过程中生成的文件。因此,只需要备份 src 文件夹,或者更好的是,将其保存在版本控制系统/服务器(如 Git 或 SVN)下。
当涉及到在目标系统上安装头文件时(如果你想最终分发你的库),CMake 有一个用于安装文件的命令(隐式创建一个“安装”目标,执行“make install”)您可以使用将所有标题放入/usr/include/
目录中。我只是为此目的使用以下 cmake 宏:
# custom macro to register some headers as target for installation:
# setup_headers("/path/to/header/something.h" "/relative/install/path")
macro(setup_headers HEADER_FILES HEADER_PATH)
foreach(CURRENT_HEADER_FILE ${HEADER_FILES})
install(FILES "${SRCROOT}${CURRENT_HEADER_FILE}" DESTINATION "${INCLUDEROOT}${HEADER_PATH}")
endforeach(CURRENT_HEADER_FILE)
endmacro(setup_headers)
SRCROOT
我设置到 src 文件夹的 cmake 变量在哪里,并且是INCLUDEROOT
我配置到标头需要去的任何地方的 cmake 变量。当然,还有很多其他的方法可以做到这一点,我敢肯定我的方法不是最好的。关键是,没有理由仅仅因为只需要在目标系统上安装头文件就将头文件和源分开,因为很容易,特别是使用 CMake(或 CPack),挑选和配置头文件以无需将它们放在单独的目录中即可安装。这是我在大多数图书馆看到的。
Quote: 其次,我想使用 Google C++ 测试框架对我的代码进行单元测试,因为它看起来相当容易使用。您是否建议将此与我的代码捆绑在一起,例如在“inc/gtest”或“contrib/gtest”文件夹中?如果捆绑,您建议使用 fuse_gtest_files.py 脚本来减少数量或文件,还是保持原样?如果没有捆绑,如何处理这种依赖关系?
不要将依赖项与您的库捆绑在一起。这通常是一个非常可怕的想法,当我被困在试图构建一个这样做的库时,我总是讨厌它。这应该是你最后的手段,并提防陷阱。通常,人们将依赖项与他们的库捆绑在一起,或者因为他们针对糟糕的开发环境(例如,Windows),或者因为他们只支持所讨论的库(依赖项)的旧(不推荐)版本。主要的缺陷是您的捆绑依赖项可能与同一个库/应用程序的已安装版本冲突(例如,您捆绑了 gtest,但尝试构建您的库的人已经安装了更新(或旧)版本的 gtest,然后两者可能会发生冲突并使那个人非常头疼)。所以,正如我所说,这样做需要您自担风险,我会说只是作为最后的手段。要求人们在能够编译您的库之前安装一些依赖项比尝试解决捆绑的依赖项和现有安装之间的冲突要小得多。
Quote: 在编写测试时,这些通常是如何组织的?我正在考虑为每个类(例如 test_vector3.cpp)创建一个 cpp 文件,但所有文件都编译为一个二进制文件,以便它们可以轻松地一起运行?
在我看来,每个类(或小的有凝聚力的类和函数组)一个 cpp 文件更常见和实用。但是,绝对不要将它们全部编译成一个二进制文件,以便“它们都可以一起运行”。这真是个坏主意。通常,当涉及到编码时,您希望尽可能多地拆分事物。在单元测试的情况下,您不希望一个二进制文件运行所有测试,因为这意味着您对库中的任何内容所做的任何微小更改都可能导致该单元测试程序几乎完全重新编译,而这只是等待重新编译的几分钟/几小时。只需坚持一个简单的方案:1 个单元 = 1 个单元测试程序。然后,
Quote: 由于 gtest 库通常是使用 cmake 和 make 构建的,我在想我的项目也像这样构建是否有意义?如果我决定使用以下项目布局:
我宁愿建议这种布局:
trunk
├── bin
├── lib
│ └── project
│ └── libvector3.so
│ └── libvector3.a products of installation / building
├── docs
│ └── Doxyfile
├── include
│ └── project
│ └── vector3.hpp
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
│
├── src
│ └── CMakeLists.txt
│ └── Doxyfile.in
│ └── project part of version-control / source-distribution
│ └── CMakeLists.txt
│ └── vector3.hpp
│ └── vector3.cpp
│ └── test
│ └── test_vector3.cpp
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
│
├── build
└── test working directories for building / testing
└── test_vector3
这里有几点需要注意。首先,你的 src 目录的子目录应该镜像你的 include 目录的子目录,这只是为了保持直观(另外,尽量保持你的子目录结构合理平坦(浅),因为文件夹的深层嵌套通常比其他任何事情都更麻烦)。其次,“include”目录只是一个安装目录,它的内容就是从 src 目录中挑选出来的任何头文件。
第三,CMake 系统旨在分布在源子目录中,而不是作为顶层的一个 CMakeLists.txt 文件。这使事情保持本地化,这很好(本着将事情分成独立部分的精神)。如果您添加新源、新标头或新测试程序,您只需在相关子目录中编辑一个小而简单的 CMakeLists.txt 文件,而不会影响其他任何内容。这也使您可以轻松地重组目录(CMakeLists 是本地的并且包含在被移动的子目录中)。顶级 CMakeLists 应该包含大部分顶级配置,例如设置目标目录、自定义命令(或宏)以及查找系统上安装的包。较低级别的 CMakeLists 应该只包含简单的标题列表、源列表、
Quote: 如何将 CMakeLists.txt 看起来,以便它可以构建库或库和测试?
基本答案是 CMake 允许您从“all”(这是您键入“make”时构建的)专门排除某些目标,您还可以创建特定的目标包。我不能在这里做一个 CMake 教程,但你自己找出来是相当直接的。然而,在这种特定情况下,推荐的解决方案当然是使用 CTest,它只是一组额外的命令,您可以在 CMakeLists 文件中使用这些命令来注册许多标记为单元的目标(程序)-测试。因此,CMake 会将所有测试放在一个特殊的构建类别中,而这正是您所要求的,因此问题解决了。
Quote: 另外,我也看到了相当多的项目有一个构建广告一个 bin 目录。构建是否发生在构建目录中,然后二进制文件移出到 bin 目录中?测试和库的二进制文件会在同一个地方吗?或者将其结构如下更有意义:
在源代码之外拥有一个构建目录(“源外”构建)确实是唯一明智的做法,这是当今事实上的标准。所以,就像 CMake 人推荐的那样,就像我遇到的每个程序员一样,肯定地,在源目录之外有一个单独的“构建”目录。至于 bin 目录,嗯,这是一个约定,坚持它可能是一个好主意,正如我在本文开头所说的那样。
Quote: 我也想使用 doxygen 来记录我的代码。是否可以使用 cmake 和 make 自动运行它?
是的。这是不可能的,太棒了。根据您想要获得的花哨,有几种可能性。CMake 确实有一个 Doxygen 模块(即find_package(Doxygen)
),它允许您注册将在某些文件上运行 Doxygen 的目标。如果你想做更多花哨的事情,比如更新 Doxyfile 中的版本号,或者为源文件自动输入日期/作者标记等等,这一切都可以通过一点 CMake 功夫来实现。通常,这样做将涉及您保留一个源 Doxyfile(例如,我放在上面的文件夹布局中的“Doxyfile.in”),它具有要被 CMake 的解析命令找到和替换的标记。在我的顶级 CMakeLists 文件中,您会发现这样一个 CMake 功夫,它与 cmake-doxygen 一起做了一些花哨的事情。