从头开始使用Cmake进行多目录项目

时间:2019-02-01 06:13:53

标签: c++ cmake compilation

我将不断混淆这个CMake的概念。我已经阅读了几篇描述如何编写CMake文件的文章。但是我发现的解释很少。

要点1 -我是否必须为每个文件夹分别创建CMakeLists.txt(是的,为简单起见,我们将其称为文件夹)?

第2点-显然,第1点的答案。我发现这些命令可以自动搜索*.cpp个文件

# get all *.cpp files recursively
file(GLOB_RECURSE SRC_LIST *.c* *.h*)

第3点-似乎无需提及*.hpp文件。 (这是模糊点)

我已尝试编译最简单的 Hello World! 程序

CMakeLists.txt
src
| - main.cpp (here I included #include "XYZ/abc.hpp")
| - XYZ
    | - abc.cpp (included #include "XYZ/abc.hpp")
    | - abc.hpp

为此,CMake是

cmake_minimum_required(VERSION 3.10)
project(CMAkeSample)
add_executable(hello src/main.cpp src/XYZ/abc.cpp)

这表明,将所有.cpp文件以及路径添加到add_executable中,就可以完成了。 这是真的吗?

要点4 -现在,我有一个相对较大的项目(出于任何原因而在eclipse中开发)。但是我需要为其创建cmake文件,因此不要使用Eclipse进行构建。

下面是文件系统,我只想制作一次CMakeLists.txt(如果可能)

CMakeLists.txt
src
| - main.cpp (here I included #include "File0.hpp" and #include "Folder1/File1.hpp")
| - File0.cpp (here I included #include "File0.hpp")
| - File0.hpp (here I included #include "Folder1/File1.hpp" and #include "Folder2/File2.hpp")
| - Folder1
    | - File1.cpp (included #include "File1.hpp")
    | - File1.hpp
| - Folder2
    | - File2.cpp (included #include "File2.hpp")
    | - File2.hpp

现在,如何在不手动在每个文件夹中写入cmake的情况下获取所有.cpp文件。有什么建议吗?

更新1: 我已经添加了如图所示的CMakeLists.txt

ProjectFolder
    CMakeLists.txt
    src
    | - CMakeLists.txt
    | - main.cpp (here I included #include "File0.hpp" and #include "Folder1/File1.hpp")
    | - File0.cpp (here I included #include "File0.hpp")
    | - File0.hpp (here I included #include "Folder1/File1.hpp" and #include "Folder2/File2.hpp")
    | - Folder1
        | - CMakeLists.txt
        | - File1.cpp (included #include "File1.hpp")
        | - File1.hpp
    | - Folder2
        | - CMakeLists.txt
        | - File2.cpp (included #include "File2.hpp")
        | - File2.hpp

ProjectFolder> src> CMakeLists.txt

add_library(main main.cpp File0.cpp File0.hpp)
target_link_libraries(main File1)

ProjectFolder> src> File1> CMakeLists.txt

add_library(File1 File1.cpp File1.hpp)
target_link_libraries(File1 File2)

ProjectFolder> src>文件> CMakeLists.txt

add_library(File2 File2.cpp File2.hpp)

毕竟,我得到的错误是

-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/ProjectFolder
[ 33%] Built target main
[ 44%] Building CXX object CMakeFiles/ProjectFolder.dir/src/main.cpp.o
[ 55%] Linking CXX executable ProjectFolder
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: cannot find -lFile1

更新2:

继续进行,要使其正常工作,这里和这里几乎没有进行任何更改(如 UPDATE 1 中所述,并在项目文件夹的CMakeLists.txt中以

的形式手动添加了链接)
set(GCC_LINK_FLAGS "-lpthread -lcurl -lgobject-2.0 -lgstreamer-1.0 -lglib-2.0 -lssl -lcrypto -lboost_thread -lboost_system")
add_subdirectory(src)
add_subdirectory(src/Folder1)
add_subdirectory(src/Folder2)

add_executable(ProjectFolder src/main.cpp)
target_link_libraries(ProjectFolder main ${GCC_LINK_FLAGS})
  

程序执行完美。但是显然,这是编写链接的非常粗糙的方式。寻找 Point2 的解决方案。

1 个答案:

答案 0 :(得分:1)

  

第1点-我是否必须为每个文件夹分别创建CMakeLists.txt(是的,为简单起见,我们将其称为文件夹)?

您应该为每个库或可执行文件创建一个单独的文件夹。 (尽管,也可以在一个文件夹中为可执行文件构建多个项目。有时我将此选项用于具有多个小型测试应用程序的文件夹。)

对于带有子文件夹的文件夹,您可能需要一个仅包含add_subdirectory()命令的CMakeLists.txt。 (请参见下面的示例。)

甚至可以制作一个CMakeLists.txt文件,其中考虑来自多个子文件夹的来源。我曾经为此写过一个答案。 (SO: Single CMakeLists.txt enough for my project?)不过,请看一下选票–没有多少人认为这是个好主意。 ;-)

  

第2点-显然,第1点的答案是“否”。我发现这些命令可以自动搜索* .cpp文件

我们广泛使用它,但也建议不要使用它。

缺点是,添加新资源后,构建链将无法自动识别。如果您在CMakeLists.txt中明确命名所有源,则可以授予该权限。

来自CMake doc.

  

注意:我们不建议您使用GLOB从源代码树中收集源文件列表。如果在添加或删除源时没有CMakeLists.txt文件更改,则生成的生成系统无法知道何时要求CMake重新生成。 CONFIGURE_DEPENDS标志可能无法在所有生成器上可靠地工作,或者如果将来添加了不支持它的新生成器,则使用该生成器的项目将被卡住。即使CONFIGURE_DEPENDS可以可靠地工作,在每次重新构建时都要进行检查。

因此,使用file(GLOB,一旦添加,移动或删除文件,您就永远不会忘记明确地重新运行CMake。

  

第3点-似乎无需提及* .hpp文件。 (这是模糊的点)

是的,没有必要,因为cpp文件中提到了包含文件。另一方面,我们将CMake与VS2013结合使用。如果在resp中找到所有标头,那就太好了。 VS项目文件夹。因此,我建议也提及包括在内。 (看来CMake足够聪明,可以将它们与源分开。因此,它不会为头文件创建构建命令。)

  

第4点-现在,我有一个相对较大的项目(无论出于何种原因,都在Eclipse中开发)。但是我需要为其创建cmake文件,因此不要使用Eclipse进行构建。

CMake是一个构建脚本构建器。我们用它来生成VS解决方案和项目。我确信它也能够为Linux构建Makefile。不幸的是,我对此没有实际经验。 (实际上,这就是为什么我们改用CMake的原因-有了一种可移植的方式来构建可移植的书面源代码。


顺便说一句。 cmake.org上有一个介绍:

CMake Tutorial


示例:

想象一下应用程序myApp的以下目录树:

└─ MyApp/
  ├─ main/
  │ ├─ CMakeLists.txt
  │ └─ myApp.cc
  ├─ gui/
  │ ├─ CMakeLists.txt
  │ ├─ guiMainWindow.cc
  │ └─ guiMainWindow.h
  ├─ model/
  │ ├─ CMakeLists.txt
  │ ├─ model.cc
  │ └─ model.h
  └─ CMakeLists.txt 

MyApp/CMakeLists.txt对任何源代码都不负责,但是它收集子文件夹的构建脚本。看起来可能像这样:

# MyApp/CMakeLists.txt

# make a project
project(MyApp)
# This will generate a MyApp solution for VisualStudio
# containing all involved projects.

# add sub-folders which have to be considered
add_subdirectory(main)
add_subdirectory(gui)
add_subdirectory(model)

MyApp/model可以为MyApp的基本数据模型提供一个库,而无需进一步依赖。因此,MyApp/model/CMakeLists.txt可能看起来像这样:

# MyApp/model/CMakeLists.txt

# build rule for library libmodel
add_libary(model
  model.cc model.h)

MyApp/gui可以为MyApp的GUI提供依赖于libmodel的另一个库。 MyApp/gui/CMakeLists.txt可能看起来像这样:

# MyApp/gui/CMakeLists.txt

# build rule for library libgui
add_libary(gui
  guiMainWindow.cc guiMainWindow.h)

# dependencies
target_link_libraries(gui
  model)

最后,MyApp/main提供了main()的{​​{1}}函数的源代码并生成了可执行文件。 MyApp可能看起来像这样:

MyApp/main/CMakeLists.txt