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 ..
只要 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
第三步: 发布生成的动态库和相关的头文件
- head.h
- 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简介 源文件(.cpp / .c)要经过 工具链 1.1 工具链 1、预处理&#…...
C++类模板的应用
template <class T> class mylist{ public: // 这是一个链表的节点 struct Link{ T val; Link* next; } 增 :insert(T val) 在链表中创建新节点,节点上保存的数据为 val 删:remove(T val) 移除链表中数据为 val 的节点 改: operator[](…...
Ubuntu 18.04无有线图表且无法设置有线网络
问题背景: 今天在登陆自己的虚拟机Ubuntu系统的时候突然出现 有线连接无法连接的问题,有线连接的图标变为没有了,无法点击网络菜单的Setting模块选项。我的虚拟机有线网络连接方式是NAT方式。 没有如下有线连接图标 解决方法: …...
QoS分类和标记
https://zhuanlan.zhihu.com/p/160937314 1111111 分类和标记是识别每个数据包优先级的过程。 这是QoS控制的第一步,应在源主机附近完成。 分组通常通过其分组报头来分类。下图指定的规则仔细检查了数据包头 : 下表列出了分类标准: 普通二…...
企业内训|阅读行业产品运营实战训练营-某运营商数字娱乐公司
近日,TsingtaoAI公司为某运营商旗下数字娱乐公司组织的“阅读行业产品运营实战训练营”在杭州落下帷幕。此次训练营由TsingtaoAI资深互联网产品专家程靖主持。该公司的业务骨干——来自内容、市场、业务、产品与技术等跨部门核心岗位、拥有8-10年实战经验的中坚力量…...
杭州乘云联合信通院发布《云计算智能化可观测性能力成熟度模型》
原文地址:杭州乘云联合中国信通院等单位正式发布《云计算智能化可观测性能力成熟度模型》标准 2024年12月3日,由全球数字经济大会组委会主办、中国信通院承办的 2024全球数字经济大会 云AI计算创新发展大会(2024 Cloud AI Compute Ignite&…...
SimAI万卡集群模拟器,LLM大模型训练通信计算模拟
SimAI,是阿里巴巴构建的一个统一的模拟器,旨在大规模精确有效地模拟LLM训练过程。通过将训练框架、内核计算和集体通信库有选择地高保真集成到仿真过程中,SimAI在仿真中实现了高精度。 简单点来说,SimAI就是模拟,大模…...
Axure9设置画布固定
在使用AxureRP9设计原型时,如果遇到画布在拖动时变得难以控制,可以尝试在Windows系统中通过‘文件’>‘首选项’,或在Mac系统中通过‘AxureRP9’>‘偏好设置’进行设置,以稳定画布的行为。 现象 页面底层的画布࿰…...
window.getSelection() 获取划线内容并实现 dom 追随功能
功能:鼠标对一段文本中某些文字进行划线之后,需要在当前划线文本处出现一个功能按钮显示对划线内容进行操作,比如收藏、添加样本库等功能。 一、需要了解的鼠标事件对象属性 给 dom 元素注册鼠标事件之后,会有 event 属性&#…...
mybatis-plus超详细讲解
mybatis-plus (简化代码神器) 地址:https://mp.baomidou.com/ 目录 mybatis-plus 简介 特性 支持数据库 参与贡献 快速指南 1、创建数据库 mybatis_plus 2、导入相关的依赖 3、创建对应的文件夹 4、编写配置文件 5、编写代码 …...
浏览器可以直接请求 websocket
一、原生支持 浏览器原生支持 WebSocket 协议,这使得开发者可以直接在 JavaScript 代码中使用 WebSocket 来建立与服务器的双向通信通道。 const socket new WebSocket("ws://localhost:8080");socket.addEventListener("open", function (e…...
* 和 .* 的区别(MATLAB)
在 MATLAB 中,* 和 .* 都是用来进行乘法操作的运算符,但它们有不同的应用场景。我们将从数学和编程的角度详细解析这两者的区别,并且讲解 MATLAB 中 . 运算符的其他常见用法。 1. * 和 .* 的区别 *:矩阵乘法(线性代数…...
51c视觉~合集30
我自己的原文哦~ https://blog.51cto.com/whaosoft/12059371 #SaRA 修改一行代码就能实现高效微调!上海交大&腾讯开源:兼顾原始生成和下游任务 仅修改一行训练代码即可实现微调过程。 文章链接:https://arxiv.org/pdf/2409.06633 …...
JVM虚拟机总揽
为什么 Java 要在虚拟机里运行? 先说结论: 可以一次编译,在各个硬件平台如 Windows_x64、Linux_aarch64)都可以执行建立一个托管环境(Managed Runtime),这个托管环境能够代替我们处理一些代码…...
PCL点云库入门——PCL库可视化之PCLVisualizer类显示复杂点云信息等(持续更新)
1、PCLVisualizer类可视化 PCLVisualizer类作为PCL库可视化到的高级功能,不仅支持点云等数据的可视化,还提供了丰富的交互功能和自定义选项,如颜色调整、视角切换、标注添加等。用户可以通过PCLVisualizer类轻松实现复杂的数据分析和处理任务…...
Hugface国内镜像
问题: 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 入门指南》系列文章: (一):常用语法和关键字对比(二):函数的定义、参数、作用域对比(三):数据类型对比 - 彻底的一切皆对象实现和包装对象异…...
c++:std::map下标运算符的不合理使用
这是我分析之前遗留代码时发现的一个隐藏点;不过我并不认为这样使用std::map是合理的。 看看简化后的代码,v1、v2的值应该是多少呢? #include <map>std::map<int, int> cm[2];int get_cm_value(int device, int ctrl) { auto …...
音频数据采样入门详解 - 给Python初学者的简单解释
音频数据采样入门详解 - 给Python初学者的简单解释 声音是如何变成数字的?什么是采样率?为什么要懂这个?Python小例子总结 大家好!今天我们来聊一个有趣的话题:音频数据是如何在计算机中处理的。让我用最简单的方式来解…...
vue el-dialog实现可拖拉
el-dialog实现拖拉,每次点击度居中显示,以下贴出代码具体实现,我是可以正常拖拉并且每次度显示在中间,效果还可以,需要的可以丢上去跑跑 组件部分: <el-dialog:visible.sync"dialogVisible"…...
iOS在项目中设置 Dev、Staging 和 Prod 三个不同的环境
在 Objective-C 项目中设置 Dev、Staging 和 Prod 三个不同的环境,并为每个环境使用不同的 Bundle ID,可以通过以下步骤实现: 步骤 1: 创建不同的 Build Configuration 打开项目: 启动 Xcode 并打开你的项目。 选择项目文件&…...
开源实时多模态AI Agent,搭载Gemini多模态API(在线体验)
今天发现一个惊艳的开源项目,利用多模态大模型API进行多智能体交互。支持RAG、搜索等。 TEN Agent 是一款由 TEN 提供支持的对话式 AI,集成了 Gemini 2.0 Multimodal Live API、OpenAI Realtime API、RTC 等。它提供实时的看、听和说功能࿰…...
【持续更新】Github实用命令
Intro 最近高强度使用github,遂小计于此作为备忘。 Basic github是一个代码管理软件,能够track文件变动并且管理版本,是当代coding必不可少的工具。当你安装好github在本地以后,你可以通过以下命令初始化当前文件夹(…...
B树的性质和插入过程
性质 平衡性:所有叶子节点都在同一层多路:m 阶 B 树 最多: m 个分支,m-1 个元素 最少: 根节点 2 个分支 1个元素 其他节点 ⌈ m / 2 ⌉ \lceil m/2\rceil ⌈m/2⌉ 个分支 ⌈ m / 2 ⌉ \lceil m/2\rceil ⌈m/2⌉ −…...
分布式链路追踪-02-Dapper 论文介绍
开源项目 auto-log 自动日志输出 概要 现代互联网服务通常被实现为复杂的、大规模的分布式系统。 这些应用程序是由软件模块的集合构建的,这些模块可能由不同的团队使用不同的编程语言开发,并且可以跨越多个物理设施的数千台机器。 在这样的环境中&…...
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 信息泄露 备份文件下载-网站源码
根据提示应是猜测网站源码的备份文件,可以采用bp拼接文件名和后缀 开启bp抓包后设置第一个攻击点导入文件名 第二个攻击点导入后缀 开始暴力破解,有成功响应的 拼接到网站后缀后可以直接下载 解压缩后记事本的名字就是flag 总结: …...
Java String详解(三)
上一篇博客:Java String详解(二) 写在前面:大家好!我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正,感谢大家的不吝赐教。我的唯一博客更新地址是: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安装保姆级教程,Pycharm环境配置和使用指南,看完这一篇就够了…...
从0到1实现vue3+vite++elementuiPlus+ts的后台管理系统(一)
前言:从这篇文章开始实现vue3vite的后台管理系统,记录下自己搭建后台系统图的过程。 这篇文章完成项目的初始化和基本配置,这一步可以直接跟着vue3官网进行。整个系列只有前端部分,不涉及后端。 vue3官网:https://cn.…...
升级thinkphp8最新版本,升级后发现版本不变
升级thinkphp8.0.3最新版本8.1.1,升级后发现版本不变, 更新TP有两个方法 1 全部更新(所有插件都一起更新) composer update 2 只更新TP框架核心 composer update topthink/framework 造成可能有两个原因,一是缓存问题,二是更新…...
PPP协议
PPP是一种常见的广域网数据链路层协议,主要用于在全双工的链路上进行点到点的数据传输封装,支持同步传输和异步传输,通常用于VPN和拨号上网 PPP 概述 PPP一般运行在serial串口上,是一种广域网协议,PPP建立分为LCP&a…...
JAVA基础:数据类型
JAVA基础:数据类型 强类型语言 强类型语言(Strongly Typed Language)是指在编程语言中,每个变量都必须有一个明确的类型,并且在编译时会进行类型检查。 JAVA是强类型语言,所有变量必须先定义后使用。 弱类型语言 弱类型语言(Weakly Typed Language)是指在编程中类…...
ElasticSearch 数据聚合与运算
1、数据聚合 聚合(aggregations)可以让我们极其方便的实现数据的统计、分析和运算。实现这些统计功能的比数据库的 SQL 要方便的多,而且查询速度非常快,可以实现近实时搜索效果。 注意: 参加聚合的字段必须是 keywor…...
Nacos 3.0 Alpha 发布,在安全、泛用、云原生更进一步
自 2021 年发布以来,Nacos 2.0 在社区的支持下已走过近三年,期间取得了诸多成就。在高性能与易扩展性方面,Nacos 2.0 取得了显著进展,同时在易用性和安全性上也不断提升。想了解更多详细信息,欢迎阅读我们之前发布的回…...
GeoIP介绍
文章目录 GeoIP1. GeoIP的详细介绍2. 在Go语言中使用GeoIP GeoIP GeoIP是一种技术,它允许通过IP地址来查询地理位置信息,如国家、地区、城市等。这种技术在网络安全、内容分发、市场分析等领域有着广泛的应用。 1. GeoIP的详细介绍 原理: …...
详述 BigDecimal 的错误计算
摘要 详细阐述在使用 Java 的 BigDecimal 类时,可能产生的错误计算。 据 java中BigDecimal的介绍及使用,BigDecimal格式化,BigDecimal常见问题-CSDN博客 介绍:“BigDecimal 的执行顺序不能调换(乘法交换律失效&am…...
3D Gaussian Splatting for Real-Time Radiance Field Rendering-简洁版
1. 研究背景与问题 传统的3D场景表示方法,如网格和点云,适合GPU加速的光栅化操作,但缺乏灵活性。而基于神经辐射场(NeRF)的表示方式,尽管质量高,但需要高成本的训练和渲染时间。此外࿰…...
(三)PyQT5+QGIS+python使用经验——解决各版本不兼容问题
一、问题描述 基础环境:Windows10(64) PyCharm2024 QGIS 3.22。 目的:解决之前python版本多,pyqt5以及QT Designer交互使用存在环境变量冲突矛盾,以及QGIS安装时自带python、pyqt5等问题。 尤其是在QT …...
uniapp navigateTo、redirectTo、reLaunch等页面路由跳转方法的区别
uni.switchTab 跳转到 tabBar 页面,并关闭其他所有非 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的混合精度训练加速神器,能够增加运算速度,并且减少显存的占用。 Github地址:https://github.com/NVIDIA/apex官方教程:https://nvidia.github.io/apex/ 安装方式 需要注意的是apex的安装不能通过…...
JavaScript网络请求( XMLHttpRequest 对象,进度事件, 跨源资源共享)
一、 XMLHttpRequest 对象 IE5 是第一个引入 XHR 对象的浏览器。这个对象是通过 ActiveX 对象实现并包含在 MSXML 库中 的。为此, XHR 对象的 3 个版本在浏览器中分别被暴露为 MSXML2.XMLHttp 、 MSXML2.XMLHttp.3.0 和 MXSML2.XMLHttp.6.0 。 所有现代…...
Android Studio、JDK、AGP、Gradle、kotlin-gradle-plugin 兼容性问题
文章目录 问题:解决办法:gradle与 java的版本兼容AGP与Gradle的版本兼容kotlin 与 jvm 的版本兼容KGP、Gradle、AGP兼容关系kotlin 与 java 的编译版本配置 问题: 你从githb上clone了一个项目,本地跑的时候,各种报错。…...
滑动窗口(定长窗口)
题目一:找到字符串中所有字母异位词 438. 找到字符串中所有字母异位词 - 力扣(LeetCode) 分析 异位次,就是通过排序之后可以跟哪个单词一样,例如 hello 跟 lleho 这是定长窗口, 窗口维护在p的…...
Vue Web开发(九)
1. 用户管理 1.1. user页面下的diolog表单 本节课完成user页面下的diolog表单,表单里的元素都是动态渲染,以一个CommonForm组件的形式放入user页面。 运用Element ui Form表单。 1.1.1. CommonForm组件 在src/components下新建CommonForm.vue组件&am…...
go语言zero框架下的日志记录的sdk实战案例
在 Go 语言中,构建一个日志 SDK 是常见的开发任务,尤其是当你希望将日志记录集中管理时。一个好的日志 SDK 可以帮助你规范化日志记录的方式,并将日志存储到不同的地方(例如:控制台、文件、数据库、远程日志服务等&…...