CMake系列EP02: 构建可执行程序和库

2023-11-02 09:15

本文主要是介绍CMake系列EP02: 构建可执行程序和库,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • cmake --build
    • message命令
    • 切换生成器
      • 使用ninja构建项目
      • 切换生成器的工作原理
    • 构建和链接静态库和动态库
      • add_library命令
      • add_executable命令
      • 构建OBJECT类型的库
      • 条件编译
      • opion命令
      • option更多信息
    • 指定编译器
    • 构建类型
      • 切换构建类型:
    • 设置编译器选项
    • cmake调试
    • 设置语言标准
      • 另外一种写法
    • list命令

cmake --build

$ cmake -Bbuild .

该命令是跨平台的,使用了-H-B为CLI选项。-H表示当前目录中搜索根CMakeLists.txt文件。-Bbuild告诉CMake在一个名为build的目录中生成所有的文件。

➜ build cmake --build . --target help
The following are some of the valid targets for this Makefile:
… all (the default if no target is provided)
… clean
… depend
… rebuild_cache
… edit_cache
… helloworld

CMake生成的目标比构建可执行文件的目标要多。可以使用cmake --build . --target <target-name>语法,实现如下功能:

  • all(或Visual Studio generator中的ALL_BUILD)是默认目标,将在项目中构建所有目标。
  • clean,删除所有生成的文件。
  • rebuild_cache,将调用CMake为源文件生成依赖(如果有的话)。
  • edit_cache,这个目标允许直接编辑缓存。

对于更复杂的项目,通过测试阶段和安装规则,CMake将生成额外的目标:

  • test(或Visual Studio generator中的RUN_TESTS)将在CTest的帮助下运行测试套件。
  • install,将执行项目安装规则。
  • package,此目标将调用CPack为项目生成可分发的包。

message命令

message :为用户显示一条消息
语法:

message( [STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR]"message to display" ...)

可以用下述可选的关键字指定消息的类型:

  • (无) = 重要消息;
  • STATUS = 非重要消息;
  • WARNING = CMake 警告, 会继续执行;
  • AUTHOR_WARNING = CMake 警告 (dev), 会继续执行;
  • SEND_ERROR = CMake 错误, 继续执行,但是会跳过生成的步骤;
  • FATAL_ERROR = CMake 错误, 终止所有处理过程;

切换生成器

➜   cmake --help
GeneratorsThe following generators are available on this platform (* marks default):
* Unix Makefiles               = Generates standard UNIX makefiles.Ninja                        = Generates build.ninja files.Watcom WMake                 = Generates Watcom WMake makefiles.CodeBlocks - Ninja           = Generates CodeBlocks project files.CodeBlocks - Unix Makefiles  = Generates CodeBlocks project files.CodeLite - Ninja             = Generates CodeLite project files.CodeLite - Unix Makefiles    = Generates CodeLite project files.Sublime Text 2 - Ninja       = Generates Sublime Text 2 project files.Sublime Text 2 - Unix Makefiles= Generates Sublime Text 2 project files.Kate - Ninja                 = Generates Kate project files.Kate - Unix Makefiles        = Generates Kate project files.Eclipse CDT4 - Ninja         = Generates Eclipse CDT 4.0 project files.Eclipse CDT4 - Unix Makefiles= Generates Eclipse CDT 4.0 project files.

使用ninja构建项目

➜ cmake_tutorial mkdir -p build
➜ cmake_tutorial cd build
➜ build ls
➜ build cmake -G Ninja …
– The C compiler identification is GNU 4.8.5
– The CXX compiler identification is GNU 4.8.5
– Check for working C compiler: /usr/bin/cc
– Check for working C compiler: /usr/bin/cc – works
– Detecting C compiler ABI info
– Detecting C compiler ABI info - done
– Detecting C compile features
– Detecting C compile features - done
– Check for working CXX compiler: /usr/bin/c++
– Check for working CXX compiler: /usr/bin/c++ – works
– Detecting CXX compiler ABI info
– Detecting CXX compiler ABI info - done
– Detecting CXX compile features
– Detecting CXX compile features - done
– Configuring done
– Generating done
– Build files have been written to: /root/workspace/cmake_tutorial/build

构建项目

➜  build cmake --build . -j8
[2/2] Linking CXX executable EP01_helloworld/helloworld➜  build ls
build.ninja  CMakeCache.txt  CMakeFiles  cmake_install.cmake  EP01_helloworld  rules.ninja

切换生成器的工作原理

