CMake 保姆级教程(上)

news2024/12/18 7:13:51

整理自 视频 【CMake 保姆级教程【C/C++】】 https://www.bilibili.com/video/BV14s4y1g7Zj/?p=5&share_source=copy_web&vd_source=6eb8f46d194c5ef9f89d3331f623a9c3

1、cmake简介

源文件(.cpp / .c)要经过 工具链

1.1 工具链

1、预处理:把头文件展开,宏替换,把注释去掉
得到的还是源文件

2、编译器进行编译(gcc / g++),编译完得到 汇编文件

3、将汇编文件 通过 汇编器进行处理,就得到 二进制文件(.obj (win) / .o (linux))

4、链接器 对二进制文件进行 链接,打包之后 生成可执行文件(也是二进制的)

5、可以把CMake看成一款自动生成 Makefile的工具,其编译流程如下图:
在这里插入图片描述

1.2 生成可执行文件

文件少 可以通过命令 生成可执行文件;项目多:
1)makefile,创建一个脚本文件,脚本文件名字 就是makefile,在makefile里面执行 一系列的指令,告诉编译器怎么编译 源文件
脚本文件写好后,执行 一系列的批处理命令,批处理命令 就叫做make,makefile里面的若干个指令 执行了 make之后就可以把 makefile里面的指令 全部执行完毕,可执行程序 就被构建出来了

2)cmake,不依赖于 平台,根据不同的平台 生成对应的 makefile脚本文件,脚本文件名字 cmakelists.txt,在这个文件里面 执行一系列的指令,有了这些指令之后 再执行命令 cmake,生成 makefile文件,执行了 make之后就可以把 makefile里面的指令 全部执行完毕,可执行程序 就被构建出来了

除了 生成可执行文件 还可以生成库文件,库文件有两种:动态库 和 静态库。库文件 引入 第三方项目使用(对第三方保密,使用更直观(变成库第三方直接调用))

主要聚焦 cmakelists.txt 命令怎么写,大型项目自动化管理

2、编写简单的 cmakelists.txt

2.1 安装cmake

查看是否安装cmake

cmake --version

安装cmake

sudo apt install cmake

或者

官网下载 安装.tar.gz cmake v3.17
安装版本:cmake-3.17.0-rc2-Linux-x86_64(新版本无法 这样安装)
解压并进入目录下bin文件(tar -zxvf),加个软链

tar -zxvf cmake-3.17.0-rc2-Linux-x86_64.tar.gz
cd cmake-3.17.0-rc2-Linux-x86_64/bin
sudo ln -s /home/名字/cmake-3.17.0-rc2-Linux-x86_64/bin/cmake /usr/bin/cmake

检验一下

./cmake -version

成功
软连接成功
不用虚拟机 也可以安装wsl解决

2.2 源文件和头文件

头文件声明,源文件具体实现,加减乘除,在main中对加减乘除函数 实现了调用
add.c

#include <stdio.h>
#include "head.h"

int add(int a, int b)
{
    return a+b;
}

sub.c

#include <stdio.h>
#include "head.h"

int subtract(int a, int b)
{
    return a-b;
}

mult.c

#include <stdio.h>
#include "head.h"

int multiply(int a, int b)
{
    return a*b;
}

div.c

#include <stdio.h>
#include "head.h"

double divide(int a, int b)
{
    return (double)a/b;
}

head.h

#ifndef _HEAD_H
#define _HEAD_H
// 加法
int add(int a, int b);
// 减法
int subtract(int a, int b);
// 乘法
int multiply(int a, int b);
// 除法
double divide(int a, int b);
#endif

main.c

#include <stdio.h>
#include "head.h"

int main()
{
    int a = 20;
    int b = 12;
    printf("a = %d, b = %d\n", a, b);
    printf("a + b = %d\n", add(a, b));
    printf("a - b = %d\n", subtract(a, b));
    printf("a * b = %d\n", multiply(a, b));
    printf("a / b = %f\n", divide(a, b));
    return 0;
}

源文件比较少,可以直接 使用命令进行编译
转到代码所在目录下

g++ *.cpp -o app

./app 运行
运行结果

2.3 初步使用 CMake

1、注释:
Make 使用 # 进行行注释
CMake 使用 #[[ ]] 形式进行块注释

