为多个项目创建一个CMake构建目录

39

我是CMake的初学者用户。我的环境中有几个项目,比如:

project
  |------ CMakeLists.txt (The main Cmake)
  |------ ProjectA
  |          |----- .cpp files
  |          |----- .hpp files
  |          |----- CMakeList.txt
  |------ ProjectB
  |          |----- .cpp files
  |          |----- .hpp files
  |          |----- CMakeList.txt
  | 
  |------ build
  |         |-----  CMakeStuff
  |------ bin
  |        |---- executables
  |------ lib
  |        |---- libwhatever.a
  |------ db 
           |---- Database stuff

如上所示,我希望为每个项目使用一个单一的构建目录,最好能够将其分成多个子项目,例如build/projectAbuild/ProjectB,这样如果我需要重建单个项目,我可以删除整个build/Project文件,所有内容都会被删除,新的Cmake将重新构建它。

我在配置CMAKE时遇到了困难。

我的原始CMakeList.txt在项目文件夹中:

cmake_minimum_required(VERSION 3.2.2.)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../bin)

project(projectA)
set(CMAKE_BUILD_TYPE Debug)

file(GLOB SOURCES "*.cpp")

add_library(commonmessage SHARED ${SOURCES})

install(TARGETS commonmessage DESTINATION ../lib)

我的问题是:

A)如果我在一个单独的构建目录上运行 CMake,会发生什么情况 - 是否可能,正确的 CMAKE 配置是什么?

B)我需要在 ProjectA 的编译中包含来自 ProjectB 的文件 - 我怎样才能在每个项目的 CMakeLists.txt 中设置它?

C)最后,我需要一个单一的 makefile 来构建所有内容,并且需要选择单独构建每个项目的选项。是否可以在一个单独的构建目录中实现这一点?

感谢您的帮助。

2个回答

62

首先,根据您发布的CMake代码,它似乎并不属于顶级CMakeList.txt文件,因为它直接引用了.cpp文件和"projectA"。 此外,还有一些非惯用用法:

cmake_minimum_required(VERSION 3.2.2.)

为什么这里要有尾随点?不确定cmake是否会抱怨,但无论如何它都是无用的。

set(CMAKE_BUILD_TYPE Debug)

不要这样做。相反,使用命令行标志-DCMAKE_BUILD_TYPE=Debug调用cmake,或者使用ccmake、GUI或编辑CMakeCache.txt文件。

file(GLOB SOURCES "*.cpp")

也不要那样做。在CMake中,明确列出源文件是一个好的实践,因为通配符匹配不会自动使cmake检测到新添加或删除的文件。但有些人可能意见不同。

现在进入主题的核心,这里是通常的做法:

顶层的CMakeLists.txt文件:

cmake_minimum_required(VERSION 3.2.2)
project(globalProject)

add_subdirectory(projectA)
add_subdirectory(projectB)

ProjectA的CMakeLists.txt文件(假设projectA是可执行文件):

add_executable(projectA file1.cpp file2.cpp ... )
include_directories(${CMAKE_SOURCE_DIR}/projectB) # include files from ProjectB
target_link_libraries(projectA projectB)

install(TARGETS projectA RUNTIME DESTINATION bin)

ProjectB的CMakeLists.txt文件(假设ProjectB是一个库):

add_library(projectB file1.cpp file2.cpp ... )

install(TARGETS projectB
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib)
请注意,此设置需要执行make install步骤,以在命令行调用cmake -DCMAKE_INSTALL_PREFIX = ..(假设从构建目录运行make)中指定的位置创建bin和lib文件夹。
此外,此设置允许您选择构建静态库或共享库,方法是使用:-DBUILD_SHARED_LIBS = ON。要同时构建两者,您需要使用两个具有不同名称的add_library调用之一为STATIC,另一个为SHARED。
总结使此工作所需的步骤:
$ mkdir build && cd build
$ cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=.. -DBUILD_SHARED_LIBS=ON
$ make
$ make install

您可以将这些命令放在脚本中以供重用。

现在,可以回答您的问题:

A) 是可能且推荐的,参见上述代码,只需要一个构建目录。

B) 请查看projectA/CMakeLists.txt项目的代码,您必须调用include_directories()

C) 是的,这是可能的。通过使用make和目标名称,可以从构建目录中单独构建项目中的每个目标:make projectBmake projectA


先生,感谢您的帮助...如果我需要在目标文件夹中生成lib和bin文件而不需要进行'make install'操作怎么办? - Mendes
好的观点。bin是所有可执行文件安装的位置。lib将保存所有库。 - Mendes
安装(TARGETS projectA,projectB ...)正在发出“在此目录中不存在的给定目标”projectA”的安装TARGETS”...由于子目录而无法工作。 - Mendes
如果在声明目标后,在这两个特定的CMakeLists.txt文件中各放置一个“install”调用,它是否有效? - SirDarius
好的,就像我刚才说的那样,在每个子目录中放置安装指令 :) - SirDarius
显示剩余3条评论

3

A) 您可以为N个项目创建1个CMakeLists.txt。当您定义库时,您可以在CMake中定义的可执行文件中使用它(请参见add_executable和target_link_libraries)。

B) 请参见target_include_directories。

C) 看起来您可以调用cmake --target target仅为cmakelists.txt文件中其中一个目标生成Makefile。


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