与前一个配置相比,每一步的输出没什么变化。每个生成器都有自己的文件集,所以编译步骤的输出和构建目录的内容是不同的:

  • build.ninjarules.ninja:包含Ninja的所有的构建语句和构建规则。
  • CMakeCache.txt :CMake会在这个文件中进行缓存,与生成器无关。
  • CMakeFiles:包含由CMake在配置期间生成的临时文件。
  • cmake_install.cmake:CMake脚本处理安装规则,并在安装时使用。

cmake --build .ninja命令封装在一个跨平台的接口中。

构建和链接静态库和动态库

add_library命令

在CMake中,add_library命令的基本语法如下:
add_library( <SHARED|STATIC|MODULE|INTERFACE> [source1] [source2…]) 其中, 是你要创建的库的名称, <SHARED|STATIC|MODULE|INTERFACE> 用于指定库的类型。什么都不指定,默认构建静态库。

add_executable命令

命令格式:
add_executable ( [ WIN32] [ MACOSX_BUNDLE] [ EXCLUDE_FROM_ALL] [source1] [source2 …])
add_executable ( IMPORTED [ GLOBAL ])
add_executable ( ALIAS )
使用指定的源文件来生成目标可执行文件。

示例:

add_library(message#STATICSHAREDmessage.hmessage.cpp)add_executable(helloworld_lib helloworld_lib.cpp)
target_link_libraries(helloworld_lib message)

CMake接受<SHARED|STATIC|MODULE|INTERFACE> 作为add_library的第二个参数的有效值:

  • STATIC:用于创建静态库,即编译文件的打包存档,以便在链接其他目标时使用,例如:可执行文件。
  • SHARED:用于创建动态库,即可以动态链接,并在运行时加载的库。可以在CMakeLists.txt中使用add_library(message SHARED Message.hpp Message.cpp) 从静态库切换到动态共享对象(DSO)。
  • OBJECT:可将给定add_library的列表中的源码编译到目标文件,不将它们归档到静态库中,也不能将它们链接到共享对象中。如果需要一次性创建静态库和动态库,那么使用对象库尤其有用。我们将在本示例中演示。
  • MODULE:又为DSO组。与SHARED库不同,它们不链接到项目中的任何目标,不过可以进行动态加载。该参数可以用于构建运行时插件。

CMAKE_POSITION_INDEPENDENT_CODE

  • 该值是POSITION_INDEPENDENT_CODE的默认值。
  • 此变量用于初始化所有目标上的POSITION_INDEPENDENT_CODE属性。有关其他信息,请参见该目标属性。如果设置,则try_compile()命令也会使用该值。
    POSITION_INDEPENDENT_CODE
  • 是否创建与位置无关的目标。
  • POSITION_INDEPENDENT_CODE属性确定是否创建位置无关的可行性文件或共享库。对于SHARED和MODULE库目标,此属性默认为True,否则为False。如果在创建目标时设置了此属性,则该属性由CMAKE_POSITION_INDEPENDENT_CODE变量的值初始化。

构建OBJECT类型的库

add_library(message-objsOBJECTmessage.hmessage.cpp 
)# this is only needed for older compilers
# but doesn't hurt either to have it
set_target_properties(message-objsPROPERTIESPOSITION_INDEPENDENT_CODE 1
)add_library(message-sharedSHARED$<TARGET_OBJECTS:message-objs>                                      )add_library(message-staticSTATIC$<TARGET_OBJECTS:message-objs>
)add_executable(hello-world helloworld_lib.cpp)
target_link_libraries(hello-world message-static)

条件编译

在以下代码片段中,我们介绍了两个变量:USE_LIBRARYBUILD_SHARED_LIBS。这两个变量都设置为OFF。如CMake语言文档中描述,逻辑真或假可以用多种方式表示:

  • 如果将逻辑变量设置为以下任意一种:1ONYEStrueY或非零数,则逻辑变量为true
  • 如果将逻辑变量设置为以下任意一种:0OFFNOfalseNIGNORE、NOTFOUND、空字符串,或者以-NOTFOUND为后缀,则逻辑变量为false

USE_LIBRARY变量将在第一个和第二个行为之间切换。BUILD_SHARED_LIBS是CMake的一个全局标志。因为CMake内部要查询BUILD_SHARED_LIBS全局变量,所以add_library命令可以在不传递STATIC/SHARED/OBJECT参数的情况下调用;如果为false或未定义,将生成一个静态库。

# option(USE_LIBRARY "Compile sources into a library" OFF)
set(USE_LIBRARY OFF)
message(STATUS "Compile sources into a library? ${USE_LIBRARY}")
set(BUILD_SHARED_LIBS OFF)
list(APPEND _sources message.h message.cpp)if(USE_LIBRARY)add_library(message ${_sources})add_executable(hello-world helloworld_lib.cpp)target_link_libraries(hello-world message)
else()add_executable(hello-world helloworld_lib.cpp ${_sources})
endif()

opion命令

option可接受三个参数:

option(<option_variable> "help string" [initial value])

  • <option_variable>表示该选项的变量的名称。
  • "help string"记录选项的字符串,在CMake的终端或图形用户界面中可见。
  • [initial value]选项的默认值,可以是ONOFF

option更多信息

有时选项之间会有依赖的情况。示例中,我们提供生成静态库或动态库的选项。但是,如果没有将USE_LIBRARY逻辑设置为ON,则此选项没有任何意义。CMake提供cmake_dependent_option()命令用来定义依赖于其他选项的选项:

include(CMakeDependentOption)# second option depends on the value of the first
cmake_dependent_option(MAKE_STATIC_LIBRARY "Compile sources into a static library" OFF"USE_LIBRARY" ON)# third option depends on the value of the first
cmake_dependent_option(MAKE_SHARED_LIBRARY "Compile sources into a shared library" ON"USE_LIBRARY" ON)

如果USE_LIBRARYONMAKE_STATIC_LIBRARY默认值为OFF,否则MAKE_SHARED_LIBRARY默认值为ON。可以通过cmake命令行指定变量的值:

$ cmake -D USE_LIBRARY=OFF -D MAKE_SHARED_LIBRARY=ON ..

这仍然不会构建库,因为USE_LIBRARY仍然为OFF

CMake有适当的机制,通过包含模块来扩展其语法和功能,这些模块要么是CMake自带的,要么是定制的。本例中,包含了一个名为CMakeDependentOption的模块。如果没有include这个模块,cmake_dependent_option()命令将不可用。参见 https://cmake.org/cmake/help/latest/module/CMakeDependentOption.html

TIPS:手册中的任何模块都可以以命令行的方式使用cmake --help-module <name-of-module> 。例如,cmake --help-module CMakeDependentOption将打印刚才讨论的模块的手册页(帮助页面)。

指定编译器

如何选择一个特定的编译器?例如,如果想使用Intel或Portland Group编译器怎么办?CMake将语言的编译器存储在 CMAKE_<LANG>_COMPILER变量中,其中 <LANG>是受支持的任何一种语言,对于我们的目的是CXXCFortran。用户可以通过以下两种方式之一设置此变量:

  1. 使用CLI中的-D选项,例如:

    $ cmake -D CMAKE_CXX_COMPILER=clang++ ..
    
  2. 通过导出环境变量CXX(C++编译器)、CC(C编译器)和FC(Fortran编译器)。例如,使用这个命令使用clang++作为C++编译器:

    $ env CXX=clang++ cmake ..
    
  3. Make提供--system-information标志,它将把关于系统的所有信息转储到屏幕或文件中。要查看这个信息,请尝试以下操作:

     $ cmake --system-information information.txt
    

构建类型

CMake可以配置构建类型,例如:Debug、Release等。配置时,可以为Debug或Release构建设置相关的选项或属性,例如:编译器和链接器标志。控制生成构建系统使用的配置变量是CMAKE_BUILD_TYPE。该变量默认为空,CMake识别的值为:

  1. Debug:用于在没有优化的情况下,使用带有调试符号构建库或可执行文件。
  2. Release:用于构建的优化的库或可执行文件,不包含调试符号。
  3. RelWithDebInfo:用于构建较少的优化库或可执行文件,包含调试符号。
  4. MinSizeRel:用于不增加目标代码大小的优化方式,来构建库或可执行文件
if(NOT CMAKE_BUILD_TYPE)set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")

切换构建类型:

cmake -D CMAKE_BUILD_TYPE=Debug …

下面是对Visual Studio的CMake调用:

$ mkdir -p build
$ cd build
$ cmake .. -G"Visual Studio 12 2017 Win64" -D CMAKE_CONFIGURATION_TYPES="Release;Debug"

将为Release和Debug配置生成一个构建树。然后,您可以使--config标志来决定构建这两个中的哪一个:

$ cmake --build . --config Release

NOTE:当使用单配置生成器开发代码时,为Release版和Debug创建单独的构建目录,两者使用相同的源代码。这样,就可以在两者之间切换,而不用重新配置和编译。

设置编译器选项

list(APPEND flags "-fPIC" "-Wall")
if(NOT WIN32)list(APPEND flags "-Wextra" "-Wpedantic")
endif()target_compile_options(geometry
PRIVATE${flags}
)

— 分割线 —

add_executable(compute-areas compute-areas.cpp)
# 为可执行目标设置了编译选项:
target_compile_options(compute-areasPRIVATE"-fPIC")
target_link_libraries(compute-areas geometry)

本例中,警告标志有-Wall-Wextra-Wpedantic,将这些标示添加到geometry目标的编译选项中; compute-areasgeometry目标都将使用-fPIC标志。编译选项可以添加三个级别的可见性:INTERFACEPUBLICPRIVATE

可见性的含义如下:

  • PRIVATE,编译选项会应用于给定的目标,不会传递给与目标相关的目标。我们的示例中, 即使compute-areas将链接到geometry库,compute-areas也不会继承geometry目标上设置的编译器选项。
  • INTERFACE,给定的编译选项将只应用于指定目标,并传递给与目标相关的目标。
  • PUBLIC,编译选项将应用于指定目标和使用它的目标。

目标属性的可见性CMake的核心,以这种方式添加编译选项,不会影响全局CMake变量CMAKE_<LANG>_FLAGS_<CONFIG>,并能更细粒度控制在哪些目标上使用哪些选项。

cmake调试

cmake --build . – VERBOSE=1
cmake --build . -j8 --verbose
cmake -DCMAKE_VERBOSE_MAKEFILE=ON …

设置语言标准

if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
endif()if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
endif()

另外一种写法

add_executable(animal-farm animal-farm.cpp)
set_target_properties(animal-farm
PROPERTIES
CXX_STANDARD 14
CXX_EXTENSIONS OFF
CXX_STANDARD_REQUIRED ON
)

  • CXX_STANDARD会设置我们想要的标准。
  • CXX_EXTENSIONS告诉CMake,只启用ISO C++标准的编译器标志,而不使用特定编译器的扩展。
  • CXX_STANDARD_REQUIRED指定所选标准的版本。如果这个版本不可用,CMake将停止配置并出现错误。当这个属性被设置为OFF时,CMake将寻找下一个标准的最新版本,直到一个合适的标志。这意味着,首先查找C++11,然后是C++98

list命令

cmake的list命令即对列表的一系列操作,cmake中的列表变量是用分号;分隔的一组字符串,创建列表可以使用set命令(参考set命令),例如:set (var a b c d)创建了一个列表 “a;b;c;d”,而set (var “a b c d”)则是只创建了一个变量"a c c d"。list命令的具体格式根据子命令不同会有所区别

    list(LENGTH <list><output variable>)list(GET <list> <elementindex> [<element index> ...]<output variable>)list(APPEND <list><element> [<element> ...])list(FIND <list> <value><output variable>)list(INSERT <list><element_index> <element> [<element> ...])list(REMOVE_ITEM <list> <value>[<value> ...])list(REMOVE_AT <list><index> [<index> ...])list(REMOVE_DUPLICATES <list>)list(REVERSE <list>)list(SORT <list>)

我们可以看到,list命令的格式如下

list (subcommand <list> [args...])

subcommand为具体的列表操作子命令,例如读取、查找、修改、排序等。为待操作的列表变量,[args…]为对列表变量操作需要使用的参数表,不同的子命令对应的参数也不一致。

  • ENGTH 返回list的长度
  • GET 返回list中index的element到value中
  • APPEND 添加新element到list中
  • FIND 返回list中element的index,没有找到返回-1
  • INSERT 将新element插入到list中index的位置
  • REMOVE_ITEM 从list中删除某个element
  • REMOVE_AT 从list中删除指定index的element
  • REMOVE_DUPLICATES 从list中删除重复的element
  • REVERSE 将list的内容反转
  • SORT 将list按字母顺序排序

示例:

list(APPEND sources_with_lower_optimizationgeometry_circle.cppgeometry_rhombus.cpp)

这篇关于CMake系列EP02: 构建可执行程序和库的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/329617

相关文章

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链

Golang使用etcd构建分布式锁的示例分享

《Golang使用etcd构建分布式锁的示例分享》在本教程中,我们将学习如何使用Go和etcd构建分布式锁系统,分布式锁系统对于管理对分布式系统中共享资源的并发访问至关重要,它有助于维护一致性,防止竞... 目录引言环境准备新建Go项目实现加锁和解锁功能测试分布式锁重构实现失败重试总结引言我们将使用Go作

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

maven 编译构建可以执行的jar包

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」👈,「stormsha的知识库」👈持续学习,不断总结,共同进步,为了踏实,做好当下事儿~ 专栏导航 Python系列: Python面试题合集,剑指大厂Git系列: Git操作技巧GO

flume系列之:查看flume系统日志、查看统计flume日志类型、查看flume日志

遍历指定目录下多个文件查找指定内容 服务器系统日志会记录flume相关日志 cat /var/log/messages |grep -i oom 查找系统日志中关于flume的指定日志 import osdef search_string_in_files(directory, search_string):count = 0

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建      首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件、动态链接库文件、可执行文件、脚本文件、配置文件等。      我们在编写hellowor