#[[ 这是一个 CMakeLists.txt 文件。
这是一个 CMakeLists.txt 文件
这是一个 CMakeLists.txt 文件]]
cmake_minimum_required(VERSION 3.0.0)

2、创建文件 CMakeLists.txt 区分大小写
创建文件

3、在创建的文件里面写命令:

cmake_minimum_required:指定 使用的 cmake 的最低版本(可选,非必须,如果不加可能会有警告)

# PROJECT 指令的语法是:
project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
       [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
       [DESCRIPTION <project-description-string>]
       [HOMEPAGE_URL <url-string>]
       [LANGUAGES <language-name>...])

与上面的字段 一一对应:定义工程名称,并可指定工程的版本、工程描述(字符串)、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可

add_executable:定义工程会生成一个可执行程序

add_executable(可执行程序名 源文件名称)

# 样式1
add_executable(app add.cpp div.cpp main.cpp mult.cpp sub.cpp)
# 样式2
add_executable(app add.cpp; div.cpp; main.cpp; mult.cpp; sub.cpp)

这里的 可执行程序名 和 project中的项目名 没有任何关系
源文件名 可以是一个 也可以是多个,如 有多个可用空格 或; 间隔

本次的文件:

cmake_minimum_required(VERSION 3.15) # 指定版本
project(test)                        # 指定工程名字
add_executable(app add.cpp div.cpp main.cpp mult.cpp sub.cpp) # 指定可执行程序名字以及源文件

在当前目录里面 执行cmake命令,cmake后面跟上 CMakeLists.txt 所在的路径 cmake .然后 会看到一系列的 日志输出
生成的文件

生成了一些新的文件 以及 目录, app 工程文件可以执行
执行工程文件
多了一些暂时不关心的文件,可能会减慢搜索速度,可以把这些文件 放到对应的编译目录
删除文件,进入创建的编译目录,再执行cmake命令(路径是CMakeLists.txt对应的路径) cmake ..
操作
操作2
只要 MakeFile 文件生成就大功告成了
还需要执行 make命令,在build文件夹里面 生成了 app工程文件
查看日志

2.4 set

1、定义变量
通过set设置变量值的时候 都是字符串类型,变量名同一个文件中不能有重复
对变量进行取值:${ 变量名 }

# SET 指令的语法是:
# [] 中的参数为可选项, 如不需要可以不写
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
# VAR:变量名  VALUE:变量值

# 方式1: 各个源文件之间使用空格间隔
# set(SRC_LIST add.c  div.c   main.c  mult.c  sub.c)

# 方式2: 各个源文件之间使用分号 ; 间隔
set(SRC_LIST add.c;div.c;main.c;mult.c;sub.c)
add_executable(app  ${SRC_LIST})

2、指定使用的C++标准
1)在编译的时候在编译命令中制定出要使用哪个标准

$ g++ *.cpp -std=c++11 -o app

2)C++标准对应有一宏叫做CMAKE_CXX_STANDARD。在CMake中想要指定C++标准有两种方式:
CMakeLists.txt 中通过 set 命令指定

#增加-std=c++11
set(CMAKE_CXX_STANDARD 11)

在执行 cmake 命令的时候指定出这个宏的值

#增加-std=c++11-D就是制定一个宏
cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=11

3、指定输出的路径
在CMake中指定可执行程序输出的路径,也对应一个宏,叫做EXECUTABLE_OUTPUT_PATH,它的值还是通过set命令进行设置

set(HOME /home/robin/Linux/Sort)
set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin)

指定输出路径时 要使用 绝对路径, 因为 如果此处指定可执行程序生成路径的时候使用的是相对路径 ./xxx/xxx,那么这个路径中的 ./ 对应的就是 makefile 文件所在的那个目录

除了给 可执行程序 指定路径,还可以 给动态库 指定路径

如果这个路径中的子目录不存在,会自动生成,无需自己手动创建

4、例子
CMakeLists.txt

cmake_minimum_required(VERSION 3.15) # 指定版本
project(test)                        # 指定工程名字
set(SRC add.cpp div.cpp main.cpp mult.cpp sub.cpp)
set(EXECUTABLE_OUTPUT_PATH /home/ashergu/vscode_workpace/cmake_v1/out)
set(CMAKE_CXX_STANDARD 11)
add_executable(app ${SRC}) # 指定可执行程序名字以及源文件

