当前位置: 首页 > 科技观察

放弃Autotools,转向CMake

时间:2023-03-16 20:58:00 科技观察

CMake是一个跨平台的编译、测试和打包软件,即使您以前从未使用过构建系统,也可以轻松上手。在我之前的文章Autotools入门中,我解释了如何使用Autotools来管理和打包您的代码。它是一个功能强大且用途广泛的平台,可以轻松集成到许多打包系统中,包括RPM、APT、pkgsrc等等。它的语法和结构可能令人困惑,但幸运的是,我们还有其他选择,开源CMake就是其中之一。CMake是一个用于构建、测试和打包软件的跨平台套件。它使用简单明了的语法,因此即使您以前从未使用过构建系统,也很容易上手。安装CMake您的Linux系统上可能已经安装了CMake。如果没有,您可以使用发行版的包管理器安装它:$sudodnfinstallcmake在Debian或类似系统上:$sudoaptinstallcmake在Mac上,您可以使用MacPorts或Homebrew安装:$sudoportinstallcmake在Windows上,您可以使用Chocolatey或直接从CMake网站下载二进制文件进行安装。使用CMake对于想要从源代码构建软件的开发人员或用户,CMake是一种快速简便的编译和安装方法。CMake分阶段工作:首先,在cmake步骤中,CMake扫描计算机以获取一些默认设置。默认设置包括库的位置和软件在系统上的安装位置。接下来,在您的系统上使用make命令(在Linux上使用GUNMake,在NetBSD上使用NetBSDMake)来编译程序。此过程通常涉及将人类可读的源代码转换为机器语言。最后,在makeinstall步骤中,将那些编译好的文件复制到电脑上合适的位置(在cmake步骤中扫描)。这个看似简单,使用CMake的时候就是这样。CMake可移植性CMake在设计时就考虑到了可移植性。虽然它不会使您的项目在所有POSIX平台上正常工作(这取决于您作为开发人员),但它将确保标记为安装的文件安装在已知平台上最合适的位置。得益于CMake等工具,高级用户可以轻松地根据他们的系统需求自定义和覆盖任何不合适的选项。使用CMake,您只需要知道将哪些文件安装到哪个一般位置即可。它会处理其他一切。不再需要有可能在任何未经测试的操作系统上失败的自定义安装脚本。打包与Autotools一样,CMake具有良好的打包支持。无论它们是打包为RPM、DEB还是TGZ(或其他任何形式),将带有CMake的项目交给打包人员,他们的工作简单明了。打包工具支持CMake,因此可能不需要修补或调整。在许多情况下,可以将CMake项目自动集成到工作流程中。如何使用CMake要在项目中使用CMake,只需在项目目录中创建一个CMakeLists.txt文件。首先,声明所需的最低CMake版本以及项目名称和版本。CMake会尽可能长时间地保持兼容性,但随着你使用它的时间更长并关注它的最新发展,你就会知道你依赖哪些功能。cmake_minimum_required(VERSION3.10)project(HelloVERSION1.0)您可能已经看到,CMake的语法是带有括号和参数的命令。大写的VERSION字符串不是任意的,也不仅仅是一种格式。它们是项目命令中的有效参数。在继续之前,先用C或C++编写一个简单的helloworld程序。为简单起见,我编写了六行C代码并将其保存在hello.c中(以匹配我在CMakeLists.txt中的可执行文件的名称)。#includeintmain(){printf("Helloopensource\n");return0;}然而,请不要误会,CMake不仅仅适用于C和C++。它可以处理任意文件并有许多可用的命令,因此它可以帮助您以多种不同的形式维护项目。所有有效的内置命令及其可用参数都记录在CMake网站中,因此无论您尝试做什么,都可以轻松发现所需的功能。然而,这是一个简单的例子,所以你需要的下一个命令是必不可少的-你必须定义CMake构建的代码:add_executable(Hellohello.c)这个命令指定你编译的二进制文件的名称是Hello。因此,这与您在终端中使用-oHello执行gcc命令是一样的。在一些比较复杂的项目中,可能还需要用到库文件,可以使用addlibrary命令链接库文件。在设置了要构建的文件并标记为安装后,一旦用户安装了程序,就必须告诉CMake最终应用程序应该在哪里。在这个简单的示例中,您需要做的就是将安装命令添加到您的CMakeLists.txt文件中。安装命令接受几个参数。但在这个例子中,你只需要使用TARGET命令指定你要安装的文件名即可。install(TARGETSHello)添加一些文件到CMake项目中一个软件项目往往交付给用户的不仅仅是代码,还有一些其他的文件数据,比如手册或者信息页,示例项目,或者配置文件。您可以使用与包含编译文件时类似的工作流程在CMake项目中包含任意数据:在CMakelists.txt文件中使用文件命令,然后指定这些文件的安装位置。例如,您可以在此项目中包含一个资产目录,您可以使用文件命令后跟COPY和DESTINATION参数来告诉CMake将这些附加文件复制到您的分发包中。file(COPYassetsDESTINATION"${CMAKE_CURRENT_BINARY_DIR}")${CMAKE_CURRENT_BINARY_DIR}变量是一个特殊的CMake内置变量,表示CMake正在处理的目录。也就是说,你拥有的任何文件都会被复制到build目录下(运行cmake命令后,这个过程会更加清晰,到时候回过头来看)。因为这些多余的数据文件有点乱(不信可以看看/usr/share目录)。为您自己的项目创建子文件夹对每个人都有好处。最好也带上版本名称。您可以通过在CMAKE_CURRENT_BINARY_DIR中指定一个新目录来执行此操作,其中包含您选择的项目名称,后跟一个为您的项目命名的特殊变量和您在项目声明中为其设置的版本。file(COPYassetsDESTINATION"${CMAKE_CURRENT_BINARY_DIR}/Hello-${Hello_VERSION}")定义安装位置您已经定义了要编译的文件,所以现在您需要告诉CMake您的程序应该安装在哪里。例如,您的主程序使用安装命令:install(DIRECTORY"${CMAKE_CURRENT_BINARY_DIR}/Hello-${Hello_VERSION}"TYPEDATA)这里有一些新参数。DIRECTORY参数指定数据文件是目录,而不是文件(FILE)或脚本(SCRIPT)。您使用与将一些额外文件复制到构建目录时相同的参数。此外,必须在安装命令中指定TYPE或DESTINATION之一。TYPE参数指定通常放置在适当位置的一般文件类型。在Linux系统上,TYPEDATA通常是/usr/local/share或/usr/share,除非用户定义了另一个位置。这是CMake等优秀构建系统的强大功能之一。您不必担心文件的确切位置,因为您知道用户可以更改CMake的首选默认值,CMake将构建代码以正常工作。运行CMake您可以通过多种方式在CMake中执行命令,您可以在终端或交互式程序中执行命令,也可以使用其图形界面(GUI)。我更喜欢使用终端命令,但我也喜欢使用其他一些方法(比在Makefile中查找那些晦涩难懂的变量然后修改它们更好)。编译过开源C++项目的任何人都熟悉的第一步是创建一个构建目录,切换到该目录,然后运行??cmake..命令。我是一个懒惰的打字员,所以我将构建目录命名为b,但您可以使用最有效的任何名称:$mkdirb$cdb$cmake..--C编译器标识是GNU11.1.1--CXX编译器标识是GNU11.1.1——检测C编译器ABI信息——检测C编译器ABI信息——完成——检查工作C编译器:/usr/bin/cc——跳过——检测C编译特性——检测C编译特性——done--DetectingCXXcompilerABIinfo--DetectingCXXcompilerABIinfo-done--检查工作的CXX编译器:/usr/bin/c++-skipped--DetectingCXXcompilefeatures--DetectingCXXcompilefeatures-done--Configuringdone--生成done--构建文件已写入:/var/home/seth/demo-hello/b$这或多或少等同于经典的./configure;制作;进行安装。/配置。查看您的构建目录,CMake已为您生成了几个新文件,以使您的项目更加完整。这会生成CMake数据文件、一个常规Makefile(这是一个免费提供的247行文件,但对于更复杂的项目,行数更多),以及一个用于编译数据的任意非Hello-1.0目录。$lsCMakeCache.txtCMakeFilesMakefileHello-1.0cmake_install.cmake接下来就可以build了。您可以使用CMake的--build选项来执行此操作,使用当前构建目录作为源目录。$cmake--build.ScanningdependenciesoftargetHello[50%]BuildingCobjectCMakeFiles/Hello.dir/hello.c.o[100%]LinkingCexecutableHello[100%]BuilttargetHello或者你可以运行make命令。这将读取CMake生成的Makefile。在这个例子中,make的默认行为是从源程序hello.c生成一个目标文件。$makeScanningdependenciesoftargetHello[50%]BuildingCobjectCMakeFiles/Hello.dir/hello.c.o[100%]LinkingCexecutableHello[100%]BuilttargetHello$如您所料,Hello二进制可执行文件现在存在于当前构建目录。由于它是一个简单的独立应用程序,您可以运行它进行测试:$./HelloHelloopensource$最后,您可以使用--install选项安装它。由于我不希望我的简单“helloworld”应用程序实际安装在我的系统上,我设置了--prefix选项以将CMake的目标从根目录(/)重定向到/tmp目录的子文件夹。$cmake——安装。--prefix/tmp/hello/--安装配置:""--安装:/tmp/dist-hello/usr/local/bin/Hello--安装:/tmp/dist-hello/usr/local/share/Hello-1.0--安装:/tmp/dist-hello/usr/local/share/Hello-1.0/assets/file0--安装:/tmp/dist-hello/usr/local/share/Hello-1.0/assets/file1或者,您也可以运行makeinstall来调用Makefile安装操作。同样,为了避免在我的系统上安装演示程序,我在此示例中设置了DESTDIR变量,将安装目标重定向到/tmp的子目录:$mkdir/tmp/dist-hello$makeinstallDESTDIR=/tmp/dist-你好[100%]BuilttargetHelloInstalltheproject...--Installconfiguration:""--Installing:/tmp/dist-hello/usr/local/bin/Hello--Installing:/tmp/dist-hello/usr/local/share/Hello-1.0--安装:/tmp/dist-hello/usr/local/share/Hello-1.0/assets/file0--安装:/tmp/dist-hello/usr/local/share/Hello-1.0/assets/file1查看输出内容,确定其具体安装位置。该程序已经安装。快速自定义CMake的安装前缀(由CMAKE_INSTALL_PREFIX变量指定)默认在/usr/local,但所有CMake变量都可以通过在运行cmake命令时添加-D选项来更改。$cmake-DCMAKE_INSTALL_PREFIX=/usr..$makeinstallDESTDIR=/tmp/dist-hello$makeinstallDESTDIR=/tmp/dist-hello[100%]BuilttargetHelloInstalltheproject...--安装配置:""--安装:/tmp/dist-hello/usr/bin/Hello--安装:/tmp/dist-hello/usr/share/Hello-1.0--安装:/tmp/dist-hello/usr/share/Hello-1.0/assets/file0--Installing:/tmp/dist-hello/usr/share/Hello-1.0/assets/file1CMake使用的所有变量都可以这样修改。交互式CMakeCMake的交互模式是配置安装环境的一种友好且有用的方式。用户要了解项目可能使用的所有CMake变量需要做很多工作,因此CMake交互式界面是他们发现自定义选项而无需查看Makefile和CMakeList的简便方法。要调用这个交互式CMake,请使用ccmake命令,这个简单的项目中没有太多内容。但对于像Rosegarden这样的大型项目,它将非常有用。更多关于RosegardenCMake的知识CMake的知识还有很多需要学习。作为一名开发人员,我非常喜欢它简洁的语法、详尽的文档、可扩展性和便利性。作为用户,我非常喜欢CMake友好实用的错误消息及其用户界面。如果您的项目尚未开始使用构建系统,请了解CMake。您和将来尝试打包您的应用程序的任何其他人都不会后悔。