gpt4 book ai didi

cmake - CMake是如何使用的?

转载 作者:行者123 更新时间:2023-12-01 06:40:45 24 4
gpt4 key购买 nike

关闭。这个问题需要更多focused .它目前不接受答案。












想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post .

4年前关闭。



Improve this question




众所周知,初学者很难获得有关 CMake 的任何有用信息。到目前为止,我已经看过一些关于如何设置一些非常基本的项目或其他项目的教程。然而,这些都没有解释其中显示的任何内容背后的推理,总是留下许多漏洞需要填补。

在 CMakeLists 上调用 CMake 是什么意思?每个构建树应该调用一次还是什么?如果每个构建都使用来自同一源的相同 CMakeLists.txt 文件,我该如何为每个构建使用不同的设置?
为什么每个子目录都需要自己的 CMakeLists 文件?在 CMakeLists.txt 而非项目根目录的 CMakeLists.txt 上使用 CMake 是否有意义?如果是,在什么情况下?
指定如何从它们自己的子目录中的 CMakeLists 文件构建可执行文件或库与在所有源的根目录下的 CMakeLists 文件中执行有什么区别?
我可以为 Eclipse 制作一个项目,为 Visual Studio 制作另一个项目吗,只需更改 -G调用 CMake 时的选项?甚至是这样使用的吗?

到目前为止,我所看到的教程、文档页面或问题/答案都没有提供任何有用的见解来理解如何使用 CMake。这些例子并不彻底。无论我阅读什么教程,我都觉得我错过了一些重要的东西。

像我这样的 CMake 新手提出的许多问题并没有明确提出这一点,但显而易见的是,作为新手,我们不知道如何处理 CMake 或如何处理它。

最佳答案

CMake 有什么用?

根据维基百科:

CMake is [...] software for managing the build process of software using a compiler-independent method. It is designed to support directory hierarchies and applications that depend on multiple libraries. It is used in conjunction with native build environments such as make, Apple's Xcode, and Microsoft Visual Studio.



使用 CMake,您不再需要维护特定于您的编译器/构建环境的单独设置。您只有一种配置,它适用于多种环境。

CMake 可以从相同的文件生成 Microsoft Visual Studio 解决方案、Eclipse 项目或 Makefile 迷宫,而无需更改其中的任何内容。

给定一堆包含代码的目录,CMake 会管理您的项目在编译之前需要完成的所有依赖项、构建顺序和其他任务。它实际上并没有编译任何东西。要使用 CMake,您必须告诉它(使用名为 CMakeLists.txt 的配置文件)您需要编译哪些可执行文件、它们链接到哪些库、您的项目中有哪些目录以及其中的内容,以及诸如标志之类的任何详细信息或任何您需要的东西(CMake 非常强大)。

如果设置正确,则您可以使用 CMake 创建您选择的“ native 构建环境”完成其工作所需的所有文件。在 Linux 中,默认情况下,这意味着 Makefiles。所以一旦你运行 CMake,它会创建一堆文件供自己使用,外加一些 Makefile s。此后您需要做的就是在每次完成代码编辑后在控制台的根文件夹中键入“make”,然后生成一个编译和链接的可执行文件。

CMake 是如何工作的?它有什么作用?

这是我将在整个过程中使用的示例项目设置:
simple/
CMakeLists.txt
src/
tutorial.cxx
CMakeLists.txt
lib/
TestLib.cxx
TestLib.h
CMakeLists.txt
build/

每个文件的内容将在后面显示和讨论。

CMake 根据根 CMakeLists.txt 设置您的项目您的项目,并在您执行的任何目录中执行此操作 cmake从控制台。从不是项目根目录的文件夹执行此操作会产生所谓的源外构建,这意味着编译期间创建的文件(obj 文件、lib 文件、可执行文件,您知道)将放置在所述文件夹中,与实际代码分开保存。它有助于减少困惑,并且由于其他原因也是首选,我不会讨论。

我不知道如果你执行 cmake 会发生什么在除根之外的任何地方 CMakeLists.txt .

在这个例子中,因为我想把它全部放在 build/ 中文件夹,首先我必须导航到那里,然后通过 CMake 根目录 CMakeLists.txt居住。
cd build
cmake ..

默认情况下,正如我所说,这使用 Makefile 设置所有内容。这是构建文件夹现在的样子:
simple/build/
CMakeCache.txt
cmake_install.cmake
Makefile
CMakeFiles/
(...)
src/
CMakeFiles/
(...)
cmake_install.cmake
Makefile
lib/
CMakeFiles/
(...)
cmake_install.cmake
Makefile

所有这些文件是什么? The only thing you have to worry about is the Makefile and the project folders .

请注意 src/lib/文件夹。创建这些是因为 simple/CMakeLists.txt使用命令 add_subdirectory(<folder>) 指向它们.此命令告诉 CMake 在所述文件夹中查找另一个 CMakeLists.txt文件并执行该脚本,因此以这种方式添加的每个子目录都必须有一个 CMakeLists.txt文件内。在这个项目中, simple/src/CMakeLists.txt描述了如何构建实际的可执行文件和 simple/lib/CMakeLists.txt描述如何构建库。每一个目标是一个 CMakeLists.txt描述将默认放置在构建树中的子目录中。所以,在快速
make