运行结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
cmake命令是在build目录中执行的,但是CMakeLists.txt文件是build目录的上一级目录中,所以cmake 命令后指定的路径为…,即当前目录的上一级目录
当命令执行完毕之后,在build目录中会生成一个makefile文件
这样就可以在build目录中执行make命令编译项目,生成的相关文件自然也就被存储到build目录中了。这样通过cmake和make生成的所有文件就全部和项目源文件隔离开了

使用cmake命令时要保证上级目录里面不能有 之前执行cmake命令生成的文件,不然就不会生成新的文件了
给对应的宏设置值,宏不一样,对应的功能也就不一样

3、搜索文件

1、如果一个项目里边的源文件很多,在编写CMakeLists.txt文件的时候不可能将项目目录的各个文件一一罗列出来,在CMake中为 提供了搜索相应目录文件的命令,可以使用aux_source_directory命令或者file命令

2、这个变量是不需要提前定义的,使用时 只要把名字指定到 参数位置就行了,命令执行完之后,这个名字对应的变量 也就初始化完成了

3.1 方式一:aux_source_directory

1、可以查找某个路径下的所有源文件(包括.c / .cpp)

aux_source_directory(< dir > < variable >)

dir:要搜索的目录(可以指定字符串(不需要加" ")或者 可以通过宏来进行指定)
宏有两个(宏存储的值相同):
1)PROJECT_SOURCE_DIR:对应cmake命令 后面跟随的路径(就是CMakeLists.txt文件所在的路径),有两个文件路径,可以写两个PROJECT_SOURCE_DIR,然后通过set进行合并 set(a, a, b) 把a,b全部放进a中
2)CMAKE_CURRENT_SOURCE_DIR:宏表示当前访问的 CMakeLists.txt 文件所在的路径

variable:将从dir目录下搜索到的源文件列表存储到该变量中

CMakeLists.txt

cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
# 搜索 src 目录下的源文件
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_LIST)
add_executable(app  ${SRC_LIST})

cmake生成了MakeFile文件,只要make就行了
CMakeLists.txt

cmake_minimum_required(VERSION 3.15) # 指定版本
project(test)                        # 指定工程名字
# set(SRC add.cpp div.cpp main.cpp mult.cpp sub.cpp)
aux_source_directory(${PROJECT_SOURCE_DIR} SRC)
set(EXECUTABLE_OUTPUT_PATH /home/ashergu/vscode_workpace/cmake_v1/out)
set(CMAKE_CXX_STANDARD 11)
add_executable(app ${SRC}) # 指定可执行程序名字以及源文件

运行结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2 方式二:file

file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径和文件类型)

GLOB: 将指定目录下搜索到的满足条件的所有文件名生成一个列表,并将其存储到变量中。
GLOB_RECURSE:递归搜索指定目录,将搜索到的满足条件的文件名生成一个列表,并将其存储到变量中。

搜索当前目录的src目录下所有的源文件,并存储到变量中

file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
file(GLOB MAIN_HEAD ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)

关于要搜索的文件路径和类型可加双引号,也可不加:

file(GLOB MAIN_HEAD "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h")

CMakeLists.txt

cmake_minimum_required(VERSION 3.15) # 指定版本
project(test)                        # 指定工程名字
# set(SRC add.cpp div.cpp main.cpp mult.cpp sub.cpp)
# aux_source_directory(${PROJECT_SOURCE_DIR} SRC)
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR})
set(EXECUTABLE_OUTPUT_PATH /home/ashergu/vscode_workpace/cmake_v1/out)
set(CMAKE_CXX_STANDARD 11)
add_executable(app ${SRC}) # 指定可执行程序名字以及源文件

运行结果
在这里插入图片描述

4、包含头文件

1、头文件和源文件不在一个目录内:把源文件放在src目录中,头文件放在include目录中
在这里插入图片描述
基于脚本文件(CMakeLists.txt)来编译src里面的源文件 最终生成可执行程序
更改目录并构建
在这里插入图片描述
将源文件对应的头文件路径指定出来

#include "head.h" // 相当于在./head.h

