首先,有一些目录的常规名称是您不能忽略的,它们基于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有一个用于安装文件的命令(隐式创建“安装”目标,执行“进行安装”)您可以用来将所有标题放入/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
是CMake的变量,我设置为src文件夹,并且INCLUDEROOT
是CMake的变量,我设置到哪里,以头需要去。当然,还有许多其他方法可以做到这一点,我敢肯定我的方法不是最好的。关键是,没有理由仅将标头安装在目标系统上就拆分标头和源,因为这非常容易,尤其是对于CMake(或CPack),可以选择并将标头配置为无需将它们放在单独的目录中即可安装。这就是我在大多数库中看到的。
Quote:其次,我想使用Google C ++测试框架对我的代码进行单元测试,因为它似乎很容易使用。您是否建议将其与我的代码捆绑在一起,例如在“ inc / gtest”或“ contrib / gtest”文件夹中?如果捆绑在一起,您是否建议使用fuse_gtest_files.py脚本减少文件数量或将其保留原样?如果不捆绑在一起,该依赖关系如何处理?
不要将依赖项与您的库捆绑在一起。通常这是一个非常可怕的想法,当我一直试图建立一个能够做到这一点的库时,我总是讨厌它。它应该是您的不得已的办法,并提防陷阱。通常,人们将依赖项与他们的库捆绑在一起是因为他们针对的是糟糕的开发环境(例如Windows),或者是因为他们仅支持所讨论的库的旧版本(不赞成使用)(依赖项)。主要的陷阱是,捆绑的依赖项可能与同一个库/应用程序的已安装版本冲突(例如,捆绑了gtest,但是尝试构建您的库的人已经安装了更新(或更旧)的gtest版本,然后两者可能会发生冲突,给那个人带来非常讨厌的头痛)。因此,正如我所说,这样做需要您自担风险,我只能说是不得已。与尝试解决捆绑的依赖项和现有安装之间的冲突相比,让人们在编译您的库之前先安装一些依赖项要容易得多。
Quote:在编写测试时,通常如何组织这些测试?我当时想为每个类创建一个cpp文件(例如,test_vector3.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”目录只是一个安装目录,其内容就是从src目录中选择的任何标头。
第三,CMake系统旨在分布在源子目录上,而不是作为一个CMakeLists.txt文件放在顶层。这样可以使内容保持本地化,这很好(本着将内容分解为独立部分的精神)。如果添加新的源代码,新的头文件或新的测试程序,则只需在相关子目录中编辑一个小的CMakeLists.txt文件即可,而不会影响其他任何内容。这也使您可以轻松地重组目录(CMakeList是本地的,包含在要移动的子目录中)。顶级CMakeLists应该包含大多数顶级配置,例如设置目标目录,自定义命令(或宏)以及查找系统上安装的软件包。较低级别的CMakeList应仅包含标头,源,
Quote:CMakeLists.txt的外观如何,以便它既可以构建库又可以构建库和测试?
基本的答案是,CMake允许您从“全部”中专门排除某些目标(这是您键入“ make”时构建的目标),并且您还可以创建特定的目标捆绑包。我无法在此处进行CMake教程,但是直接查找是很简单的。但是,在这种情况下,推荐的解决方案当然是使用CTest,这只是可以在CMakeLists文件中使用的另一组命令,用于注册标记为unit-的许多目标(程序)。测试。因此,CMake将所有测试放在一个特殊的构建类别中,而这正是您所要的,因此,问题已得到解决。
Quote:另外,我也看到了很多项目具有一个bin目录的构建。是否在构建目录中进行构建,然后将二进制文件移到bin目录中?测试的二进制文件和库是否位于同一位置?还是将其结构如下所示更有意义:
在源代码外部(“ out-of-source”版本)之外拥有一个构建目录确实是唯一理智的事情,这已成为当今的事实上的标准。因此,当然,就像CMake人们推荐的那样,在源目录之外,还有一个单独的“ build”目录,就像我遇到的每个程序员一样。至于bin目录,这是一个惯例,坚持下去可能是个好主意,就像我在本文开头提到的那样。
Quote:我也想用doxygen来记录我的代码。是否有可能使它自动与cmake和make一起运行?
是。这是不可能的,它很棒。根据您想要获得的幻想,有几种可能性。CMake确实具有Doxygen的模块(即find_package(Doxygen)
),该模块允许您注册将在某些文件上运行Doxygen的目标。如果您想做更多花哨的事情,例如更新Doxyfile中的版本号,或自动为源文件输入日期/作者戳等,则可以使用一些CMake功夫来实现。通常,执行此操作将涉及保留一个源Doxyfile(例如,我在上面的文件夹布局中放入的“ Doxyfile.in”),该源Doxyfile具有要查找的令牌并由CMake的解析命令代替。在我的顶级CMakeLists文件中,您会找到一块这样的CMake功夫,它可以与cmake-doxygen一起做一些有趣的事情。