在控制台完成 build/ ,添加了一些文件:
simple/build/
(...)
lib/
libTestLib.a
(...)
src/
Tutorial
(...)

项目已构建,可执行文件已准备好执行。 如果要将可执行文件放在特定文件夹中,您会怎么做? Set the appropriate CMake variable, or change the properties of a specific target .稍后会详细介绍 CMake 变量。

我如何告诉 CMake 如何构建我的项目?

以下是源目录中每个文件的内容解释:
simple/CMakeLists.txt :
cmake_minimum_required(VERSION 2.6)

project(Tutorial)

# Add all subdirectories in this project
add_subdirectory(lib)
add_subdirectory(src)

根据 CMake 在您不设置时抛出的警告,应始终设置所需的最低版本。使用您的 CMake 版本。

您的项目名称可以在以后使用,并暗示您可以从相同的 CMake 文件管理多个项目。不过,我不会深入研究。

如前所述, add_subdirectory()向项目添加一个文件夹,这意味着 CMake 期望它有一个 CMakeLists.txt内,然后它将在继续之前运行。顺便说一句,如果你碰巧定义了一个 CMake 函数,你可以从其他 CMakeLists.txt 使用它。 s 在子目录中,但您必须在使用 add_subdirectory() 之前定义它否则它不会找到它。不过,CMake 在库方面更聪明,因此这可能是您遇到此类问题的唯一一次。
simple/lib/CMakeLists.txt :
add_library(TestLib TestLib.cxx)

要创建您自己的库,您可以为其命名,然后列出构建它的所有文件。直截了当。如果它需要另一个文件, foo.cxx ,要编译,你应该写 add_library(TestLib TestLib.cxx foo.cxx) .这也适用于其他目录中的文件,例如 add_library(TestLib TestLib.cxx ${CMAKE_SOURCE_DIR}/foo.cxx) .稍后将详细介绍 CMAKE_SOURCE_DIR 变量。

你可以用它做的另一件事是指定你想要一个共享库。示例: add_library(TestLib SHARED TestLib.cxx) .不要害怕,这是 CMake 开始让您的生活更轻松的地方。无论是否共享,现在使用以这种方式创建的库所需要做的就是在此处为其指定名称。这个库的名称现在是 TestLib,您可以从项目的任何地方引用它。 CMake 会找到它。

有没有更好的方法来列出依赖项? Definitely yes .查看下面的更多信息。
simple/lib/TestLib.cxx :
#include <stdio.h>

void test() {
printf("testing...\n");
}
simple/lib/TestLib.h :
#ifndef TestLib
#define TestLib

void test();

#endif
simple/src/CMakeLists.txt :
# Name the executable and all resources it depends on directly
add_executable(Tutorial tutorial.cxx)

# Link to needed libraries
target_link_libraries(Tutorial TestLib)

# Tell CMake where to look for the .h files
target_include_directories(Tutorial PUBLIC ${CMAKE_SOURCE_DIR}/lib)

命令 add_executable()add_library() 的工作原理完全相同,当然,除了它会生成一个可执行文件。这个可执行文件现在可以作为诸如 target_link_libraries() 之类的目标被引用。 .由于 tutorial.cxx 使用在 TestLib 库中找到的代码,因此您将其指出给 CMake,如图所示。

类似地,在 add_executable() 中由任何来源 #included 的任何 .h 文件与源不在同一目录中的必须以某种方式添加。如果不是 target_include_directories()命令, lib/TestLib.h编译Tutorial 时找不到,所以整个 lib/文件夹被添加到要搜索#includes 的包含目录中。您可能还会看到命令 include_directories()它以类似的方式运行,不同之处在于它不需要您指定目标,因为它完全为所有可执行文件全局设置了它。稍后我将再次解释 CMAKE_SOURCE_DIR。
simple/src/tutorial.cxx :
#include <stdio.h>
#include "TestLib.h"
int main (int argc, char *argv[])
{
test();
fprintf(stdout, "Main\n");
return 0;
}

请注意“TestLib.h”文件是如何包含的。无需包含完整路径:由于 target_include_directories(),CMake 会在幕后处理所有这些工作。 .

从技术上讲,在这样一个简单的源代码树中,您可以不用 CMakeLists.txtlib/src/并添加类似 add_executable(Tutorial src/tutorial.cxx) 的内容至 simple/CMakeLists.txt .这取决于您和您的项目的需求。

我还应该知道什么才能正确使用 CMake?

(又名与您的理解相关的主题)

查找和使用包 : The answer to this question比我以往任何时候都更好地解释它。

声明变量和函数,使用控制流等 : 退房 this tutorial这解释了 CMake 必须提供的基础知识,并且总体上是一个很好的介绍。

CMake 变量 :有很多,所以接下来是一个速成类(class),让你走上正轨。 The CMake wiki is a good place to get more in-depth information on variables表面上还有其他事情。