include_directories(headpath) // 参数是头文件对应的目录,建议使用绝对路径

在这里插入图片描述
在这里插入图片描述

5、制作动态库或静态库

有些时候我们编写的源代码并不需要将他们编译生成可执行程序,而是生成一些库文件(包括 静态库 或 动态库)提供给第三方使用

先复制一份
在这里插入图片描述
制作库就不需要main.cpp了,主要是用来测试的,把main.cpp移动出来
在这里插入图片描述

5.1 制作静态库

add_library(库名称 STATIC 源文件1 [源文件2] ...) 

在Linux中,静态库名字分为三部分:lib+库名字+.a(windows中是.lib),此处只需要指定出库的名字就可以了,另外两部分在生成该文件的时候会自动填充

工程名字需要跟之前不同,cmake和make之后

CMakeLists.txt

cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(calc STATIC ${SRC_LIST})

最终就会生成对应的静态库文件libcalc.a,没有可执行权限
在这里插入图片描述

5.2 制作动态库

add_library(库名称 SHARED 源文件1 [源文件2] ...) 

就后缀名称变了(linux中为.so,Windows中为.dll),动态库有另一个名字 共享库,所以参数改为 SHARED(唯一改动)

cmake_minimum_required(VERSION 3.15) # 指定版本
project(test2)                        # 指定工程名字
# set(SRC add.cpp div.cpp main.cpp mult.cpp sub.cpp)
# aux_source_directory(${PROJECT_SOURCE_DIR} SRC)
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
set(EXECUTABLE_OUTPUT_PATH /home/ashergu/vscode_workpace/cmake_v1/out)
set(CMAKE_CXX_STANDARD 11)
include_directories(${PROJECT_SOURCE_DIR}/include)
# add_executable(app ${SRC}) # 指定可执行程序名字以及源文件
add_library(calc SHARED ${SRC})

动态库有可执行权限,所以是绿色
在这里插入图片描述
发布给使用者时,除了库文件之外,还需要对应的头文件
不论静态库还是动态库 都是源代码,只不过是二进制的(.cpp源代码是文本格式的)

5.3 指定输出的路径

1、适用于动态库:
由于在Linux下生成的动态库默认是有执行权限的,所以可以按照生成可执行程序的方式去指定它生成的目录

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

对于这种方式来说,其实就是通过set命令给EXECUTABLE_OUTPUT_PATH宏设置了一个路径,这个路径就是可执行文件生成的路径

2、都适用:使用LIBRARY_OUTPUT_PATH,这个宏对应静态库文件和动态库文件都适用

# 设置动态库/静态库生成路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

6、Linux 静态库和动态库

整理自 https://subingwen.cn/linux/library/

1、不管是Linux还是Windows中的库文件 其本质和工作模式都是相同的, 只不过在不同的平台上库对应的文件格式和文件后缀不同。程序中调用的库有两种 静态库和动态库,不管是哪种库文件本质是还是源文件

2、使用库一般有两个目的,一个是为了使程序更加简洁不需要在项目中维护太多的源文件,另一方面是为了源代码保密

3、拿到了库文件(动态库、静态库)之后 要想使用还必须有这些库中提供的API函数的声明,也就是头文件,把这些都添加到项目中

6.1 生成静态链接库

在Linux中静态库由程序 ar 生成,以lib作为前缀, 以.a作为后缀, 中间是库的名字自己指定

1、生成静态库,需要先对源文件进行汇编操作 (使用参数 -c) 得到二进制格式的目标文件 (.o 格式), 然后在通过 ar工具将目标文件打包就可以得到静态库文件了 (libxxx.a)

参数c:创建一个库,不管库是否存在,都将创建。
参数s:创建目标文件索引,这在创建较大的库时能加快时间。
参数r:在库中插入模块(替换)。默认新的成员添加在库的结尾处,如果模块名已经在库中存在,则替换同名的模块

在这里插入图片描述
在这里插入图片描述
2、具体步骤:
1、第一步: 将源文件add.c, div.c, mult.c, sub.c 进行汇编, 得到二进制目标文件 add.o, div.o, mult.o, sub.o

# 1. 生成.o
$ gcc add.c div.c mult.c sub.c -c
sub.c:2:18: fatal error: head.h: No such file or directory
compilation terminated.

