CMake "project"指令的正确用法是什么

what is the proper use of the CMake "project" directive

本文关键字:用法 是什么 project 指令 CMake      更新时间:2023-10-16

我有一个很大的代码库,它构建了几十个库和几个可执行文件。

代码库按层次划分,库几乎在每个级别构建。

我已经在每个目录下放置了一个CMakeLists.txt文件来构建每个库。

在每个CMakeLists.txt中,我使用了"项目(xxx)"指令。这为我定义了PROJECT_NAME, PROJECT_SOURCE_DIR和PROJECT_BINARY_DIR变量,我明智地使用了它们。

然而,一个团队对这种方法不满意,因为他找不到任何其他人这样做的真实世界的例子。他经常引用KitWare没有使用这种方法的例子,因此我们也不应该使用这种方法。

他提倡的另一种方法是在每个makefile中设置这些变量,这看起来很像"project"给你的。

我真的不明白他的意思,在说服他其他方面也没有什么进展。有谁能解释一下这样使用项目指令的缺点吗?

我把自己扔给你的集体智慧?

首先,它使您能够使用<projectName>_BINARY_DIR<projectName>_SOURCE_DIR,但这不是主要优点。如果你给CMake一个项目名,那么它会在自己的目录下为每个子项目生成构建目标。这意味着无论您使用的是GNU Make、Eclipse CDT、XCode还是其他任何受支持的生成器,您都可以单独构建子项目。例如,在GNU Make中,每个子项目都有自己的完整构建系统,从它自己的目录。

可以通过PROJECT_NAME访问当前项目名,通过CMAKE_PROJECT_NAME访问根项目名。

编辑:我刚刚意识到以下将是标准的CMake行为的任何构建目标,无论他们是否是项目。我将把它保存在这里作为一般信息,但它与答案无关:

假设我有一个c++库,我可以生成三个二进制可执行文件;Maintests/test1,以及examples/ex1。我可以在我从ALL目标调用CMake的目录中运行make,运行make ex1,或者我可以将目录更改为examples/,并从该目录中使用make构建示例。这将构建所有依赖的项目和库,即使它们在目录结构的其他地方,但不会构建Maintests/test1或它们依赖的examples/ex1不依赖的任何库。如果我然后从主目录运行make,它不会重新构建examples/ex1所依赖的任何库,除非它们的源代码发生了变化。

如果库是真正独立的项目,那么使用project命令是有意义的。但是,如果它们不是,我反而会将它们作为子目录添加到根CmakeLists.txt中。如果需要知道当前正在处理的目录,可以使用CMAKE_CURRENT_SOURCE_DIR和CMAKE_CURRENT_BINARY_DIR变量。

我今天发现了一个很好的使用示例:添加氧气文档。

我使用CMake(和Ninja)来构建我个人的c++项目。我一时兴起决定在我的一个几乎完整但未记录的工作中添加一些oxygen文档。我还认为,一旦我弄清楚如何使它尽可能通用,将它添加到其他项目中也会很好。

首先,我生成了一个标准的氧模板并将其重命名。

cd my_projects/projectx
doxygen -g Doxyfile
mv Doxyfile Doxyfile.in

注意。in扩展名。如果我没理解错的话,可能没有必要,但这是惯例。

接下来,我在我的CMakeLists.txt文件中添加了以下代码块,就在定义我的目标之前(不确定这是否重要,但CMake有时对某些命令的顺序很麻烦)。

FIND_PACKAGE(Doxygen)
IF("${DOXYGEN_FOUND}" MATCHES "^YES$")
    CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
                    ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
                    @ONLY)
    ADD_CUSTOM_TARGET(  doc ALL
                        COMMAND ${DOXYGEN_EXECUTABLE}
                        ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
                        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
                        COMMENT "Doxygenating..."
                        VERBATIM)
ENDIF()

创建一个名为doc的新目标。指定ALL将其添加到默认的"ALL"目标,但这是可选的。指定@ONLY确保任何"${variable}"类型的变量不会被CONFIGURE_FILE扩展,只能被"@variable@"类型扩展。有点令人困惑(至少对我来说),CMAKE_CURRENT_SOURCE_DIR似乎指的是项目目录,CMAKE_CURRENT_BINARY_DIR指的是构建目录。

最后,这就是PROJECT_NAME等进来的地方,我编辑了Doxyfile.in.

这是我的新Doxyfile.in:

DOXYFILE_ENCODING      = UTF-8
PROJECT_NAME           = "@PROJECT_NAME@"
PROJECT_NUMBER         = @PROJECT_VERSION_TWEAK@
PROJECT_BRIEF          =
PROJECT_LOGO           = @CMAKE_CURRENT_SOURCE_DIR@/res/doc_logo-200x55.png
OUTPUT_DIRECTORY       = @CMAKE_CURRENT_SOURCE_DIR@/doc

我想你明白了。一旦这是完全泛化的(这是一个词吗?)我可以复制它到我的其他项目,只要我标记我的代码,我将有很好的文档无处不在。

注意PROJECT_BRIEF没有指定。我还没写完,还有一些空白需要我思考。例如,PROJECT_VERSION_TWEAK实际上还没有包含任何内容。我将不得不找到一种方法来得到我的构建号在那里。