招魂2冲贬顿中字冲百度云资源免费在线播放-星辰影院
9. 烟台长岛 —— 山东省烟台市长岛县
2024年12月22日,前面说了,其实明初尚有初心时,为了尽量稳定阶级,对民间的衣食住行,都进行了有条可依的明确规定(本意减少奢靡的攀比)。
招魂2冲贬顿中字冲百度云资源免费在线播放-星辰影院
CMake构建Makefile深度解析:从底层原理到复杂项目2023-06-10 21:24·linux技术栈一、CMake构建后的项目结构解析(Analysis of the Project Structure After CMake Build)1.1 CMake构建后的目录结构(Directory Structure After CMake Build)CMake构建完成后会在项目的根目录下生成一个名为build的目录这个目录是CMake构建过程中所有中间文件和最终生成的目标文件的存放地下面我们将详细解析这个目录的结构首先我们来看一下build目录的一级子目录:CMakeFiles:这个目录中存放的是CMake在构建过程中生成的临时文件包括编译器检查的结果、Find模块(Find Modules)查找的结果等这些文件主要用于CMake自身的需求一般情况下我们不需要关注这个目录的内容Testing:如果你的项目中包含了CTest测试那么这个目录将会被生成它包含了所有CTest测试的结果bin:这个目录中包含了所有的可执行文件(Executable Files)如果你的CMake项目中包含了多个可执行文件那么它们都会被放在这个目录中lib:这个目录中包含了所有的库文件(Library Files)无论是静态库(Static Libraries)还是动态库(Dynamic Libraries)都会被放在这个目录中接下来我们再深入到CMakeFiles目录中看一下它的二级子目录:project.dir:这个目录中包含了项目构建过程中的临时文件如.o文件和.d文件这些文件是编译器在编译源代码时生成的CMakeOutput.log:这个文件记录了CMake在配置过程中的输出信息包括编译器检查的结果、Find模块查找的结果等CMakeError.log:这个文件记录了CMake在配置过程中遇到的错误信息以上就是CMake构建后的目录结构的基本情况在实际的项目中可能会根据项目的具体需求生成更多的子目录和文件但是这些基本的目录和文件是你在任何一个使用CMake构建的项目中都能看到的1.2 构建生成的文件类型及其作用(Types of Files Generated by the Build and Their Functions)CMake构建过程中会生成多种类型的文件每种文件都有其特定的作用下面我们将详细解析这些文件的类型和作用CMakeFiles目录:这个目录中存放的是CMake在构建过程中生成的临时文件包括编译器检查的结果、Find模块(Find Modules)查找的结果等这些文件主要用于CMake自身的需求一般情况下我们不需要关注这个目录的内容project.dir目录:这个目录中包含了项目构建过程中的临时文件如.o文件和.d文件这些文件是编译器在编译源代码时生成的CMakeOutput.log文件:这个文件记录了CMake在配置过程中的输出信息包括编译器检查的结果、Find模块查找的结果等CMakeError.log文件:这个文件记录了CMake在配置过程中遇到的错误信息Testing目录:如果你的项目中包含了CTest测试那么这个目录将会被生成它包含了所有CTest测试的结果bin目录:这个目录中包含了所有的可执行文件(Executable Files)如果你的CMake项目中包含了多个可执行文件那么它们都会被放在这个目录中lib目录:这个目录中包含了所有的库文件(Library Files)无论是静态库(Static Libraries)还是动态库(Dynamic Libraries)都会被放在这个目录中以上就是CMake构建过程中生成的主要文件类型及其作用理解这些文件的作用可以帮助我们更好地理解CMake的构建过程1.3 CMakeLists.txt与生成的Makefile的关系(The Relationship Between CMakeLists.txt and the Generated Makefile)在CMake构建系统中CMakeLists.txt文件和生成的Makefile文件之间存在着密切的关系下面我们将详细解析这种关系CMakeLists.txt是CMake构建系统的核心文件它定义了项目的构建规则和依赖关系在执行CMake命令时CMake会读取CMakeLists.txt文件解析其中的构建规则和依赖关系然后生成相应的Makefile文件Makefile文件是由CMake根据CMakeLists.txt文件生成的它是Make构建工具可以直接读取的构建脚本Makefile文件中包含了具体的编译命令和链接命令以及源文件和目标文件之间的依赖关系在一个CMake项目中通常会有多个CMakeLists.txt文件每个目录下都可以有一个CMakeLists.txt文件这些CMakeLists.txt文件中定义的构建规则和依赖关系会被CMake合并到一起生成一个或多个Makefile文件如果一个CMake项目中只有一个CMakeLists.txt文件那么CMake会生成一个Makefile文件如果一个CMake项目中有多个CMakeLists.txt文件那么CMake会在每个CMakeLists.txt文件所在的目录下生成一个Makefile文件这些Makefile文件中顶层目录下的Makefile文件是主Makefile文件它会调用其他目录下的Makefile文件总的来说CMakeLists.txt文件和生成的Makefile文件之间的关系是:CMakeLists.txt文件定义了项目的构建规则和依赖关系CMake根据CMakeLists.txt文件生成Makefile文件然后Make根据Makefile文件执行具体的构建任务相关视频推荐从程序编译到掌握 cmake 项目构建工具2023就业行情一片惨淡如何拿到自己理想的offer2023年最新技术图谱c++后端的8个技术维度助力你快速成为大牛需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++Linuxgolang技术NginxZeroMQMySQLRedisfastdfsMongoDBZK流媒体CDNP2PK8SDockerTCP/IP协程DPDKffmpeg等)免费分享二、深入理解CMake生成的Makefile2.1 Makefile的基本结构和原理Makefile是GNU make工具的配置文件它定义了一组规则来指定哪些文件需要被更新以及如何更新这些文件在C++项目中Makefile通常用于编译源代码并生成可执行文件Makefile的基本结构包括三个部分:目标(Target)、依赖(Dependencies)和命令(Commands)目标(Target):这是需要生成的文件名它可以是一个对象文件(Object File)也可以是一个可执行文件(Executable File)依赖(Dependencies):这些是目标文件需要的源文件如果任何一个依赖文件比目标文件更新那么目标文件就需要被重新生成命令(Commands):这些是生成目标文件所需要执行的shell命令这些命令必须以Tab字符开始下面是一个简单的Makefile示例:target: dependencies commands在CMake中CMakeLists.txt文件中的指令会被转换为Makefile中的目标、依赖和命令例如add_executable指令会生成一个目标target_link_libraries指令会生成依赖而实际的编译和链接命令则由CMake自动生成理解Makefile的基本结构和原理对于深入理解CMake生成的Makefile有着重要的作用在下一节中我们将进一步探讨多个CMakeLists.txt生成的Makefile的解析2.2 多个CMakeLists.txt生成的Makefile解析在大型的C++项目中通常会有多个CMakeLists.txt文件每个目录下都有一个这种结构有助于保持项目的模块化使得每个部分可以独立地被构建和测试当运行CMake命令时它会首先查找根目录下的CMakeLists.txt文件然后递归地处理每个子目录中的CMakeLists.txt文件每个CMakeLists.txt文件都会生成一个对应的Makefile在这个过程中CMake会处理CMakeLists.txt文件中的指令如add_executable、add_library、target_link_libraries等并将这些指令转换为Makefile中的目标、依赖和命令例如如果我们有如下的目录结构:project/├── CMakeLists.txt├── main.cpp└── module/ ├── CMakeLists.txt └── module.cpp在根目录的CMakeLists.txt文件中我们可能会有如下的指令:add_executable(main main.cpp)add_subdirectory(module)target_link_libraries(main module)在module目录的CMakeLists.txt文件中我们可能会有如下的指令:add_library(module module.cpp)在这个例子中CMake会生成两个Makefile一个在project目录一个在project/module目录在project目录的Makefile中会有一个名为main的目标它依赖于main.cpp和module目录的Makefile中生成的库在project/module目录的Makefile中会有一个名为module的目标它依赖于module.cpp通过这种方式CMake使得每个子目录可以独立地被构建同时也保证了整个项目的构建顺序2.3 CMake与Makefile的对应关系CMake是一个跨平台的构建系统它的主要任务是根据用户的需求生成适当的Makefile文件CMake通过读取CMakeLists.txt文件来了解用户的需求然后生成对应的Makefile文件在CMake与Makefile之间存在一种明确的对应关系CMakeLists.txt文件中的每一条指令都会在生成的Makefile文件中有一个对应的表现下面我们来看一些常见的CMake指令以及它们在Makefile中的对应关系:add_executable:这个CMake指令用于定义一个可执行文件的目标在生成的Makefile中这个目标会被定义为一个规则规则的目标是可执行文件依赖项是源文件命令是编译命令add_library:这个CMake指令用于定义一个库文件的目标在生成的Makefile中这个目标也会被定义为一个规则规则的目标是库文件依赖项是源文件命令是编译命令target_link_libraries:这个CMake指令用于定义目标的链接库在生成的Makefile中这个指令会影响到链接命令链接命令会包含对应的库文件add_subdirectory:这个CMake指令用于添加子目录在生成的Makefile中这个指令会导致生成一个新的Makefile文件在对应的子目录中通过理解CMake与Makefile的对应关系我们可以更好地理解CMake的工作原理以及如何编写有效的CMakeLists.txt文件在下一章节中我们将进一步探讨CMake构建过程的底层原理三、CMake构建过程的底层原理(Underlying Principles of the CMake Build Process)3.1 CMake构建过程的基本流程(Basic Flow of the CMake Build Process)CMake的构建过程可以分为三个主要步骤:配置(Configuration)、生成(Generation)和构建(Build)下面我们将详细解析每个步骤1、配置(Configuration)配置阶段是CMake解析CMakeLists.txt文件的过程在这个阶段CMake会读取CMakeLists.txt文件并执行其中的命令这些命令主要用于检查系统环境(例如编译器、库等)设置构建选项以及定义构建目标(例如库、可执行文件等)CMakeLists.txt文件是CMake的核心它定义了项目的构建规则和依赖关系每个目录(包括子目录)中都可以有一个CMakeLists.txt文件在配置阶段CMake会从顶层目录的CMakeLists.txt文件开始递归地处理每个子目录中的CMakeLists.txt文件2、生成(Generation)生成阶段是CMake根据配置阶段的结果生成实际的构建文件的过程这些构建文件通常是Makefile文件但也可以是其他类型的构建文件例如Ninja构建文件或者Visual Studio项目文件这取决于你选择的构建工具在生成阶段CMake会将CMakeLists.txt文件中定义的构建规则和依赖关系转换为构建工具可以理解的形式例如如果你选择的构建工具是MakeCMake会生成Makefile文件每个目录(包括子目录)中都会生成一个Makefile文件3、构建(Build)构建阶段是使用构建工具(例如Make、Ninja或Visual Studio)根据生成的构建文件编译源代码并链接生成目标文件的过程在构建阶段构建工具会读取生成的构建文件按照其中定义的规则和依赖关系执行实际的编译和链接操作构建工具会自动处理依赖关系确保在编译和链接一个目标文件之前其所有依赖的目标文件都已经被正确地编译和链接以上就是CMake构建过程的基本流程在理解了这个流程之后我们就可以更深入地探讨CMake如何生成Makefile以及CMake构建过程中的关键步骤了3.2 CMake如何生成Makefile(How CMake Generates Makefile)CMake生成Makefile的过程是在其生成阶段完成的这个过程主要涉及到CMake的核心组件——生成器(Generator)下面我们将详细解析这个过程1、选择生成器(Selecting a Generator)在CMake的生成阶段开始时首先需要选择一个生成器生成器是CMake的一个核心组件它负责将CMakeLists.txt文件中的构建规则和依赖关系转换为特定构建工具可以理解的形式CMake支持多种生成器可以生成Makefile文件也可以生成Ninja构建文件或者Visual Studio项目文件等选择生成器的方式通常是在运行CMake命令时通过-G选项指定例如如果你想生成Unix风格的Makefile文件可以使用"Unix Makefiles"生成器命令如下:cmake -G "Unix Makefiles"如果没有指定生成器CMake会选择一个默认的生成器这个默认的生成器通常是根据你的系统环境自动选择的2、生成Makefile选择好生成器之后CMake就会开始生成Makefile文件在这个过程中CMake会遍历项目中的每个目录(包括子目录)对每个目录中的CMakeLists.txt文件进行处理对于每个CMakeLists.txt文件CMake会解析其中的命令根据这些命令定义的构建规则和依赖关系生成对应的Makefile文件每个CMakeLists.txt文件都会生成一个Makefile文件这个Makefile文件中包含了编译和链接该目录中的目标文件所需要的规则和命令在生成Makefile文件时CMake会自动处理目标文件之间的依赖关系如果一个目标文件依赖于其他目标文件CMake会在生成的Makefile文件中为这个目标文件添加相应的依赖规则以上就是CMake如何生成Makefile的过程理解了这个过程我们就可以更好地理解CMake构建过程中的关键步骤以及CMake与Makefile之间的关系了3.3 CMake构建过程中的关键步骤(Key Steps in the CMake Build Process)CMake构建过程中的关键步骤主要包括以下几个方面:1、解析CMakeLists.txt文件(Parsing CMakeLists.txt Files)这是CMake构建过程的第一步也是最关键的一步CMakeLists.txt文件是CMake的核心它定义了项目的构建规则和依赖关系CMake需要解析这个文件以获取构建项目所需的所有信息2、检查系统环境(Checking System Environment)在CMakeLists.txt文件中通常会包含一些检查系统环境的命令例如检查编译器、库等这些命令在CMake构建过程中会被执行以确保系统环境满足项目的构建需求3、生成构建文件(Generating Build Files)CMake的主要任务是生成构建文件这些构建文件通常是Makefile文件但也可以是其他类型的构建文件例如Ninja构建文件或者Visual Studio项目文件这取决于你选择的构建工具生成构建文件的过程是CMake构建过程中的一个关键步骤4、执行构建命令(Executing Build Commands)在生成了构建文件之后就可以开始执行构建命令了这些构建命令通常是由构建工具(例如Make、Ninja或Visual Studio)执行的构建工具会根据构建文件中定义的规则和命令编译源代码并链接生成目标文件以上就是CMake构建过程中的关键步骤理解了这些步骤我们就可以更好地理解CMake的工作原理以及如何使用CMake进行项目构建了四、CMake在复杂项目中的应用(Application of CMake in Complex Projects)4.1 复杂项目中的CMake构建策略(CMake Build Strategy in Complex Projects)在复杂的项目中CMake的构建策略需要更加精细和周全我们需要考虑到项目的模块化依赖关系以及可能存在的平台差异以下是一些在复杂项目中使用CMake的策略和建议4.1.1 模块化的CMakeLists.txt(Modularized CMakeLists.txt)在大型项目中我们通常会看到项目被划分为多个模块或子项目每个模块都有自己的源代码和依赖这种情况下我们可以为每个模块创建一个CMakeLists.txt文件这样可以使构建过程更加清晰也方便我们管理每个模块的构建规则例如我们可以在每个模块的目录下创建一个CMakeLists.txt文件然后在项目的顶级目录下的CMakeLists.txt文件中使用add_subdirectory()命令来添加这些模块4.1.2 管理依赖关系(Managing Dependencies)在复杂的项目中不同的模块可能会有各种依赖关系CMake提供了一些命令来帮助我们管理这些依赖关系例如target_link_libraries()命令可以用来指定一个目标需要链接的库在处理依赖关系时我们需要注意的一个重要原则是:尽量让依赖关系明确和直观这意味着如果一个模块A依赖于模块B那么在模块A的CMakeLists.txt文件中我们应该明确地指出这个依赖关系4.1.3 处理平台差异(Handling Platform Differences)在跨平台的项目中我们可能需要处理不同平台的差异CMake提供了一些变量和命令来帮助我们处理这些差异例如CMAKE_SYSTEM_NAME变量可以用来检测当前的操作系统if()命令可以用来根据不同的条件执行不同的命令在处理平台差异时我们应该尽量避免硬编码特定平台的信息相反我们应该尽可能地使用CMake提供的变量和命令这样可以使我们的CMakeLists.txt文件更加通用和可维护以上就是在复杂项目中使用CMake的一些策略和建议在实际应用中我们还需要根据项目的具体情况和需求来调整和优化我们的CMake构建策略4.1.4 使用现代CMake命令(Using Modern CMake Commands)现代的CMake版本提供了一些新的命令和特性这些命令和特性可以使我们的CMakeLists.txt文件更加简洁和易于理解例如target_include_directories()命令可以用来指定一个目标的头文件搜索路径这比使用旧的include_directories()命令更加灵活和直观在使用现代CMake命令时我们需要注意的一个重要原则是:尽量使用目标属性(target properties)而不是全局变量(global variables)这是因为目标属性可以使我们的CMakeLists.txt文件更加模块化也更容易理解和维护4.1.5 利用CMake的脚本功能(Leveraging CMake’s Scripting Capabilities)CMake不仅是一个构建工具它也是一种脚本语言我们可以利用CMake的脚本功能来实现一些复杂的构建逻辑例如我们可以使用if()、foreach()等命令来编写循环和条件语句在使用CMake的脚本功能时我们需要注意的一个重要原则是:尽量避免过度复杂的脚本逻辑过度复杂的脚本逻辑可能会使我们的CMakeLists.txt文件难以理解和维护相反我们应该尽可能地使用CMake提供的命令和特性这样可以使我们的CMakeLists.txt文件更加简洁和易于理解以上就是在复杂项目中使用CMake的一些策略和建议在实际应用中我们还需要根据项目的具体情况和需求来调整和优化我们的CMake构建策略4.2 多个CMakeLists.txt在复杂项目中的管理(Management of Multiple CMakeLists.txt in Complex Projects)在大型的复杂项目中我们通常会有多个CMakeLists.txt文件每个子目录下都可能有一个这些CMakeLists.txt文件共同定义了整个项目的构建规则管理这些CMakeLists.txt文件是一个重要的任务以下是一些策略和建议4.2.1 模块化管理(Modular Management)每个CMakeLists.txt文件应该只负责管理其所在目录下的源代码和依赖这样可以使每个CMakeLists.txt文件的内容保持简洁也方便我们理解和维护每个模块的构建规则4.2.2 统一的构建规则(Unified Build Rules)尽管每个CMakeLists.txt文件都有其自己的构建规则但我们应该尽量使这些构建规则保持一致这样可以使我们的构建过程更加可预测也方便我们管理和维护我们的构建规则4.2.3 利用CMake的包管理功能(Leveraging CMake’s Package Management Features)CMake提供了一些命令和特性来帮助我们管理项目的依赖例如find_package()命令可以用来查找和加载外部库我们应该尽量利用这些命令和特性这样可以使我们的CMakeLists.txt文件更加简洁也可以避免一些常见的依赖问题4.2.4 避免硬编码路径(Avoid Hard-Coded Paths)在CMakeLists.txt文件中我们应该尽量避免硬编码路径硬编码的路径可能会使我们的构建过程依赖于特定的目录结构这会降低我们的构建规则的可移植性相反我们应该尽可能地使用CMake提供的变量和命令来指定路径这样可以使我们的CMakeLists.txt文件更加通用和可维护以上就是在复杂项目中管理多个CMakeLists.txt文件的一些策略和建议在实际应用中我们还需要根据项目的具体情况和需求来调整和优化我们的管理策略4.3 CMake在大型项目中的最佳实践(Best Practices of CMake in Large Projects)在大型项目中使用CMake我们需要遵循一些最佳实践以确保构建过程的高效、稳定和可维护以下是一些在大型项目中使用CMake的最佳实践4.3.1 使用最新版本的CMake(Use the Latest Version of CMake)尽可能使用最新版本的CMake新版本的CMake通常会包含一些新的特性和改进这些特性和改进可能会使我们的构建过程更加高效和稳定此外新版本的CMake也可能会修复一些旧版本中的问题和缺陷4.3.2 避免在CMakeLists.txt文件中修改编译器标志(Avoid Modifying Compiler Flags in CMakeLists.txt Files)在CMakeLists.txt文件中直接修改编译器标志可能会导致一些问题例如这可能会覆盖用户在命令行中指定的编译器标志或者导致在不同平台上的构建行为不一致相反我们应该使用CMake提供的命令和特性来管理编译器标志例如target_compile_options()命令4.3.3 使用CMake的测试功能(Use CMake’s Testing Features)CMake提供了一些命令和特性来帮助我们管理和运行测试例如enable_testing()命令和add_test()命令我们应该尽量利用这些命令和特性这样可以使我们的测试过程更加自动化和可控4.3.4 使用CMake的安装功能(Use CMake’s Installation Features)CMake提供了一些命令和特性来帮助我们管理项目的安装过程例如install()命令我们应该尽量利用这些命令和特性这样可以使我们的安装过程更加自动化和可控以上就是在大型项目中使用CMake的一些最佳实践在实际应用中我们还需要根据项目的具体情况和需求来调整和优化我们的构建过程五、CMake生成的Makefile详解5.1 CMake如何翻译生成Makefile在深入理解CMake如何翻译生成Makefile之前我们首先来看一下CMake与Makefile的关系如下图所示CMake通过解析CMakeLists.txt文件生成对应的Makefile然后执行Makefile进行编译链接最后生成可执行文件CMake的主要工作就是解析CMakeLists.txt文件并将其翻译成MakefileCMakeLists.txt文件是CMake的核心它定义了项目的构建规则包括项目的目录结构、需要编译的源文件、依赖关系、编译参数等信息CMake通过读取CMakeLists.txt文件理解这些构建规则然后生成对应的Makefile在生成Makefile的过程中CMake会进行一系列的翻译操作这些操作主要包括:解析CMakeLists.txt文件:CMake首先会读取CMakeLists.txt文件解析其中的命令和参数理解项目的构建规则生成Makefile:根据解析得到的构建规则CMake会生成对应的Makefile这个Makefile包含了所有的编译链接命令以及源文件和目标文件之间的依赖关系处理依赖关系:在生成Makefile的过程中CMake会处理源文件之间的依赖关系如果一个源文件依赖于另一个源文件那么在Makefile中这个源文件的编译命令就会依赖于另一个源文件的编译命令设置编译参数:CMake还会设置Makefile中的编译参数包括编译器选项、链接器选项等这些参数会影响到编译链接的过程以上就是CMake如何翻译生成Makefile的基本过程在后续的小节中我们将深入探讨Makefile的详细结构和原理以及如何在CMake中使用外部Makefile等高级话题5.2 Makefile的详细解析Makefile是由make工具执行的一种脚本文件它描述了一组目标(target)以及构建这些目标所需的规则(rule)在CMake生成的Makefile中每一个目标通常对应一个或多个源文件而规则则描述了如何从这些源文件生成目标以下是一个简单的Makefile示例:all: hellohello: main.o function.o g++ main.o function.o -o hellomain.o: main.cpp g++ -c main.cppfunction.o: function.cpp g++ -c function.cppclean: rm *.o hello在这个示例中all、hello、main.o、function.o和clean都是目标而每个目标后面的内容则是构建该目标的规则例如hello目标的规则是g++ main.o function.o -o hello这条规则告诉make工具如何从main.o和function.o这两个源文件生成hello这个目标在CMake生成的Makefile中这些规则会更加复杂因为它们需要处理项目中的依赖关系、编译参数等问题但是基本的结构和原理是相同的:每个目标都有一组规则这些规则描述了如何从源文件生成目标5.3 CMake如何翻译生成Makefile当然可以让我们更深入地探讨一些CMake命令和生成的Makefile之间的关系add_executable:这个命令在CMake中用于定义一个目标可执行文件例如add_executable(hello main.cpp)会定义一个名为hello的目标这个目标由main.cpp这个源文件生成在生成的Makefile中这个命令会被翻译成一个编译命令如$(CXX) $(CXXFLAGS) -o hello main.cpp这条命令告诉make工具使用C++编译器(( C X X ) )和编译选项( (CXX))和编译选项((CXX))和编译选项((CXXFLAGS))来编译main.cpp并将输出文件命名为helloadd_library:这个命令在CMake中用于定义一个目标库文件例如add_library(mylib mylib.cpp)会定义一个名为mylib的目标这个目标由mylib.cpp这个源文件生成在生成的Makefile中这个命令会被翻译成一个库生成命令如$(AR) $(ARFLAGS) mylib mylib.cpp这条命令告诉make工具使用库生成器(( A R ) )和库生成选项( (AR))和库生成选项((AR))和库生成选项((ARFLAGS))来生成mylib这个库target_link_libraries:这个命令在CMake中用于定义目标的链接库例如target_link_libraries(hello mylib)会告诉CMakehello这个目标需要链接mylib这个库在生成的Makefile中这个命令会被翻译成一个链接命令如$(CXX) $(LDFLAGS) -o hello main.cpp -lmylib这条命令告诉make工具在链接hello时需要链接mylib这个库以上就是CMake命令和生成的Makefile之间的一些基本关系在实际的项目中这些关系可能会更复杂因为CMake和Makefile都是非常强大的工具它们提供了许多高级功能来处理项目中的各种问题但是理解这些基本关系是理解CMake和Makefile的关键5.4 CMake生成的Makefile中的常见问题及解决方案在使用CMake生成Makefile的过程中可能会遇到一些常见的问题这些问题可能涉及到Makefile的生成、执行、以及依赖关系的处理等方面下面我们将详细介绍这些问题以及相应的解决方案Makefile生成失败:这是一个比较常见的问题通常是由于CMakeLists.txt文件中的错误导致的解决这个问题的方法是检查CMakeLists.txt文件确保其中的命令和参数都是正确的Makefile执行错误:这个问题通常是由于Makefile中的命令错误导致的解决这个问题的方法是检查Makefile确保其中的编译链接命令都是正确的依赖关系处理错误:这个问题通常是由于CMake处理源文件之间的依赖关系时出错导致的解决这个问题的方法是检查CMakeLists.txt文件确保其中的依赖关系都是正确的以上就是在使用CMake生成Makefile时可能遇到的一些常见问题以及相应的解决方案在实际使用中可能还会遇到其他的问题这时候需要根据具体的错误信息进行相应的排查和解决六、CMake与外部Makefile的交互(Interaction Between CMake and External Makefile)6.1 如何在CMake中使用外部Makefile(How to Use External Makefile in CMake)在CMake中使用外部Makefile我们可以使用add_custom_command和add_custom_target这两个命令这两个命令可以用来执行一些自定义的构建规则比如运行一个脚本创建一个文件或者运行一个Makefile6.1.1 add_custom_commandadd_custom_command命令用于定义如何生成一个文件这个命令有很多参数但是最常用的是OUTPUTCOMMAND和DEPENDSOUTPUT参数用于指定生成的文件COMMAND参数用于指定生成文件的命令可以是任何shell命令DEPENDS参数用于指定生成文件所依赖的文件例如我们可以使用以下命令来运行一个外部Makefile:add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated_file COMMAND make -C ${CMAKE_CURRENT_SOURCE_DIR}/external_project DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/external_project/Makefile)这个命令表示如果generated_file不存在或者external_project/Makefile有任何改动那么就会执行make -C external_project命令来生成generated_file6.1.2 add_custom_target然而add_custom_command只有在其输出文件被其他目标使用时才会被执行如果我们想要在每次构建时都执行某个命令那么我们需要使用add_custom_target命令add_custom_target命令用于定义一个自定义的目标这个目标不会生成任何文件也不会在构建时自动被执行我们需要手动执行这个目标或者将它添加为其他目标的依赖例如我们可以使用以下命令来定义一个运行外部Makefile的目标:add_custom_target( run_external_makefile COMMAND make -C ${CMAKE_CURRENT_SOURCE_DIR}/external_project)这个命令定义了一个名为run_external_makefile的目标我们可以使用make run_external_makefile命令来手动执行这个目标如果我们想要在每次构建时都执行这个目标那么我们可以将它添加为其他目标的依赖例如我们可以使用以下命令来将run_external_makefile添加为my_target的依赖:add_dependencies(my_target run_external_makefile)这样每次构建my_target时都会先执行run_external_makefile目标以上就是如何在CMake中使用外部Makefile的基本方法在实际使用中我们可能需要根据具体的需求来调整这些命令的参数6.1.3 add_custom_command的其他参数除了OUTPUTCOMMAND和DEPENDS参数外add_custom_command命令还有一些其他的参数可以用来控制命令的行为WORKING_DIRECTORY参数用于指定命令的工作目录如果不指定这个参数那么命令的工作目录就是当前的构建目录COMMENT参数用于指定一个注释这个注释会在命令执行时显示在控制台上VERBATIM参数用于控制命令的参数是否需要转义如果设置为TRUE那么命令的参数就会被转义这样就可以安全地处理包含特殊字符的参数例如我们可以使用以下命令来运行一个外部Makefile并显示一个注释:add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated_file COMMAND make -C ${CMAKE_CURRENT_SOURCE_DIR}/external_project DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/external_project/Makefile WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Running external Makefile" VERBATIM)这个命令表示如果generated_file不存在或者external_project/Makefile有任何改动那么就会在${CMAKE_CURRENT_BINARY_DIR}目录下执行make -C external_project命令来生成generated_file并显示"Running external Makefile"的注释以上就是在CMake中使用外部Makefile的基本方法在实际使用中我们可能需要根据具体的需求来调整这些命令的参数6.2 外部Makefile如何影响CMake生成的Makefile(How External Makefile Affects Makefile Generated by CMake)在CMake中我们可以通过add_custom_command或add_custom_target命令来插入外部Makefile从而影响CMake生成的Makefile下面是这个过程的示意图:编辑添加图片注释不超过 140 字(可选)在这个过程中CMake首先解析CMakeLists.txt文件生成CMakeCache.txt文件然后CMake根据CMakeCache.txt文件生成Makefile在生成Makefile的过程中CMake会执行add_custom_command或add_custom_target命令插入外部Makefile插入外部Makefile的主要目的是为了增加一些自定义的构建规则例如我们可能需要在构建过程中执行一些特殊的命令或者生成一些特殊的文件通过插入外部Makefile我们可以在CMake的构建过程中执行这些自定义的构建规则然而插入外部Makefile也可能会带来一些问题例如如果外部Makefile中的构建规则与CMake生成的构建规则冲突那么可能会导致构建失败因此在插入外部Makefile时我们需要确保外部Makefile中的构建规则与CMake生成的构建规则是兼容的在实际使用中我们可能需要根据具体的需求来调整插入外部Makefile的方式例如我们可以通过修改add_custom_command或add_custom_target命令的参数来控制外部Makefile的插入位置或者控制外部Makefile的执行方式6.3 高级技巧:自由控制CMake生成规则(Advanced Techniques: Freely Control CMake Generation Rules)CMake提供了一系列的命令可以用来自由控制生成规则这些命令可以用来定义自定义的目标添加依赖关系设置编译选项等等下面我们将介绍一些高级的技巧可以帮助你更好地控制CMake的生成规则6.3.1 自定义目标(Custom Targets)在CMake中我们可以使用add_custom_target命令来定义一个自定义的目标这个目标不会生成任何文件也不会在构建时自动被执行我们需要手动执行这个目标或者将它添加为其他目标的依赖例如我们可以使用以下命令来定义一个运行外部Makefile的目标:add_custom_target( run_external_makefile COMMAND make -C ${CMAKE_CURRENT_SOURCE_DIR}/external_project)这个命令定义了一个名为run_external_makefile的目标我们可以使用make run_external_makefile命令来手动执行这个目标6.3.2 添加依赖关系(Adding Dependencies)在CMake中我们可以使用add_dependencies命令来添加目标之间的依赖关系这个命令接受两个或更多的参数第一个参数是目标后面的参数是它所依赖的目标例如我们可以使用以下命令来将run_external_makefile添加为my_target的依赖:add_dependencies(my_target run_external_makefile)这样每次构建my_target时都会先执行run_external_makefile目标6.3.3 设置编译选项(Setting Compilation Options)在CMake中我们可以使用target_compile_options命令来设置目标的编译选项这个命令接受两个参数第一个参数是目标第二个参数是编译选项例如我们可以使用以下命令来为my_target设置编译选项:target_compile_options(my_target PRIVATE -Wall -Wextra)这个命令会为my_target添加-Wall和-Wextra这两个编译选项以上就是在CMake中自由控制生成规则的一些高级技巧在实际使用中我们可能需要根据具体的需求来调整这些命令的参数
其一,主流预期认为牛市中券商上涨和指数点位简单正相关,通过复盘可以发现并非如此简单。事实上,相较于上证的涨幅幅度和位置高低,上证指数所处的位置区间对券商的投资指引意义更重要,也即券商股是指数冲关的催化剂。原标题:独家| 浦发银行潘卫东离任 下一站为上海联交所