# 提示头文件找不到, 添加参数 -I 重新头文件路径即可
$ gcc add.c div.c mult.c sub.c -c -I ./include/

# 查看目标文件是否已经生成
$ tree
.
├── add.c
├── add.o            # 目标文件
├── div.c
├── div.o            # 目标文件
├── include
│   └── head.h
├── main.c
├── mult.c
├── mult.o           # 目标文件
├── sub.c
└── sub.o            # 目标文件

2、第二步: 将生成的目标文件通过 ar工具打包生成静态库

# 2. 将生成的目标文件 .o 打包成静态库
$ ar rcs libcalc.a a.o b.o c.o    # a.o b.o c.o在同一个目录中可以写成 *.o

# 查看目录中的文件
$ tree
.
├── add.c
├── add.o
├── div.c
├── div.o
├── include
│   └── `head.h  ===> 和静态库一并发布
├── `libcalc.a   ===> 生成的静态库
├── main.c
├── mult.c
├── mult.o
├── sub.c
└── sub.o

3、第三步: 将生成的的静态库 libcalc.a和库对应的头文件head.h一并发布给使用者就可以了

# 3. 发布静态库
	1. head.h    => 函数声明
	2. libcalc.a => 函数定义(二进制格式)

6.2 静态库的使用

# 1. 首先拿到了发布的静态库
	`head.h``libcalc.a`
	
# 2. 将静态库, 头文件, 测试程序放到一个目录中准备进行测试
.
├── head.h          # 函数声明
├── libcalc.a       # 函数定义(二进制格式)
└── main.c          # 函数测试

编译测试程序, 得到可执行文件

在编译的时将静态库的路径和名字都指定出来
-L: 指定库所在的目录(相对或者绝对路径)
-l: 指定库的名字, 需要掐头(lib)去尾(.a) 剩下的才是需要的静态库的名字

# 4. 编译的时候指定库信息
	-L: 指定库所在的目录(相对或者绝对路径)
	-l: 指定库的名字, 掐头(lib)去尾(.a) ==> calc
# -L -l, 参数和参数值之间可以有空格, 也可以没有  -L./ -lcalc
$ gcc main.c -o app -L ./ -l calc

# 查看目录信息, 发现可执行程序已经生成了
$ tree
.
├── app   		# 生成的可执行程序
├── head.h
├── libcalc.a
└── main.c

编译的源文件中包含了头文件 head.h, 这个头文件中声明的函数对应的定义(也就是函数体实现)在静态库中,程序在编译的时候没有找到函数实现

6.3 生成动态链接库

动态链接库是程序运行时加载的库,当动态链接库正确部署之后,运行的多个程序可以使用同一个加载到内存中的动态库,因此在Linux中动态链接库也可称之为共享库

动态链接库是目标文件的集合,目标文件在动态链接库中的组织方式是 按照特殊方式形成的。库中函数和变量的地址使用的是相对地址(静态库中使用的是绝对地址),其真实地址是 在应用程序加载动态库时形成的

在Linux中动态库以lib作为前缀, 以.so作为后缀, 中间是库的名字自己指定即可, 即: libxxx.so

1、生成动态链接库是直接使用gcc命令并且需要添加-fPIC(-fpic) 以及-shared 参数

-fPIC 或 -fpic 参数的作用是使得 gcc 生成的代码是与位置无关的,也就是使用相对位置。
-shared参数的作用是告诉编译器生成一个动态链接库
在这里插入图片描述
2、生成动态链接库的具体步骤如下:
1)将源文件进行汇编操作, 需要使用参数 -c, 还需要添加额外参数 -fpic / -fPIC

# 得到若干个 .o文件
$ gcc 源文件(*.c) -c -fpic

2)将得到的.o文件打包成动态库, 还是使用gcc, 使用参数 -shared 指定生成动态库(位置没有要求)

$ gcc -shared 与位置无关的目标文件(*.o) -o 动态库(libxxx.so)

3)发布动态库和头文件

# 发布
 	1. 提供头文件: xxx.h
 	2. 提供动态库: libxxx.so

第一步: 使用gcc将源文件进行汇编(参数-c), 生成与位置无关的目标文件, 需要使用参数 -fpic或者-fPIC
在这里插入图片描述