您可能希望在不重建构建树的情况下编辑某些变量。为此使用 ccmake(它编辑 CMakeCache.txt 文件)。记得要 c完成更改后进行配置,然后 g使用更新的配置生成 makefile。

阅读 previously referenced tutorial学习使用变量,但长话短说: set(<variable name> value)更改或创建变量。 ${<variable name>}使用它。
  • CMAKE_SOURCE_DIR : 源码的根目录。在前面的例子中,这总是等于 /simple
  • CMAKE_BINARY_DIR : 构建的根目录。在前面的例子中,这等于 simple/build/ ,但如果你运行 cmake simple/来自文件夹,例如 foo/bar/etc/ ,然后所有对 CMAKE_BINARY_DIR 的引用在那个构建树中将成为 /foo/bar/etc .
  • CMAKE_CURRENT_SOURCE_DIR : 当前CMakeLists.txt所在的目录是在。这意味着它在整个过程中都发生了变化:从 simple/CMakeLists.txt 打印此内容 yield /simple ,并从 simple/src/CMakeLists.txt 打印它 yield /simple/src .
  • CMAKE_CURRENT_BINARY_DIR : 你懂的。此路径不仅取决于构建所在的文件夹,还取决于当前 CMakeLists.txt脚本的位置。

  • 为什么这些很重要?源文件显然不会在构建树中。如果你尝试类似 target_include_directories(Tutorial PUBLIC ../lib)在前面的例子中,那个路径是相对于构建树的,也就是说它就像写 ${CMAKE_BINARY_DIR}/lib ,这将查看内部 simple/build/lib/ .那里没有 .h 文件;最多你会找到 libTestLib.a .你要 ${CMAKE_SOURCE_DIR}/lib相反。
  • CMAKE_CXX_FLAGS : 传递给编译器的标志,在本例中是 C++ 编译器。另外值得注意的是CMAKE_CXX_FLAGS_DEBUG如果 CMAKE_BUILD_TYPE 将被使用设置为调试。还有更多这样的;退房 the CMake wiki .
  • CMAKE_RUNTIME_OUTPUT_DIRECTORY : 告诉 CMake 在构建时将所有可执行文件放在哪里。这是一个全局设置。例如,您可以将其设置为 bin/并把所有东西都整齐地放在那里。 EXECUTABLE_OUTPUT_PATH类似,但已弃用,以防您偶然发现它。
  • CMAKE_LIBRARY_OUTPUT_DIRECTORY : 同样,一个全局设置告诉 CMake 把所有库文件放在哪里。

  • 目标属性 :您可以设置仅影响一个目标的属性,无论是可执行文件还是库(或存档……您懂的)。 Here is a good example如何使用它(使用 set_target_properties()

    有没有一种简单的方法可以自动将源添加到目标? Use GLOB列出同一变量下给定目录中的所有内容。示例语法是 FILE(GLOB <variable name> <directory>/*.cxx) .

    你能指定不同的构建类型吗? 是的,虽然我不确定它是如何工作的或它的局限性。它可能需要一些 if/then'ning,但 CMake 确实提供了一些基本支持而无需配置任何东西,例如 CMAKE_CXX_FLAGS_DEBUG 的默认值。 ,例如。
    您可以从 CMakeLists.txt 中设置您的构建类型。文件通过 set(CMAKE_BUILD_TYPE <type>)或者通过使用适当的标志从控制台调用 CMake,例如 cmake -DCMAKE_BUILD_TYPE=Debug .

    使用 CMake 的项目有什么好的例子吗? 维基百科有一个使用 CMake 的开源项目列表,如果你想研究的话。到目前为止,在线教程在这方面一直让我失望,但是 this Stack Overflow question有一个非常酷且易于理解的 CMake 设置。值得一看。

    在代码中使用来自 CMake 的变量 :这是一个快速而肮脏的例子(改编自 some other tutorial ):
    simple/CMakeLists.txt :
    project (Tutorial)

    # Setting variables
    set (Tutorial_VERSION_MAJOR 1)
    set (Tutorial_VERSION_MINOR 1)

    # Configure_file(<input> <output>)
    # Copies a file <input> to file <output> and substitutes variable values referenced in the file content.
    # So you can pass some CMake variables to the source code (in this case version numbers)
    configure_file (
    "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
    "${PROJECT_SOURCE_DIR}/src/TutorialConfig.h"
    )
    simple/TutorialConfig.h.in :
    // Configured options and settings
    #define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
    #define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

    CMake 生成的结果文件, simple/src/TutorialConfig.h :
    // Configured options and settings
    #define Tutorial_VERSION_MAJOR 1
    #define Tutorial_VERSION_MINOR 1

    巧妙地使用这些,你可以做一些很酷的事情,比如关闭图书馆等。我建议您查看 that tutorial因为有些更高级的东西迟早会在更大的项目中非常有用。

    对于其他一切,Stack Overflow 充满了具体的问题和简明的答案,这对所有人都很好,除了初学者。

    关于cmake - CMake是如何使用的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26007566/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com