cmake学习笔记1

基础概念

CMake是什么?
CMake是一个元构建系统(meta build-system),用于生产其他构建系统文件(如Makefile或Ninja)。

基础操作方式

CMake使用一个CMakeLists.txt文件描述配置,然后使用cmake驱动这个文件生成对应构建系统文件。
如果不想使用cmake命令行驱动CMakeLists.txt,也可以用cmake-gui进行可视化完成.

.
└── CMakeLists.txt
1 directory, 1 file

在这个目录执行如下命令可以生成默认的构建系统文件(一般为Makefile)

# -S 指定源码目录, -B 指定生产的构建文件的目录
cmake  -S . -B build 

运行后会在build目录下生成很多文件。

tree -L 2
.
├── CMakeLists.txt
└── build├── CMakeCache.txt├── CMakeFiles├── Makefile└── cmake_install.cmake3 directories, 4 files

你会惊讶的发现在build文件夹下有一个Makefile文件。如果你想生成Ninja可以使用-G命令完成。

cmake -G "Ninja" -S . -B build

如果想查询支持的构建系统用cmkae --help查询,如下所示在这里插入图片描述

由于cmake会生成不同的构建系统。比如makefile你会继续调用make命令去完成编译等流程。但是如果是ninja就要执行ninja命令去编译。为了屏蔽这个差异make提供了下列命令去无差别编译安装

# --VERBOSE用于指定输出详细信息 
camke --build .  --verbose
camke --install .

但可惜的cmake没有提供相关的clean命令,需要你自己根据平台调用如ninja cleanmake clean

变量类型

CMAKE中变量可以大致分两种:

  1. 缓存变量
  2. 非缓存变量

所以我们先明白这个非常重要的基础概念才能方便我们编写文件。

缓存变量