第二步: 使用gcc将得到的目标文件打包生成动态库, 需要使用参数 -shared
在这里插入图片描述

第三步: 发布生成的动态库和相关的头文件

  1. head.h
  2. libcalc.so

6.4 动态库的使用

1、拿到发布的动态库
head.h libcalc.so

2、基于头文件编写测试程序, 测试动态库中提供的接口是否可用
main.cpp

include <stdio.h>
#include "head.h"

int main()
{
    int a = 20;
    int b = 12;
    printf("a = %d, b = %d\n", a, b);
    printf("a + b = %d\n", add(a, b));
    printf("a - b = %d\n", subtract(a, b));
    printf("a * b = %d\n", multiply(a, b));
    printf("a / b = %f\n", divide(a, b));
    return 0;
}
.
├── head.h          ==> 函数声明
├── libcalc.so      ==> 函数定义
└── main.c          ==> 函数测试

和使用静态库一样, 在编译的时候需要指定库相关的信息: 库的路径 -L和 库的名字 -l
在编译的时候指定动态库相关的信息: 库的路径 -L, 库的名字 -l

在这里插入图片描述
执行生成的可执行程序, 错误提示:可执行程序执行的时候找不到动态库

6.5 解决动态库无法加载问题

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

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

相关文章

[计算机网络]唐僧的”通关文牒“NAT地址转换

1.NAT&#xff1a;唐僧的通关文牒 在古老的西游记中&#xff0c;唐僧师徒四人历经九九八十一难&#xff0c;终于取得了真经。然而&#xff0c;他们并不是一开始就获得了通关文牒&#xff0c;而是经过了重重考验&#xff0c;最终得到了国王的认可&#xff0c;才顺利通过了各个关…

vscode设置终端代理

转载请标明出处&#xff1a;小帆的帆的博客 设置终端代理 修改项目的.vscode/settings.json {"terminal.integrated.env.windows": {"http_proxy": "http://127.0.0.1:7890","https_proxy": "http://127.0.0.1:7890"}, }…

java后端环境配置

因为现在升学了&#xff0c;以前本来想毕业干java的&#xff0c;很多java的环境配置早就忘掉了&#xff08;比如mysql maven jdk idea&#xff09;&#xff0c;想写个博客记录下来&#xff0c;以后方便自己快速搭建环境 JAVA后端开发配置 环境配置jdkideamavenMySQLnavicate17…

云计算HCIP-OpenStack03

书接上回&#xff1a; 云计算HCIP-OpenStack02-CSDN博客 10.KeyStone keystone-Openstack&#xff0c;IAM服务&#xff08;统一身份认证&#xff09;-云服务 建议先去了解Hadoop&#xff08;大数据生态系统&#xff09;中的kerberos&#xff08;LDAPkerberos的鉴权机制&#xf…

.Net WebAPI(一)

文章目录 项目地址一、WebAPI基础1. 项目初始化1.1 创建简单的API1.1.1 get请求1.1.2 post请求1.1.3 put请求1.1.4 Delete请求 1.2 webapi的流程 2.Controllers2.1 创建一个shirts的Controller 3. Routing3.1 使用和创建MapControllers3.2 使用Routing的模板语言 4. Mould Bind…

【Flink-scala】DataStream编程模型之状态编程

DataStream编程模型之状态编程 参考&#xff1a; 1.【Flink-Scala】DataStream编程模型之数据源、数据转换、数据输出 2.【Flink-scala】DataStream编程模型之 窗口的划分-时间概念-窗口计算程序 3.【Flink-scala】DataStream编程模型之窗口计算-触发器-驱逐器 4.【Flink-scal…

Gitlab服务管理和仓库项目权限管理

Gitlab服务管理 gitlab-ctl start # 启动所有 gitlab 组件&#xff1b; gitlab-ctl stop # 停止所有 gitlab 组件&#xff1b; gitlab-ctl restart # 重启所有 gitlab 组件&#xff1b; gitlab-ctl status …

SCAU期末笔记 - Linux系统应用与开发教程样卷解析(2024版)

