第2章:创建项目
Last updated
Was this helpful?
Last updated
Was this helpful?
如果没有构建系统,项目仅为文件的集合。CMake为构建项目制定了规则,首先需要有一个名为CMakeLists.txt的文件,该文件定义了构建什么、如何构建、运行哪些测试以及创建哪些包。该文件对整个项目进行了描述。CMake构建时,会将其解析为构建工具的项目文件。CMakeLists.txt是一个普通的文本文件,开发人员可以在文本编辑器或开发环境中对其进行编辑。这个文件的内容将在后面的章节中详细介绍。目前,知道CMake在设置和执行构建过程中要做的事情就足够了。
源目录和二进制目录概念是CMake的基础。源目录是CMakeLists.txt文件所在的文件夹,项目的源文件和构建所需的其他文件都组织在该位置下。源目录经常处于Git、Subversion或其他版本控制工具的控制之下。
二进制目录是生成构建内容的地方,通常称为构建目录。CMake通常使用“二进制目录”,但是在开发人员中,“构建目录”更常用。这本书倾向于后者,因为更直观。CMake所选择的构建工具(例如:make, Visual Studio等),CTest和CPack都在构建目录中创建。可执行文件、库、测试输出和包都在构建目录中创建。CMake还在构建目录中创建一个CMakeCache.txt的特殊文件,存储各种信息,以便在后续运行时重用。开发人员通常不需要关心CMakeCache.txt文件,后面的章节将详细讨论此文件。构建工具的项目文件(如Xcode或Visual Studio项目文件、makefile文件等)也是在构建目录中创建的,这些并不需要版本控制。CMakeLists.txt文件是项目的描述,生成的项目文件应该视为构建输出。
开发人员处理项目时,需要确定构建目录相对于源目录的位置。有两种方式:源内构建和源外构建。
源目录和构建目录可以相同,但不推荐这样做,这种方式称为源内构建。菜鸟开发人员通常会使用这种方法,因为看起来简单。然而,内源构建的主要问题在于,构建输出与源文件混杂在一起。这种缺乏分离的方式导致目录与各种文件和目录混杂在一起,使得项目管理变得非常困难,并有着构建输出覆盖源文件的风险。这种方式还使版本控制系统的工作难度增加,因为有许多由构建创建的文件,源代码控制工具必须知道要忽略哪些文件,或者在提交时手动排除这些文件。源内构建的另一个缺点是,清除所有构建输出并使用干净的源重新开发非常困难。由于这些原因,不推荐开发人员在任何的情况下使用源内构建方式进行构建。
更可取的方式是让源目录和构建目录不同,这称为源外构建。这使得源文件和构建输出完全分离,从而避免了混合问题。源外构建还有一个优势,开发人员可以为同一个源目录创建多个构建目录,这就允许使用不同的选项设置构建项目,比如:Debug和Release版本等等。
本书将使用源外构建,并遵循源目录和构建目录位于同级目录下的模式。构建目录将称为build(或其他)。目录结构类似如下方式:
一些开发人员将构建目录作为源目录的子目录,虽然也是源外构建,但是仍然带有内源构建的一些缺点。除非有很好的理由这样构造,否则建议将构建目录完全置于源目录之外。
选择好目录结构后,开发人员运行CMake,读入CMakeLists.txt文件并在构建目录中创建项目文件。开发人员通过选择生成器来选择要创建的项目文件。CMake支持一系列生成器,下表列出了常用的生成器。
一些生成器支持多种配置(如Debug、Release等),其允许开发者在不同的配置中进行选择,不必重新运行CMake,CMake很适合为Xcode和Visual Studio等IDE生成项目文件。对于不支持多配置的生成器,开发人员必须重新运行CMake在Debug、Release等之间切换构建方式。通常在与特定编译器(Qt Creator、KDevelop等)关联不那么紧密的IDE环境中,CMake都有很好的支持。
运行CMake最基本的方法是通过CMake命令行。调用它的最简单方法是将目录切换到build目录,并将生成器类型和源树位置的选项传递给CMake。例如:
如果省略了-G选项,CMake将根据平台选择默认的生成器类型。对于所有的生成器类型,CMake将执行测试并询问系统,以确定如何建立项目文件。这包括验证编译器是否工作、确定支持的编译器特性集和其他各种任务。在CMake完成验证之前,将记录各种信息,如以下的信息:
上面展示了项目文件的创建时的两个步骤:配置和生成。在配置阶段,CMake读取CMakeLists.txt文件,并构建整个项目的内部表示文件。完成这些之后,生成阶段将创建项目文件。配置和生成之间的区别对于CMake使用来说并不重要,在后面的章节中,配置和生成的分离就会变得很重要。第10章生成器表达式中会有更详细的介绍。
CMake完成运行时,在构建目录中保存一个CMakeCache.txt文件。CMake用这个文件保存信息,当CMake再次运行时,可以重用第一次的信息,加速项目的生成。如后面章节所述,还允许在运行间保存开发人员选项。CMake还有一个GUI应用程序,cmake-gui,可以作为CMake命令行工具的替代。GUI应用程序的介绍会在第5章详细介绍。
此时,项目文件已经可用,开发人员可以按照习惯的方式使用相应的构建工具。构建目录将包含必要的项目文件,这些文件可以加载到IDE中,通过命令行工具等等。当然,CMake也可以“代表"构建工具进行构建:
这种方式更适用于常用IDE的开发人员,--build
选项指向CMake项目生成的构建目录。对于多个配置,--config
选项指定要构建哪个配置,而单个配置生成器将忽略--config
选项,而依赖于执行CMake项目生成时的信息。第13章会详细介绍构建配置。--target
选项可以用来告诉构建工具要构建什么目标,如果省略该选项,将构建默认目标。
虽然开发人员通常会在开发中直接调用构建工具,但是通过cmake命令来调用构建工具,在自动化构建中会更有用。可以使用这种方式进行构建:
如果开发人员希望测试不同的生成器,要做的就是更改CMake选项-G
的参数,然后选择正确的构建工具。为了让cmake --build
正常工作,构建工具甚至不需要在用户的PATH环境变量中(第一次调用cmake时可能需要配置上)。
即使是第一次使用CMake,也建议养成将构建目录与源目录完全分离的习惯。尽早体验这种方式的好处,为了使用相同的源目录设置两个或更多不同的构建,一个版本可以配置成Debug,另一个版本可以配置成Release。另一种选择是为不同的构建目录使用不同的项目生成器,比如:Unix Makefiles和Xcode。这有助于确定特定构建工具的依赖,或检查生成器类型之间的不同编译器设置。
项目的早期集中使用特定类型的生成器非常简单,特别是开发人员不习惯编写跨平台软件时。然而,项目通常会有超出其初始范围的趋势时,项目通常需要支持其他平台,因此需要支持不同的生成器。定期使用与常用生成器不同的生成器检查构建,可以避免在使用特定生成器时的问题。这样,项目可以很好地使用任何新的生成器。一种测试策略是,在每个平台上使用默认生成器类型,以及另一种类型构建项目。Ninja生成器是后者最佳的选择,因为它支持的平台最广泛,还能进行非常高效的构建。如果在为项目编写构建脚本,通过cmake --build
调用构建工具,而非直接调用构建工具。无需对脚本进行修改,就可以轻松地在生成器之间进行切换。