当前位置: 首页 > news >正文

CMake 保姆级教程(上)

整理自 视频 【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.hinclude_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.h2. 提供动态库: 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 解决动态库无法加载问题

相关文章:

CMake 保姆级教程(上)

整理自 视频 【CMake 保姆级教程【C/C】】 https://www.bilibili.com/video/BV14s4y1g7Zj/?p5&share_sourcecopy_web&vd_source6eb8f46d194c5ef9f89d3331f623a9c3 1、cmake简介 源文件&#xff08;.cpp / .c&#xff09;要经过 工具链 1.1 工具链 1、预处理&#…...

C++类模板的应用

template <class T> class mylist{ public: // 这是一个链表的节点 struct Link{ T val; Link* next; } 增 &#xff1a;insert(T val) 在链表中创建新节点&#xff0c;节点上保存的数据为 val 删&#xff1a;remove(T val) 移除链表中数据为 val 的节点 改: operator[](…...

Ubuntu 18.04无有线图表且无法设置有线网络

问题背景&#xff1a; 今天在登陆自己的虚拟机Ubuntu系统的时候突然出现 有线连接无法连接的问题&#xff0c;有线连接的图标变为没有了&#xff0c;无法点击网络菜单的Setting模块选项。我的虚拟机有线网络连接方式是NAT方式。 没有如下有线连接图标 解决方法&#xff1a; …...

QoS分类和标记

https://zhuanlan.zhihu.com/p/160937314 1111111 分类和标记是识别每个数据包优先级的过程。 这是QoS控制的第一步&#xff0c;应在源主机附近完成。 分组通常通过其分组报头来分类。下图指定的规则仔细检查了数据包头 &#xff1a; 下表列出了分类标准&#xff1a; 普通二…...

企业内训|阅读行业产品运营实战训练营-某运营商数字娱乐公司

近日&#xff0c;TsingtaoAI公司为某运营商旗下数字娱乐公司组织的“阅读行业产品运营实战训练营”在杭州落下帷幕。此次训练营由TsingtaoAI资深互联网产品专家程靖主持。该公司的业务骨干——来自内容、市场、业务、产品与技术等跨部门核心岗位、拥有8-10年实战经验的中坚力量…...

杭州乘云联合信通院发布《云计算智能化可观测性能力成熟度模型》

原文地址&#xff1a;杭州乘云联合中国信通院等单位正式发布《云计算智能化可观测性能力成熟度模型》标准 2024年12月3日&#xff0c;由全球数字经济大会组委会主办、中国信通院承办的 2024全球数字经济大会 云AI计算创新发展大会&#xff08;2024 Cloud AI Compute Ignite&…...

SimAI万卡集群模拟器,LLM大模型训练通信计算模拟

SimAI&#xff0c;是阿里巴巴构建的一个统一的模拟器&#xff0c;旨在大规模精确有效地模拟LLM训练过程。通过将训练框架、内核计算和集体通信库有选择地高保真集成到仿真过程中&#xff0c;SimAI在仿真中实现了高精度。 简单点来说&#xff0c;SimAI就是模拟&#xff0c;大模…...

Axure9设置画布固定

在使用AxureRP9设计原型时&#xff0c;如果遇到画布在拖动时变得难以控制&#xff0c;可以尝试在Windows系统中通过‘文件’>‘首选项’&#xff0c;或在Mac系统中通过‘AxureRP9’>‘偏好设置’进行设置&#xff0c;以稳定画布的行为。 现象 页面底层的画布&#xff0…...

window.getSelection() 获取划线内容并实现 dom 追随功能

功能&#xff1a;鼠标对一段文本中某些文字进行划线之后&#xff0c;需要在当前划线文本处出现一个功能按钮显示对划线内容进行操作&#xff0c;比如收藏、添加样本库等功能。 一、需要了解的鼠标事件对象属性 给 dom 元素注册鼠标事件之后&#xff0c;会有 event 属性&#…...

mybatis-plus超详细讲解

mybatis-plus &#xff08;简化代码神器&#xff09; 地址&#xff1a;https://mp.baomidou.com/ 目录 mybatis-plus 简介 特性 支持数据库 参与贡献 快速指南 1、创建数据库 mybatis_plus 2、导入相关的依赖 3、创建对应的文件夹 4、编写配置文件 5、编写代码 …...

浏览器可以直接请求 websocket

一、原生支持 浏览器原生支持 WebSocket 协议&#xff0c;这使得开发者可以直接在 JavaScript 代码中使用 WebSocket 来建立与服务器的双向通信通道。 const socket new WebSocket("ws://localhost:8080");socket.addEventListener("open", function (e…...

* 和 .* 的区别(MATLAB)

在 MATLAB 中&#xff0c;* 和 .* 都是用来进行乘法操作的运算符&#xff0c;但它们有不同的应用场景。我们将从数学和编程的角度详细解析这两者的区别&#xff0c;并且讲解 MATLAB 中 . 运算符的其他常见用法。 1. * 和 .* 的区别 *&#xff1a;矩阵乘法&#xff08;线性代数…...

51c视觉~合集30

我自己的原文哦~ https://blog.51cto.com/whaosoft/12059371 #SaRA 修改一行代码就能实现高效微调&#xff01;上海交大&腾讯开源&#xff1a;兼顾原始生成和下游任务 仅修改一行训练代码即可实现微调过程。 文章链接&#xff1a;https://arxiv.org/pdf/2409.06633 …...

JVM虚拟机总揽

为什么 Java 要在虚拟机里运行&#xff1f; 先说结论&#xff1a; 可以一次编译&#xff0c;在各个硬件平台如 Windows_x64、Linux_aarch64&#xff09;都可以执行建立一个托管环境&#xff08;Managed Runtime&#xff09;&#xff0c;这个托管环境能够代替我们处理一些代码…...

PCL点云库入门——PCL库可视化之PCLVisualizer类显示复杂点云信息等(持续更新)

1、PCLVisualizer类可视化 PCLVisualizer类作为PCL库可视化到的高级功能&#xff0c;不仅支持点云等数据的可视化&#xff0c;还提供了丰富的交互功能和自定义选项&#xff0c;如颜色调整、视角切换、标注添加等。用户可以通过PCLVisualizer类轻松实现复杂的数据分析和处理任务…...

Hugface国内镜像

问题&#xff1a; urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(hosthuggingface.co, port443): Max retries exceeded with url: /Salesforce/blip-image-captioning-base/resolve/main/preprocessor_config.json (Caused by ProxyError(Cannot connect to proxy.,…...

Vue3 重置ref或者reactive属性值

需要重新定义一个对象绑定复制给原对象 。 实例代码: const data () > ({groupId: ,groupCode: ,groupName: ,groupType: ,});const formData ref(data());//重置对象值 const reset()>{Object.assign(formData, data()…...

前端的Python入门指南(完):错误和异常处理策略及最佳实践

《前端的 Python 入门指南》系列文章&#xff1a; &#xff08;一&#xff09;&#xff1a;常用语法和关键字对比&#xff08;二&#xff09;&#xff1a;函数的定义、参数、作用域对比&#xff08;三&#xff09;&#xff1a;数据类型对比 - 彻底的一切皆对象实现和包装对象异…...

c++:std::map下标运算符的不合理使用

这是我分析之前遗留代码时发现的一个隐藏点&#xff1b;不过我并不认为这样使用std::map是合理的。 看看简化后的代码&#xff0c;v1、v2的值应该是多少呢&#xff1f; #include <map>std::map<int, int> cm[2];int get_cm_value(int device, int ctrl) { auto …...

音频数据采样入门详解 - 给Python初学者的简单解释

音频数据采样入门详解 - 给Python初学者的简单解释 声音是如何变成数字的&#xff1f;什么是采样率&#xff1f;为什么要懂这个&#xff1f;Python小例子总结 大家好&#xff01;今天我们来聊一个有趣的话题&#xff1a;音频数据是如何在计算机中处理的。让我用最简单的方式来解…...

vue el-dialog实现可拖拉

el-dialog实现拖拉&#xff0c;每次点击度居中显示&#xff0c;以下贴出代码具体实现&#xff0c;我是可以正常拖拉并且每次度显示在中间&#xff0c;效果还可以&#xff0c;需要的可以丢上去跑跑 组件部分&#xff1a; <el-dialog:visible.sync"dialogVisible"…...

iOS在项目中设置 Dev、Staging 和 Prod 三个不同的环境

在 Objective-C 项目中设置 Dev、Staging 和 Prod 三个不同的环境&#xff0c;并为每个环境使用不同的 Bundle ID&#xff0c;可以通过以下步骤实现&#xff1a; 步骤 1: 创建不同的 Build Configuration 打开项目&#xff1a; 启动 Xcode 并打开你的项目。 选择项目文件&…...

开源实时多模态AI Agent,搭载Gemini多模态API(在线体验)

今天发现一个惊艳的开源项目&#xff0c;利用多模态大模型API进行多智能体交互。支持RAG、搜索等。 TEN Agent 是一款由 TEN 提供支持的对​​话式 AI&#xff0c;集成了 Gemini 2.0 Multimodal Live API、OpenAI Realtime API、RTC 等。它提供实时的看、听和说功能&#xff0…...

【持续更新】Github实用命令

Intro 最近高强度使用github&#xff0c;遂小计于此作为备忘。 Basic github是一个代码管理软件&#xff0c;能够track文件变动并且管理版本&#xff0c;是当代coding必不可少的工具。当你安装好github在本地以后&#xff0c;你可以通过以下命令初始化当前文件夹&#xff08…...

B树的性质和插入过程

性质 平衡性&#xff1a;所有叶子节点都在同一层多路&#xff1a;m 阶 B 树 最多&#xff1a; m 个分支&#xff0c;m-1 个元素 最少&#xff1a; 根节点 2 个分支 1个元素 其他节点 ⌈ m / 2 ⌉ \lceil m/2\rceil ⌈m/2⌉ 个分支 ⌈ m / 2 ⌉ \lceil m/2\rceil ⌈m/2⌉ −…...

分布式链路追踪-02-Dapper 论文介绍

开源项目 auto-log 自动日志输出 概要 现代互联网服务通常被实现为复杂的、大规模的分布式系统。 这些应用程序是由软件模块的集合构建的&#xff0c;这些模块可能由不同的团队使用不同的编程语言开发&#xff0c;并且可以跨越多个物理设施的数千台机器。 在这样的环境中&…...

python:用 sklearn 构建线性回归模型,并评价

编写 test_sklearn_6.py 如下 # -*- coding: utf-8 -*- """ 使用 sklearn 估计器构建线性回归模型 """ import numpy as np import pandas as pd import matplotlib.pyplot as plt from matplotlib import rcParamsfrom sklearn import dataset…...

CTFHUB 信息泄露 备份文件下载-网站源码

根据提示应是猜测网站源码的备份文件&#xff0c;可以采用bp拼接文件名和后缀 开启bp抓包后设置第一个攻击点导入文件名 第二个攻击点导入后缀 开始暴力破解&#xff0c;有成功响应的 拼接到网站后缀后可以直接下载 解压缩后记事本的名字就是flag 总结&#xff1a; …...

Java String详解(三)

上一篇博客&#xff1a;Java String详解&#xff08;二&#xff09; 写在前面&#xff1a;大家好&#xff01;我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正&#xff0c;感谢大家的不吝赐教。我的唯一博客更新地址是&#xff1a;https://ac-fun.blo…...

在pycharm2024.3.1中配置anaconda3-2024-06环境

version: anaconda3-2024.06-1 pycharm-community-2024.3.1 1、安装anaconda和pycharm 最新版最详细Anaconda新手安装配置环境创建教程_anaconda配置-CSDN博客 【2024最新版】超详细Pycharm安装保姆级教程&#xff0c;Pycharm环境配置和使用指南&#xff0c;看完这一篇就够了…...

从0到1实现vue3+vite++elementuiPlus+ts的后台管理系统(一)

前言&#xff1a;从这篇文章开始实现vue3vite的后台管理系统&#xff0c;记录下自己搭建后台系统图的过程。 这篇文章完成项目的初始化和基本配置&#xff0c;这一步可以直接跟着vue3官网进行。整个系列只有前端部分&#xff0c;不涉及后端。 vue3官网&#xff1a;https://cn.…...

升级thinkphp8最新版本,升级后发现版本不变

升级thinkphp8.0.3最新版本8.1.1&#xff0c;升级后发现版本不变&#xff0c; 更新TP有两个方法 1 全部更新(所有插件都一起更新) composer update 2 只更新TP框架核心 composer update topthink/framework 造成可能有两个原因&#xff0c;一是缓存问题&#xff0c;二是更新…...

PPP协议

PPP是一种常见的广域网数据链路层协议&#xff0c;主要用于在全双工的链路上进行点到点的数据传输封装&#xff0c;支持同步传输和异步传输&#xff0c;通常用于VPN和拨号上网 PPP 概述 PPP一般运行在serial串口上&#xff0c;是一种广域网协议&#xff0c;PPP建立分为LCP&a…...

JAVA基础:数据类型

JAVA基础:数据类型 强类型语言 强类型语言(Strongly Typed Language)是指在编程语言中,每个变量都必须有一个明确的类型,并且在编译时会进行类型检查。 JAVA是强类型语言,所有变量必须先定义后使用。 弱类型语言 弱类型语言(Weakly Typed Language)是指在编程中类…...

ElasticSearch 数据聚合与运算

1、数据聚合 聚合&#xff08;aggregations&#xff09;可以让我们极其方便的实现数据的统计、分析和运算。实现这些统计功能的比数据库的 SQL 要方便的多&#xff0c;而且查询速度非常快&#xff0c;可以实现近实时搜索效果。 注意&#xff1a; 参加聚合的字段必须是 keywor…...

Nacos 3.0 Alpha 发布,在安全、泛用、云原生更进一步

自 2021 年发布以来&#xff0c;Nacos 2.0 在社区的支持下已走过近三年&#xff0c;期间取得了诸多成就。在高性能与易扩展性方面&#xff0c;Nacos 2.0 取得了显著进展&#xff0c;同时在易用性和安全性上也不断提升。想了解更多详细信息&#xff0c;欢迎阅读我们之前发布的回…...

GeoIP介绍

文章目录 GeoIP1. GeoIP的详细介绍2. 在Go语言中使用GeoIP GeoIP GeoIP是一种技术&#xff0c;它允许通过IP地址来查询地理位置信息&#xff0c;如国家、地区、城市等。这种技术在网络安全、内容分发、市场分析等领域有着广泛的应用。 1. GeoIP的详细介绍 原理&#xff1a; …...

详述 BigDecimal 的错误计算

摘要 详细阐述在使用 Java 的 BigDecimal 类时&#xff0c;可能产生的错误计算。 据 java中BigDecimal的介绍及使用&#xff0c;BigDecimal格式化&#xff0c;BigDecimal常见问题-CSDN博客 介绍&#xff1a;“BigDecimal 的执行顺序不能调换&#xff08;乘法交换律失效&am…...

3D Gaussian Splatting for Real-Time Radiance Field Rendering-简洁版

1. 研究背景与问题 传统的3D场景表示方法&#xff0c;如网格和点云&#xff0c;适合GPU加速的光栅化操作&#xff0c;但缺乏灵活性。而基于神经辐射场&#xff08;NeRF&#xff09;的表示方式&#xff0c;尽管质量高&#xff0c;但需要高成本的训练和渲染时间。此外&#xff0…...

(三)PyQT5+QGIS+python使用经验——解决各版本不兼容问题

一、问题描述 基础环境&#xff1a;Windows10&#xff08;64&#xff09; PyCharm2024 QGIS 3.22。 目的&#xff1a;解决之前python版本多&#xff0c;pyqt5以及QT Designer交互使用存在环境变量冲突矛盾&#xff0c;以及QGIS安装时自带python、pyqt5等问题。 尤其是在QT …...

uniapp navigateTo、redirectTo、reLaunch等页面路由跳转方法的区别

uni.switchTab 跳转到 tabBar 页面&#xff0c;并关闭其他所有非 tabBar 页面 // app.json {"tabBar": {"list": [{"pagePath": "index","text": "首页"},{"pagePath": "other","text&…...

[创业之路-198]:华为的成立发展与新中国的建立与发展路径的相似性比较

目录 一、公司比较 1、创业初期的艰难与挑战 2、坚持自主创新与研发 3、市场拓展与国际化战略 4、企业文化与社会责任 5、面临的挑战与应对策略 二、任正非管理企业的思想大量借鉴了毛泽东建国的思想 1、矛盾论与企业管理 2、群众路线与企业文化 3、战略思维与长远发…...

[Unity Shader]【图形渲染】【游戏开发】 Unity Shader与原始Shader的区别

在Unity中,Shader是用于控制如何渲染图形的程序,通常涉及到对图形管线的自定义操作。尽管所有的着色器都遵循基本的图形渲染流程,但Unity Shader和原始Shader(通常指OpenGL/DirectX等底层API的Shader)之间存在显著差异。理解这些区别能帮助开发者更好地在Unity环境下进行图…...

JAVA学习日记(二十七)反射

一、反射的概述 二、获取Class对象的三种方式 import testpackage.Student;public class Main {public static void main(String[] args) throws ClassNotFoundException {//获取.class对象的三种方式//1. Class.forName("全类名")//2. 类名.class//3. 对象.getClas…...

PyTorch中apex的安装方式

apex是NVIDIA开发的基于PyTorch的混合精度训练加速神器&#xff0c;能够增加运算速度&#xff0c;并且减少显存的占用。 Github地址&#xff1a;https://github.com/NVIDIA/apex官方教程&#xff1a;https://nvidia.github.io/apex/ 安装方式 需要注意的是apex的安装不能通过…...

JavaScript网络请求( XMLHttpRequest 对象,进度事件, 跨源资源共享)

一、 XMLHttpRequest 对象 IE5 是第一个引入 XHR 对象的浏览器。这个对象是通过 ActiveX 对象实现并包含在 MSXML 库中 的。为此&#xff0c; XHR 对象的 3 个版本在浏览器中分别被暴露为 MSXML2.XMLHttp 、 MSXML2.XMLHttp.3.0 和 MXSML2.XMLHttp.6.0 。 所有现代…...

Android Studio、JDK、AGP、Gradle、kotlin-gradle-plugin 兼容性问题

文章目录 问题&#xff1a;解决办法&#xff1a;gradle与 java的版本兼容AGP与Gradle的版本兼容kotlin 与 jvm 的版本兼容KGP、Gradle、AGP兼容关系kotlin 与 java 的编译版本配置 问题&#xff1a; 你从githb上clone了一个项目&#xff0c;本地跑的时候&#xff0c;各种报错。…...

滑动窗口(定长窗口)

题目一&#xff1a;找到字符串中所有字母异位词 438. 找到字符串中所有字母异位词 - 力扣&#xff08;LeetCode&#xff09; ​ ​ 分析 异位次&#xff0c;就是通过排序之后可以跟哪个单词一样&#xff0c;例如 hello 跟 lleho 这是定长窗口&#xff0c; 窗口维护在p的…...

Vue Web开发(九)

1. 用户管理 1.1. user页面下的diolog表单 本节课完成user页面下的diolog表单&#xff0c;表单里的元素都是动态渲染&#xff0c;以一个CommonForm组件的形式放入user页面。 运用Element ui Form表单。 1.1.1. CommonForm组件 在src/components下新建CommonForm.vue组件&am…...

go语言zero框架下的日志记录的sdk实战案例

在 Go 语言中&#xff0c;构建一个日志 SDK 是常见的开发任务&#xff0c;尤其是当你希望将日志记录集中管理时。一个好的日志 SDK 可以帮助你规范化日志记录的方式&#xff0c;并将日志存储到不同的地方&#xff08;例如&#xff1a;控制台、文件、数据库、远程日志服务等&…...