我真的不理解奥&#xff0c;为什么会有给样卷不自带解析的&#xff0c;对答案都没得对&#xff0c;故整理一篇 样卷1 一、选择题 1、为了遍历shell脚本调用时传入的参数&#xff0c;需要在shell脚本中使用_____。 A.$#表示参数的个数B.S表示所有参数C.$0表示脚本名D.$1表示…

学习threejs,区域光THREE.AreaLight效果

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.AreaLight 区域光 二…

RabbitMQ消息队列的笔记

Rabbit与Java相结合 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency> 在配置文件中编写关于rabbitmq的配置 rabbitmq:host: 192.168.190.132 /…

VSCode,Anaconda,JupyterNotebook

文章目录 一. 下载VSCode并安装二. 下载Anaconda并安装1. anaconda介绍2. Anaconda的包管理功能3. Anaconda的虚拟环境管理4.Jupyter Notebook5. Jupyter Notebook使用简介6. Jupyter Notebook快捷键7.Jupyter notebook的功能扩展8. Jupyter notebook和Jupyter lab的区别 三. V…

动态导出word文件支持转pdf

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、功能说明二、使用步骤1.controller2.工具类 DocumentUtil 导出样式 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff…

那些不属性的C语言关键字-const

大家都知道const修饰的变量是不可变的&#xff0c;但是到底是怎么实现的那&#xff0c;有方法修改只读变量的值吗&#xff0c;今天我们结合实验代码&#xff0c;分析下const关键字的实现原理 const变量 1.const修饰局部变量 int main(){const int abc 123;printf("%d\…

【Java 数据结构】List -> 给我一个接口!!!

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 目录 1. 什么是 List 2. List 常用的方法 3. List 的使用 1. 什么是 List 其实 List 是一个接口&#xff0c;它继承了 Collection 接口 下列为 List 接口中的各种…

【5G】5G的主要架构选项

最初&#xff0c;在3GPP讨论中考虑了所有可能的聚合和核心网络组合&#xff0c;共有八个架构选项。以下重点介绍option2、3、4和7。 1. 独立组网 (Standalone, SA) 架构选项 2 &#xff1a;Standalone architecture with 5G-core 特点&#xff1a; 5G核心网&#xff08;5GC, …

Ajax简单理解

Ajax 1 什么是ajax AJAXAsynchronous JavaScript and XML (异步的JavaScript和XML)AJAX不是新的编程语言&#xff0c;二十一种使用现有标准的新方法 AJAX 最大的优点是在不重新加载整个页面的情况下&#xff0c;可以与服务器交换数据并更新部分网页内容。 AJAX 不需要任何浏…

【GESP】C++二级考试大纲知识点梳理, (2)计算机网络的基本概念及分类

GESP C二级官方考试大纲中&#xff0c;共有9条考点&#xff0c;本文针对C&#xff08;2&#xff09;号知识点进行总结梳理。 &#xff08;2&#xff09;了解计算机网络的概念&#xff0c;了解计算机网络的分类&#xff08;广域网&#xff08;WAN&#xff09;、城域网&#xff0…

相机与NAS的奇妙组合,如何使用相机拍照自动上传或备份到NAS

相机与NAS的奇妙组合&#xff0c;如何使用相机拍照自动上传或备份到NAS 哈喽小伙伴们好&#xff0c;我是Stark-C~ 对于喜欢使用专业器材拍照摄影的小伙伴来说&#xff0c;想要将相机存储卡中的照片或视频导出到电脑上&#xff0c;要么是使用数据线直接和相机连接&#xff0c;…

window下的qt5.14.2配置vs2022

这里做一个笔记&#xff0c;已知qt5.14.2和vs2022不兼容&#xff0c;无法自动扫描到vs的编译器。但由于团队协作原因&#xff0c;必须使用qt5.14.2&#xff0c;并且第三方库又依赖vs2022。其实qt5.15.2是支持vs2022的&#xff0c;如果能够用qt5.15.2&#xff0c;还是建议使用qt…

QT从入门到精通(一)——Qlabel介绍与使用

1. QT介绍——代码测试 Qt 是一个跨平台的应用程序开发框架&#xff0c;广泛用于开发图形用户界面&#xff08;GUI&#xff09;应用程序&#xff0c;也支持非图形应用程序的开发。Qt 提供了一套工具和库&#xff0c;使得开发者能够高效地构建高性能、可移植的应用程序。以下是…