所有声明的变量会在cmake生成配置文件后会放入一个CMakeCache.txt文件中。
如果你再次修改CMakeLists.txt去修改一个缓存变量你会发现CMakeCache.txt不会更新,除非你手动删除这个文件。(如果使用命令行CMAKE -DKEY=VALUE 的缓存变量会强制更新CMakeCache.txt

缓存变量特性:

  1. 全局修改会被其他cmake感知
  2. 全局可访问(同级cmake也可以)
  3. 除显示强制覆盖否则不会重写该数值
  4. 修改CMakeLists.txt中的缓存变量在次用cmake重生成构建文件不会更新CMakeCache.txt
  5. 命令行传入的缓存变量每次cmake生产配置文件都会更新CMakeCache.txt

示例一

证明缓存变量会被写一个CMakeCache.txt文件中

我们看有如下目录文件

├── CMakeLists.txt
1 directory, 1 files
//CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(DEMO)
# 声明一个缓存变量
set(myvar "Hello" CACHE STRING "一个说明行描述可以无视")
# 声明一个非缓存变量
set(myNormalVar "Hello world")

执行如下命令

cmake   -S . -B build

生成如下文件和对应目录

.
├── CMakeLists.txt
└── build├── CMakeCache.txt├── CMakeFiles├── Makefile└── cmake_install.cmake
3 directories, 4 files

我们查找这里两个变量是否在CmakeCache.txt中

使用grep查找
grep -E "myvar|myNormalVar" ./build/CMakeCache.txt  
输出:
myvar:STRING=Hello

示例二

修改CMakeLists.txt的缓存变量不会引起CmakeCache.txt更新

# CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(DEMO)
# 声明一个缓存变量
set(myvar "Hello" CACHE STRING "一个说明行描述可以无视")
//生成配置文件
cmake -S . -B build
//查找变量
grep -E "myvar" ./build/CMakeCache.txt
//输出结果
myvar:STRING=Hello

此时我们修改CMakeLists.txt中的myvar变量为world

# CMakeLists.txt//...略
//修改一个变量
set(myvar "World" CACHE STRING "一个说明行描述可以无视")
//...略
//重新生成配置文件
cmake -S . -B build
//在此查找变量
grep -E "myvar" ./build/CMakeCache.txt
//输出结果 发现并没有改为World
myvar:STRING=Hello

示例二

CMake -DKey=value 命令行传入的缓存变量会强制刷新CMakeCache.txt

//第一次运行配置命令并查找
cmake -DmyKey=myvalue -S . -B build ; grep -E "myKey" ./build/CMakeCache.txt
myKey:UNINITIALIZED=myvalue
//第二次运行配置命令并查找
cmake -DmyKey=myvalue22222 -S . -B build ; grep -E "myKey" ./build/CMakeCache.txt
myKey:UNINITIALIZED=myvalue22222

示例三

我们缓存变量作用域和可见性

.
├── CMakeLists.txt
├── childDir01
│   └── CMakeLists.txt
└── childDir02└── CMakeLists.txt
3 directories, 3 files
//.CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(PARENT_PRO)set(myParentNormalVal "I'm myParentNormalVal")
set(myParentCacheVal "I'm myParentCacheVal" CACHE STRING "一个描述")#引入子cmake
add_subdirectory(childDir01)
add_subdirectory(childDir02)
# 打印子make修改后的变量
# 虽然CHILD01_PRO修改普通变量,但是由于作用域问题输出旧数值。 PARENT_PRO myParentNormalVal =  I'm myParentNormalVal
message("${PROJECT_NAME} myParentNormalVal =  ${myParentNormalVal}")
# 缓存变量全局修改都会生效,输出CHILD01_PRO修改后的数值。 PARENT_PRO myParentCacheVal = I'm myParentCacheValChild01 
message("${PROJECT_NAME} myParentCacheVal = ${myParentCacheVal}")
# 父cmake无妨访问子cmake的普通变量
message("${PROJECT_NAME} myChild01NormalVal =  ${myChild01NormalVal}")
# 子cmake定义的缓存变量全局都可以访问
message("${PROJECT_NAME} myChild01CacheVal = ${myChild01CacheVal}")//./child01/CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(CHILD01_PRO)
set(myChild01NormalVal "I'm myChild01NormalVal")
set(myChild01CacheVal "I'm myChild01CacheVal" CACHE STRING "一个描述" FORCE)
# 打印父变量
#子cmake可以任意访问父变量(普通变量修改仅所在的Cmake文件生效不能跨全局) 输出 CHILD01_PRO myParentNormalVal =  I'm myParentNormalVal
message("${PROJECT_NAME} myParentNormalVal =  ${myParentNormalVal}")
#子cmake可以任意访问父变量(注意缓存变量的修改全局都可以生效) 输出 CHILD01_PRO myParentCacheVal = I'm myParentCacheVal
message("${PROJECT_NAME} myParentCacheVal = ${myParentCacheVal}")
message("\r\n${PROJECT_NAME} change myParentNormalVal and myParentCacheVal :\r\n")
# 修改父变量
set(myParentNormalVal "I'm myParentNormalValChild01")
set(myParentCacheVal "I'm myParentCacheValChild01 " CACHE STRING "一个描述" FORCE)
# 打印修改变量后的数值
#修改普通变量仅在当前CMakeLists.txt生效。回到父时依旧是旧值。输出 CHILD01_PRO myParentNormalVal =  I'm myParentNormalValChild01
message("${PROJECT_NAME} myParentNormalVal =  ${myParentNormalVal}")
#修改缓存变量全局生效。回到父时输出改变后的数值。输出 CHILD01_PRO myParentCacheVal = I'm myParentCacheValChild01 
message("${PROJECT_NAME} myParentCacheVal = ${myParentCacheVal}")//./child02/CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(CHILD02_PRO)
# 打印父变量
#子cmake可以任意访问父变量(普通变量修改仅所在的Cmake文件生效不能跨全局) 输出 CHILD02_PRO myParentNormalVal =  I'm myParentNormalVal
message("${PROJECT_NAME} myParentNormalVal =  ${myParentNormalVal}")
#子cmake可以任意访问父变量(注意缓存变量的修改全局都可以生效) 输出 CHILD02_PRO myParentCacheVal = I'm myParentCacheValChild01 
message("${PROJECT_NAME} myParentCacheVal = ${myParentCacheVal}")
#打印同级的Cmake变量
#同级cmake变量无法访问 输出 CHILD02_PRO myChild01NormalVal =  
message("${PROJECT_NAME} myChild01NormalVal =  ${myChild01NormalVal}")
#缓存变量可以访问 输出 CHILD02_PRO myChild01CacheVal = I'm myChild01CacheVal
message("${PROJECT_NAME} myChild01CacheVal = ${myChild01CacheVal}")
#执行命令
cmake  -S . -B build
#输出结果
CHILD01_PRO myParentNormalVal =  I'm myParentNormalVal
CHILD01_PRO myParentCacheVal = I'm myParentCacheVal
CHILD01_PRO change myParentNormalVal and myParentCacheVal :
CHILD01_PRO myParentNormalVal =  I'm myParentNormalValChild01
CHILD01_PRO myParentCacheVal = I'm myParentCacheValChild01 CHILD02_PRO myParentNormalVal =  I'm myParentNormalVal
CHILD02_PRO myParentCacheVal = I'm myParentCacheValChild01 
CHILD02_PRO myChild01NormalVal =  
CHILD02_PRO myChild01CacheVal = I'm myChild01CacheValPARENT_PRO myParentNormalVal =  I'm myParentNormalVal
PARENT_PRO myParentCacheVal = I'm myParentCacheValChild01 
PARENT_PRO myChild01NormalVal =  
PARENT_PRO myChild01CacheVal = I'm myChild01CacheVa

非缓存变量

反向参考变量

变量声明方式

set

你可以使用set命令如下声明如下变量MYVAR 。(注意此处非缓存变量类型)
set(<variable> <value>... [PARENT_SCOPE])

cmake_minimum_required(VERSION 3.14)
project(DEMO)
set(MYVAR "MYVALUE")
message("变量MYVAR=${MYVAR}")

当然变量可以拼接多个字符串并自动使用进行分割

cmake_minimum_required(VERSION 3.14)
project(DEMO)
set(MYVAR "MYVALUE" "MYVALUE2" "MYVALUE3")
message("变量MYVAR=${MYVAR}")

输出:

cmake -S . -B build 
变量MYVAR=MYVALUE;MYVALUE2;MYVALUE3
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /Users/fanjack/Desktop/learnMake/build

上面声明的是一个非缓存类型的普通变量。我们来看看声明缓存变量
set(<variable> <value>... CACHE <type> <docstring> [FORCE])

cmake_minimum_required(VERSION 3.14)
project(DEMO)
# 声明一个缓存变量
set(myvar "Hello" CACHE STRING "一个说明")
message("myvar is ${myvar}")  
# 想修改缓存变量 但是由于缓存变量一定被设置除非使用FORCE关键字不然不允许重写
set(myvar "Hello2" CACHE STRING  "一个说明")
message("myvar is ${myvar}") 
# 使用FORCE关键字重写
set(myvar "Hello3" CACHE STRING "一个说明" FORCE)
message("myvar is ${myvar}")  

对应的输出:

myvar is Hello
myvar is Hello
myvar is Hello3

选项变量

option(<variable> "<help_text>" [value]) (自动为缓存变量)

option(USE_MYMATH "Use my math implementation" ON)
//为ON表示条件为真输出 Using my math implementation
if(USE_MYMATH)message("Using my math implementation")
else()message("Using standard math library")  
endif()

环境变量

访问环境变量 $ENV{XXX} 其中XXX为环境变量名,makefile会自动将环境转化为makefile变量。

举例

cmake_minimum_required(VERSION 3.14)
project(DEMO)
#因为环境变量存在PATH所以输出相关数值
message("env $ENV\{PATH\} = $ENV{PATH}")
#因为PATH是环境而不是CMAKE变量所以不会有任何输出
message("env $\{PATH\} = ${PATH}")

传递可见性

在CMAKE有很多函数可以定义头文件目录或宏等,在函数中一个参数叫可见性的属性。这个属性在多CMakeLists中显得尤为重要。假设target A 依赖target B。那么target B部分定义的属性是否对于target A可见?
在cmake一般有如下三个可见性属性

<INTERFACE|PUBLIC|PRIVATE>

  • INTERFACE 对自身不可见,但是对于依赖自身的target可见
  • PUBLIC 对自身和依赖自身的target都可见
  • PRIVATE 仅自身可见

我们举例如下

.
├── CMakeLists.txt
├── main.cpp
└── mycalclib├── CMakeLists.txt├── mycalc.cpp└── mycalc.h2 directories, 5 files
//main.cpp
#include "mycalclib/mycalc.h"
#include <iostream>
using namespace std;
int main(int argc, char *args[]) {mycalc d;d.run();
#ifdef  FOOcout<<"main "<<"FOO "<<FOO<<endl;
#elsecout << "main " << "nothing" << endl;
#endifreturn 0;
}
# ./CMakeLists.txt
cmake_minimum_required(VERSION 3.26)
project(learnC)set(CMAKE_CXX_STANDARD 17)
add_subdirectory(mycalclib)
add_executable(learnC main.cpp)
target_link_libraries(learnC mycalc)
# ./mycalclib/CMakeLists.txt
cmake_minimum_required(VERSION 3.26)
project(mycalclib)
set(CMAKE_CXX_STANDARD 17)
add_library(mycalc STATIC mycalc.cpp)
#定义一个宏变量,名为mycalc,且是私有的也就是库本身才可见。
target_compile_definitions(mycalc PRIVATE FOO=1)
//mycalc.cpp
#include "mycalc.h"
#include <iostream>
using namespace std;
mycalc::mycalc() {
}
void mycalc::run() {
#ifdef  FOOcout<<"mycalc "<<"FOO "<<FOO<<endl;
#elsecout << "mycalc " << "nothing" << endl;
#endif
}
//mycalc.h
#ifndef LEARNC_MYCALC_H
#define LEARNC_MYCALC_H
class mycalc{
public:mycalc();void run();
};
#endif //LEARNC_MYCALC_H

我们最后编译输出

mycalc FOO 1
main nothing

由于target_compile_definitions(mycalc PRIVATE FOO=1)是私有定义,在main.cpp是不可见的,但是对于库本身是可见。我们改为INTERFACE再次运行。
target_compile_definitions(mycalc INTERFACE FOO=1)

mycalc nothing
main FOO 1

public运行结果,target_compile_definitions(mycalc PUBLIC FOO=1)

mycalc FOO 1
main FOO 1

配置头文件

configure_file文档
camke提供了配置头文件,可以留用这个文件根据条件生成C++中的标准头文件等。

配置文件有一些奇特占位符语法:

  • #cmakedefine VAR
  • ${VAR}
  • @VAR@
  • $CACHE{VAR}

#cmakedefine VAR 表示如果cmake存在一个变量VAR可以让if返回为true,那么这一行会被换为#define VAR
${VAR}/@VAR@/$CACHE{VAR} VAR 表示如果cmake存在一个变量VAR可以让if返回为true,那么这一行会被换为对应的变量.如果没有那么会替换为空

我们举例如下
假设我们的配置头文件叫foo.h.in

//foo.h.in
#cmakedefine FOO_STRING 
#define FOO_STRING2 "${FOO_STRING2_VALUE}"
#cmakedefine FOO_STRING3

对应cmka文件

cmake_minimum_required(VERSION 3.14)
project(DEMO)
# 因为FOO_STRING 被定义了当if条件为变量时会为true.所以#cmakedefine FOO_STRING 转为 # define FOO_STRING 
set(FOO_STRING "Enable")
# 因为FOO_STRING2_VALUE 被定义了当if条件为变量时会为true. 因此foo.h.in的FOO_STRING2_VALUE会被替换为I'm FOO_STRING2_VALUE  
set(FOO_STRING2_VALUE "I'm FOO_STRING2_VALUE ")
# 定义了一个可选变量由于是OFF if会返回true。#cmakedefine FOO_STRING3 不会转化为# define FOO_STRING3 
option(FOO_STRING3 "Use my math implementation" OFF)
#设置配置文件和对应的输出文件
configure_file(foo.h.in foo.h )

执行命令后会在当前目录生产一个foo.h文件

//foo.h
#define FOO_STRING 
#define FOO_STRING2 "I'm FOO_STRING2_VALUE "
/* #undef FOO_STRING3 */

配置文件

CMake 保姆级教程【C/C++】
CMake 保姆级教程(上)
CMake 保姆级教程(下)
CMake官方教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/798139.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

websokcet服务端实现

一/websokcet服务端实现 步骤一&#xff1a; springboot底层帮我们自动配置了websokcet&#xff0c;引入maven依赖 1 2 3 4 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</arti…

AI图片智能选区抠像解决方案

高质量的图片处理往往依赖于繁琐的手动操作&#xff0c;耗费大量时间与精力。美摄科技推出了一款革命性的AI图片智能选区抠像解决方案&#xff0c;旨在帮助企业轻松实现图片的高效处理&#xff0c;提升内容创作效率与质量。 美摄科技的AI图片智能选区抠像解决方案&#xff0c;…

AFCI 应用笔记二之数据采集

1. 简介 基于监督学习的神经网络算法需要大量数据作为输入&#xff0c;模型完全由数据驱动&#xff0c;其数据质量是算法有效的必要条件&#xff0c;所以如何高效的采集到数据&#xff0c;以及正确的标注或分析是极其重要的&#xff0c;如果第一步有问题&#xff0c;后续的所有…

C++搭建深度学习的推理框架

我们的目的是:借助C++搭建一个类似于pytorch,tensorflow的深度学习框架,对标pytorch,tensorflow实现对应的功能。由于本人能力有限,下面本人将借助C++搭建一个简单的全连接神经网络,并且尝试解释里面的算子定义和计算图构建。 算子定义 回顾pytorch里面搭建的全连接神经网…

ESP32S3网络编程学习笔记(1)—— Wi-Fi扫描实验

前言 &#xff08;1&#xff09;如果有嵌入式企业需要招聘湖南区域日常实习生&#xff0c;任何区域的暑假Linux驱动/单片机/RTOS的实习岗位&#xff0c;可C站直接私聊&#xff0c;或者邮件&#xff1a;zhangyixu02gmail.com&#xff0c;此消息至2025年1月1日前均有效 &#xff…

基于DPDK的VPP 插件demo代码

VPP的插件编写&#xff0c; 首先要把VPP 工程下载下来&#xff0c; 编译通过。 然后按照example程序的套中来编写插件。 还有一个前提&#xff0c; 就是测试机上已经具备了DPDK 已经可用版本。 1. 下载VPP。 可以从github上下载VPP的指定版本的zip包&#xff0c; 也可以用…

2024年租用阿里云服务器多少钱一年?连夜整理分享

阿里云服务器租用价格表2024年最新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元&#xff0c;ECS u1服务器2核4G5M固定带宽199元一年&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;2核…

软考高级架构师:嵌入式系统的内核架构

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

2024/4/1—力扣—二叉树的最近公共祖先

代码实现&#xff1a; 思路&#xff1a; 递归判断左子树和右子树&#xff0c;查找p或者q是否在当前节点的子树上 1&#xff0c;在同一子树上&#xff0c;同一左子树&#xff0c;返回第一个找到的相同值&#xff0c;同一右子树上&#xff0c;返回第一个找到的相同值 2&#xff0…

UML 绘制工具 starUML 入门介绍

拓展阅读 常见免费开源绘图工具 OmniGraffle 创建精确、美观图形的工具 UML-架构图入门介绍 starUML UML 绘制工具 starUML 入门介绍 PlantUML 是绘制 uml 的一个开源项目 UML 等常见图绘制工具 绘图工具 draw.io / diagrams.net 免费在线图表编辑器 绘图工具 excalidr…

工具推荐-针对Nacos利器-NacosExploitGUI_v4.0

Nacos是由阿里所开发的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 工具简介 集成Nacos的各种poc Nacos控制台默认口令漏洞(nacos,nacos)Nacostoken.secret.key默认配置(QVD-2023-6271)Nacos-clientYaml反序列化漏洞Nacos Jraft Hessian反序列化漏洞…

PET-SQL:基于大模型的两阶段Text2SQL方法

简介 PET-SQL出自论文《PET-SQL: A Prompt-enhanced Two-stage Text-to-SQL Framework with Cross-consistency》&#xff0c;将基于大模型的Text2SQL分为两个阶段进行&#xff0c;在第一阶段使用数据表schema信息、数据表采样数据、相似问答问答对生成初步的SQL(PreSQL)&…

【边缘智能】00_边缘计算发展背景

本系列是个人学习《边缘就算基础知识入门》的笔记&#xff0c;仅为个人学习记录&#xff0c;欢迎交流&#xff0c;感谢批评指正 移动物联设备产生海量数据&#xff0c;数据密集型移动智能应用&#xff0c;计算密集、动态性高&#xff0c;实时性强 传统云计算架构 基于广域互联…

matrix-breakout-2-morpheus 靶机渗透

信息收集&#xff1a; 1.nmap存活探测&#xff1a; nmap -sn -r 192.168.10.1/24 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-04-06 12:13 CST Nmap scan report for 192.168.10.1 Host is up (0.00056s latency). MAC Address: 00:50:56:C0:00:08 (VMware) Nmap…

鸿蒙内核源码分析 (双向链表篇) | 谁是内核最重要结构体

双向链表是什么&#xff1f; 谁是鸿蒙内核最重要的结构体 &#xff1f; 一定是: LOS_DL_LIST(双向链表)&#xff0c; 它长这样。 typedef struct LOS_DL_LIST {struct LOS_DL_LIST *pstPrev; /**< Current nodes pointer to the previous node | 前驱节点(左手)*/struct L…

Qt实现Kermit协议(四)

3 实现 3.3 KermitRecvFile 该模块实现了Kermit接收文件功能。 序列图如下&#xff1a; 3.3.1 KermitRecvFile定义 class QSerialPort; class KermitRecvFile : public QObject, public Kermit {Q_OBJECT public:explicit KermitRecvFile(QSerialPort *serial, QObject *…

面试(03)————多线程和线程池

一、多线程 1、什么是线程?线程和进程的区别? 2、创建线程有几种方式 &#xff1f; 3、Runnable 和 Callable 的区别&#xff1f; 4、如何启动一个新线程、调用 start 和 run 方法的区别&#xff1f; 5、线程有哪几种状态以及各种状态之间的转换&#xff1f; 6、线程…

极越夏一平反思:论技术我们很能打,要解决品牌认知问题

作者 |张祥威 编辑 |德新 今年起&#xff0c;新能源汽车竞争强度明显再上一个台阶。 华为主导下的问界强势逆袭&#xff0c;雷军亲自坐镇的小米汽车在发布后斩获丰厚的大定订单&#xff0c;给其它汽车品牌带来压力。3月末&#xff0c;在小米发布会前几日&#xff0c;极越在北…

【JavaScript】作用域 ③ ( JavaScript 作用域链 | 作用域链变量查找机制 )

文章目录 一、JavaScript 作用域链1、作用域2、作用域链3、作用域链变量查找机制 二、代码示例 - 作用域链 一、JavaScript 作用域链 1、作用域 在 JavaScript 中 , 任何代码都有 作用域 , 全局作用域 : 在 <script> 标签中 或者 js 脚本中 定义的变量 属于 全局作用域 …

k8s安全控制、授权管理介绍,全网最新

3.ABAC 4.Webhook 5.Node 6.RBAC 三.Role解释 1.Role和ClusterRole 2.Rolebinding和ClusterBinding 3.Rolebinding和ClusterRole 四.准入控制 1.命令格式 2.可配置控制器 五.例子 1.生成签署证书 2.设置用户和上下文信息 3.为sulibao用户授权 一.Kubernetes安全控…