makefile 学习(5)完整的makefile模板
参考自:
- (1)深度学习部署笔记(二): g++, makefile语法,makefile自己的CUDA编程模板
- (2)https://zhuanlan.zhihu.com/p/396448133
- (3) 一个挺好的工程模板,(https://github.com/shouxieai/cpp-proj-template)
1. c++ 编译流程图

2. 使用makefile编译工程
- Makefile是一个经典的构建工具,使用它可以根据一系列规则构建程序。在编写
Makefile的过程中,需要了解一些底层的细节,包括链接器,编译器等等。Makefile可以被配置成在所有的平台上都能够使用,非常适合轻量级项目和较小的项目。 - 而
CMake则是一种构建工具的高级语言,可以自动生成适合各种平台和编译器的Makefile文件,同时也能生成Visual Studio等IDE所需要的工程文件。CMake使用的是一种高级的、面向目标的语言,可以实现更加复杂的构建任务。CMake的优点在于它可以跨平台地生成Makefile文件,同时具有很好的可读性和可维护性,非常适合大型的、复杂的项目。CMake的缺点在于它的学习曲线相对较陡,需要学习一些新的概念和语法。 - 总之,Makefile和CMake各自有其优缺点,在实际使用中需要根据项目的规模和需求选择适合的构建工具。
2.1 demo
(1) 一个makefile的demo
- 新建一个main.cpp文件和一个01kernel.cu文件
#include <iostream>
using namespace std;int main()
{cout << "Hello CUDA" << endl;return 0;
}
- 新建一个Makefile文件
cpp_srcs := $(shell find src -name "*.cpp")
cpp_objs := $(patsubst %.cpp,%.o,$(cpp_srcs))
cpp_objs := $(subst src/,objs/,$(cpp_objs))debug :@echo $(cpp_objs)
- 终端执行 make debug 如果有问题就是有bug
(2) 逐行解释这个小demo
- 定义变量
cpp_srcs,它的值是通过调用find命令在 src 目录下查找所有以 .cpp 结尾的文件,并将它们的路径存入 cpp_srcs 变量中。
cpp_srcs := $(shell find src -name "*.cpp")
- 定义变量
cpp_objs,它的值是将 cpp_srcs 变量中所有.cpp后缀的文件名都替换成以.o结尾的目标文件名,并将这些目标文件名保存到 cpp_objs 变量中。
cpp_objs := $(patsubst %.cpp,%.o,$(cpp_srcs))
- 将
cpp_objs变量中的所有 src/ 替换为 objs/,并将替换后的值存储回 cpp_objs 变量
cpp_objs := $(subst src/,objs/,$(cpp_objs))
- 创建一个名为 debug 的伪目标,它的命令是打印 cpp_objs 变量的值,@ 告诉 Make 不要显示命令行上的命令,只显示命令的输出。
debug :@echo $(cpp_objs)
2.2 makefile的一个简单模板
# 定义cpp源码路径,并转换为objs目录先的o文件
cpp_srcs := $(shell find src -name "*.cpp")
cpp_objs := $(patsubst %.cpp,%.o,$(cpp_srcs))
cpp_objs := $(subst src/,objs/,$(cpp_objs))# 定义cu源码路径,并转换为objs目录先的cuo文件
# 如果cpp文件和cu名字一样,把.o换成.cuo
cu_srcs := $(shell find src -name "*.cu") # 全部src下的*.cu存入变量cu_srcs
cu_objs := $(patsubst %.cu,%.cuo,$(cu_srcs)) # cu_srcs中全部.cu换成.o
cu_objs := $(subst src/,objs/,$(cu_objs)) # cu_objs src/换成objs/# 定义名称参数
workspace := workspace
binary := pro# makefile中定义cpp的编译方式
# $@:代表规则中的目标文件(生成项)
# $<:代表规则中的第一个依赖文件
# $^:代表规则中的所有依赖文件,以空格分隔
# $?:代表规则中所有比目标文件更新的依赖文件,以空格分隔# 定义cpp文件的编译方式
# @echo Compile $< 输出正在编译的源文件的名称
objs/%.o : src/%.cpp@mkdir -p $(dir $@)@echo Compile $< @g++ -c $^ -o $@ # 定义.cu文件的编译方式
objs/%.cuo : src/%.cu@mkdir -p $(dir $@)@echo Compile $< @nvcc -c $^ -o $@# 定义workspace/pro文件的编译
$(workspace)/$(binary) : $(cpp_objs) $(cu_objs)@mkdir -p $(dir $@)@echo Link $^@g++ $^ -o $@# 定义pro快捷编译指令,这里只发生编译,不执行
# 快捷指令就是make pro
pro : $(workspace)/$(binary)# 定义指令并且执行的指令,并且执行目录切换到workspace下
run : pro@cd $(workspace) && ./$(binary)debug :@echo $(cpp_objs)@echo $(cu_objs)
这里报错了,因为缺少了cuda的库文件,下面是查看自己cuda版本和找到在哪里的指令,以我的CUDA11.7为例, 去到目录下看看有什么库文件,我们当前需要一个cudaruntime的头文件
nvcc --version
whereis cuda-11.7
cuda-11: /usr/local/cuda-11.7
cd /usr/local/cuda-11.7/lib64
2.3 完整学习整个makefile文件
来看看最后要完成的工程目录
project/- src/- main.cpp- 01.kernel.cu- objs/- workspace/- Makefile
(1) 定义源码路径
- 这里定义源码路径的作用是为了在后续的代码中可以方便地引用源码文件,并将其编译成目标文件。具体地,使用find命令查找src目录下的所有扩展名为
.cpp和.cu的文件,然后将它们分别存储到cpp_srcs和cu_srcs变量中。接着,使用patsubst和subst函数将源码文件路径中的src/替换成objs/,并将它们分别存储到cpp_objs和cu_objs变量中,这样就得到了在objs目录下存储的目标文件列表。在后面的编译和链接过程中,这些目标文件(*.o, *.cuo)会被用来生成最终的可执行文件。
-objs目录中放置的是编译生成的目标文件,对于这个 makefile 来说,所有的.o和.cuo文件都会被放到objs目录下。在链接生成可执行文件时,makefile 会从这些目标文件中找到需要的文件进行链接。
# 定义cpp源码路径,并转换为objs目录先的o文件
cpp_srcs := $(shell find src -name "*.cpp")
cpp_objs := $(patsubst %.cpp,%.o,$(cpp_srcs))
cpp_objs := $(subst src/,objs/,$(cpp_objs))# 定义cu源码路径,并转换为objs目录先的cuo文件
# 如果cpp文件和cu名字一样,把.o换成.cuo
cu_srcs := $(shell find src -name "*.cu") # 全部src下的*.cu存入变量cu_srcs
cu_objs := $(patsubst %.cu,%.cuo,$(cu_srcs)) # cu_srcs中全部.cu换成.o
cu_objs := $(subst src/,objs/,$(cu_objs)) # cu_objs src/换成objs/
(2) 定义可执行文件及存放位置
这里定义的名称参数 workspace 和 binary 是用来指定工作空间和生成的可执行文件名称的。在这个 Makefile 中,workspace 表示的是工作空间的目录名称,binary 表示生成的可执行文件的名称。这些参数可以在 Makefile 中的其它规则中使用,例如在链接时指定目标文件路径和生成的可执行文件名称等。
workspace := workspace
binary := pro
(3) 定义头文件,库文件和链接目标
- 因为编译cuda环境需要用到
libcudart.so这个库,cudart 是 CUDA runtime库,CUDA编程必须用到的 - 先整个定义了,后面用foreach一次性加进来
- 每个人的cuda的安装位置不一样,可以用
whereis cuda-版本查找位置 - 编译的过程中需要查找
头文件,库文件,include_path,library_path告诉编译器去哪里找头文件,库文件 link_librarys是告诉链接器需要链接那些库文件
# 定义头文件库文件和链接目标,后面用foreach一次性增加
include_paths := /usr/local/cuda-11.7/include
library_paths := /usr/local/cuda-11.7/lib64
link_librarys := cudart
(4) 定义编译选项
# 定义编译选项
cpp_compile_flags := -m64 -fPIC -g -O0 -std=c++11
cu_compile_flags := -m64 -g -O0 -std=c++11
- -m64:表示编译器生成的代码是 64 位的。
- -fPIC:表示编译器要生成位置独立的代码。
- -g:表示编译器会在生成的目标文件中加入调试信息,方便进行调试。
- -O0:表示关闭优化。
- -std=c++11:表示采用 C++11 标准进行编译。
(5)合并选项
-L指定链接时查找的目录-l指定链接的目标名称,符合libname.so -lname 规则-I指定编译时头文件查找目录run path链接的时查找动态链接库文件的路径,让程序运行的时候,自动查找并加载动态链接库
rpath := $(foreach item,$(link_librarys),-Wl,-rpath=$(item))
include_paths := $(foreach item,$(include_paths),-I$(item))
library_paths := $(foreach item,$(library_paths),-L$(item))
link_librarys := $(foreach item,$(link_librarys),-l$(item))
(6) 把合并后的选项给到编译器选项
cpp_compile_flags += $(include_paths): 将include_paths添加到cpp_compile_flags中,用于在编译C++源代码时指定头文件搜索路径。cu_compile_flags += $(include_paths): 将include_paths添加到cu_compile_flags中,用于在编译CUDA源代码时指定头文件搜索路径。link_flags := $(rpath) $(library_paths) $(link_librarys): 将rpath、library_paths、link_librarys合并成一个链接选项link_flags。rpath指定运行时库搜索路径,library_paths指定链接库搜索路径,link_librarys指定要链接的库文件名。
cpp_compile_flags += $(include_paths)
cu_compile_flags += $(include_paths)
link_flags := $(rpath) $(library_paths) $(link_librarys)
(7) 定义cpp cuda编译方式
- 把
.cpp .cu源文件 编译成目标文件.o .cuo,放在objs里面 .cpp, .cu源文件是依赖项,生成目标文件.o .cuo
# 定义cpp文件的编译方式
# @echo Compile $< 输出正在编译的源文件的名称
objs/%.o : src/%.cpp@mkdir -p $(dir $@)@echo Compile $< @g++ -c $^ -o $@ $(cpp_compile_flags)# 定义.cu文件的编译方式
objs/%.cuo : src/%.cu@mkdir -p $(dir $@)@echo Compile $< @nvcc -c $^ -o $@ $(cu_compile_flags)
(8) 在workspace下编译出可执行文件
- 上面.cpp, .cu文件编译出来的结果在这里就是依赖项
-L./objs表示告诉链接器在当前目录下寻找库文件,./objs 是指定的路径。实际上,./objs 是目标文件存储的路径,不是库文件存储的路径,这里写的是 -L./objs 只是为了指定链接时查找目录的路径。
# 定义workspace/pro文件的编译
$(workspace)/$(binary) : $(cpp_objs) $(cu_objs)@mkdir -p $(dir $@)@echo Link $^@g++ $^ -o $@ $(link_flags) -L./objs
(9)定义伪标签, 作为指令
- 上面编译的可执行文件,是指令依赖项
- 执行可执行文件
# 定义pro快捷编译指令,这里只发生编译,不执行
# 快捷指令就是make pro
pro : $(workspace)/$(binary)# 定义指令并且执行的指令,并且执行目录切换到workspace下
run : pro@cd $(workspace) && ./$(binary)debug :@echo $(cpp_objs)@echo $(cu_objs)clean : @rm -rf objs $(workspace)/$(binary)# 指定伪标签,作为指令
.PHONY : clean debug run pro
(10) 完整的makefile文件
# 定义cpp源码路径,并转换为objs目录先的o文件
cpp_srcs := $(shell find src -name "*.cpp")
cpp_objs := $(patsubst %.cpp,%.o,$(cpp_srcs))
cpp_objs := $(subst src/,objs/,$(cpp_objs))# 定义cu源码路径,并转换为objs目录先的cuo文件
# 如果cpp文件和cu名字一样,把.o换成.cuo
cu_srcs := $(shell find src -name "*.cu") # 全部src下的*.cu存入变量cu_srcs
cu_objs := $(patsubst %.cu,%.cuo,$(cu_srcs)) # cu_srcs中全部.cu换成.o
cu_objs := $(subst src/,objs/,$(cu_objs)) # cu_objs src/换成objs/# 定义可执行文件存放目录以及可执行文件名
workspace := workspace
binary := pro# 定义头文件库文件和链接目标,后面用foreach一次性增加
include_paths := /usr/local/cuda-11.7/include
library_paths := /usr/local/cuda-11.7/lib64
link_librarys := cudart# 定义编译选项
cpp_compile_flags := -m64 -fPIC -g -O0 -std=c++11
cu_compile_flags := -m64 -g -O0 -std=c++11# 对头文件, 库文件,目标统一增加 -I,-L-l
rpath := $(foreach item,$(link_librarys),-Wl,-rpath=$(item))
include_paths := $(foreach item,$(include_paths),-I$(item))
library_paths := $(foreach item,$(library_paths),-L$(item))
link_librarys := $(foreach item,$(link_librarys),-l$(item))# 合并选项
# 合并完选项后就可以给到编译方式里面去了
cpp_compile_flags += $(include_paths)
cu_compile_flags += $(include_paths)
link_flags := $(rpath) $(library_paths) $(link_librarys)# makefile中定义cpp的编译方式
# $@:代表规则中的目标文件(生成项)
# $<:代表规则中的第一个依赖文件
# $^:代表规则中的所有依赖文件,以空格分隔
# $?:代表规则中所有比目标文件更新的依赖文件,以空格分隔# 定义cpp文件的编译方式
# @echo Compile $< 输出正在编译的源文件的名称
objs/%.o : src/%.cpp@mkdir -p $(dir $@)@echo Compile $< @g++ -c $^ -o $@ $(cpp_compile_flags)# 定义.cu文件的编译方式
objs/%.cuo : src/%.cu@mkdir -p $(dir $@)@echo Compile $< @nvcc -c $^ -o $@ $(cu_compile_flags)# 定义workspace/pro文件的编译
$(workspace)/$(binary) : $(cpp_objs) $(cu_objs)@mkdir -p $(dir $@)@echo Link $^@g++ $^ -o $@ $(link_flags) -L./objs# 定义pro快捷编译指令,这里只发生编译,不执行
# 快捷指令就是make pro
pro : $(workspace)/$(binary)# 定义指令并且执行的指令,并且执行目录切换到workspace下
run : pro@cd $(workspace) && ./$(binary)debug :@echo $(cpp_objs)@echo $(cu_objs)clean : @rm -rf objs $(workspace)/$(binary)# 指定伪标签,作为指令
.PHONY : clean debug run pro
3. 推荐一个makefile工程
超全面和详细的一个makefil工程,值得学习借鉴
cc := g++
name := pro
workdir := workspace
srcdir := src
objdir := objs
stdcpp := c++11
cuda_home := /home/yuanwushui/anaconda3/lib/python3.9/site-packages/trtpy/trt8cuda112cudnn8
syslib := /home/yuanwushui/anaconda3/lib/python3.9/site-packages/trtpy/lib
cpp_pkg := /home/yuanwushui/anaconda3/lib/python3.9/site-packages/trtpy/cpp-packages #opencv4.2
cuda_arch :=
nvcc := $(cuda_home)/bin/nvcc -ccbin=$(cc)# 定义cpp的路径查找和依赖项mk文件
cpp_srcs := $(shell find $(srcdir) -name "*.cpp")
cpp_objs := $(cpp_srcs:.cpp=.cpp.o)
cpp_objs := $(cpp_objs:$(srcdir)/%=$(objdir)/%)
cpp_mk := $(cpp_objs:.cpp.o=.cpp.mk)# 定义cu文件的路径查找和依赖项mk文件
cu_srcs := $(shell find $(srcdir) -name "*.cu")
cu_objs := $(cu_srcs:.cu=.cu.o)
cu_objs := $(cu_objs:$(srcdir)/%=$(objdir)/%)
cu_mk := $(cu_objs:.cu.o=.cu.mk)# 定义opencv和cuda需要用到的库文件
link_cuda := cudart cudnn
link_trtpro :=
link_tensorRT := nvinfer nvinfer_plugin
link_opencv := opencv_core opencv_imgproc opencv_imgcodecs opencv_videoio opencv_video opencv_highgui
link_sys := stdc++ dl protobuf
link_librarys := $(link_cuda) $(link_tensorRT) $(link_sys) $(link_opencv)# 定义头文件路径,请注意斜杠后边不能有空格
# 只需要写路径,不需要写-I
include_paths := src \$(cuda_home)/include/cuda \$(cuda_home)/include/tensorRT \$(cpp_pkg)/opencv4.2/include \$(cuda_home)/include/protobuf \include# 定义库文件路径,只需要写路径,不需要写-L
library_paths := $(cuda_home)/lib64 $(syslib) $(cpp_pkg)/opencv4.2/lib# 把library path给拼接为一个字符串,例如a b c => a:b:c
# 然后使得LD_LIBRARY_PATH=a:b:c
empty :=
library_path_export := $(subst $(empty) $(empty),:,$(library_paths))# 把库路径和头文件路径拼接起来成一个,批量自动加-I、-L、-l
run_paths := $(foreach item,$(library_paths),-Wl,-rpath=$(item))
include_paths := $(foreach item,$(include_paths),-I$(item))
library_paths := $(foreach item,$(library_paths),-L$(item))
link_librarys := $(foreach item,$(link_librarys),-l$(item))# 如果是其他显卡,请修改-gencode=arch=compute_75,code=sm_75为对应显卡的能力
# 显卡对应的号码参考这里:https://developer.nvidia.com/zh-cn/cuda-gpus#compute
# 如果是 jetson nano,提示找不到-m64指令,请删掉 -m64选项。不影响结果
cpp_compile_flags := -std=$(stdcpp) -w -g -O0 -m64 -fPIC -fopenmp -pthread
cu_compile_flags := -std=$(stdcpp) -w -g -O0 -m64 $(cuda_arch) -Xcompiler "$(cpp_compile_flags)"
link_flags := -pthread -fopenmp -Wl,-rpath='$$ORIGIN'cpp_compile_flags += $(include_paths)
cu_compile_flags += $(include_paths)
link_flags += $(library_paths) $(link_librarys) $(run_paths)# 如果头文件修改了,这里的指令可以让他自动编译依赖的cpp或者cu文件
ifneq ($(MAKECMDGOALS), clean)
-include $(cpp_mk) $(cu_mk)
endif$(name) : $(workdir)/$(name)all : $(name)
run : $(name)@cd $(workdir) && ./$(name) $(run_args)$(workdir)/$(name) : $(cpp_objs) $(cu_objs)@echo Link $@@mkdir -p $(dir $@)@$(cc) $^ -o $@ $(link_flags)$(objdir)/%.cpp.o : $(srcdir)/%.cpp@echo Compile CXX $<@mkdir -p $(dir $@)@$(cc) -c $< -o $@ $(cpp_compile_flags)$(objdir)/%.cu.o : $(srcdir)/%.cu@echo Compile CUDA $<@mkdir -p $(dir $@)@$(nvcc) -c $< -o $@ $(cu_compile_flags)# 编译cpp依赖项,生成mk文件
$(objdir)/%.cpp.mk : $(srcdir)/%.cpp@echo Compile depends C++ $<@mkdir -p $(dir $@)@$(cc) -M $< -MF $@ -MT $(@:.cpp.mk=.cpp.o) $(cpp_compile_flags)# 编译cu文件的依赖项,生成cumk文件
$(objdir)/%.cu.mk : $(srcdir)/%.cu@echo Compile depends CUDA $<@mkdir -p $(dir $@)@$(nvcc) -M $< -MF $@ -MT $(@:.cu.mk=.cu.o) $(cu_compile_flags)# 定义清理指令
clean :@rm -rf $(objdir) $(workdir)/$(name) $(workdir)/*.trtmodel $(workdir)/*.onnx @rm -rf $(workdir)/image-draw.jpg $(workdir)/input-image.jpg $(workdir)/pytorch.jpg# 防止符号被当做文件
.PHONY : clean run $(name)# 导出依赖库路径,使得能够运行起来
export LD_LIBRARY_PATH:=$(library_path_export)相关文章:
makefile 学习(5)完整的makefile模板
参考自: (1)深度学习部署笔记(二): g, makefile语法,makefile自己的CUDA编程模板(2)https://zhuanlan.zhihu.com/p/396448133(3) 一个挺好的工程模板,(https://github.com/shouxieai/cpp-proj-template) 1. c 编译流…...
专业远程控制如何塑造安全体系?向日葵“全流程安全闭环”解析
安全是远程控制的重中之重,作为国民级远程控制品牌,向日葵远程控制就极为注重安全远控服务的塑造。近期向日葵发布了以安全和核心的新版“向日葵15”以及同步发布《贝锐向日葵远控安全标准白皮书》(下简称《白皮书》),…...
node.js解决输出中文乱码问题
个人简介 👨🏻💻个人主页:九黎aj 🏃🏻♂️幸福源自奋斗,平凡造就不凡 🌟如果文章对你有用,麻烦关注点赞收藏走一波,感谢支持! 🌱欢迎订阅我的…...
CentOS 7 使用异步网络框架Libevent
CentOS 7 安装Libevent库 libevent github地址:https://github.com/libevent/libevent 步骤1:首先,你需要下载libevent的源代码。你可以从github或者源代码官方网站下载。并上传至/usr/local/source_code/ 步骤2:下载完成后&…...
枚举 B. Lorry
Problem - B - Codeforces 题目大意:给物品数量 n n n,体积为 v ( 0 ≤ v ≤ 1 e 9 ) v_{(0 \le v \le 1e9)} v(0≤v≤1e9),第一行读入 n , v n, v n,v,之后 n n n行,读入 n n n个物品,之后每行依次是体…...
ON1 Photo RAW 2024 for Mac——专业照片编辑的终极利器
ON1 Photo RAW 2024 for Mac是一款专为Mac用户打造的照片编辑器,以其强大的功能和易用的操作,让你的照片编辑工作变得轻松愉快。 一、强大的RAW处理能力 ON1 Photo RAW 2024支持大量的RAW格式照片,能够让你在编辑过程中获得更多的自由度和更…...
从word复制内容到wangEditor富文本框的时候会把html标签也复制过来,如果只想实现直接复制纯文本,有什么好的实现方式
从word复制内容到wangEditor富文本框的时候会把html标签也复制过来,如果只想实现直接复制纯文本,有什么好的实现方式? 将 Word 中的内容复制到富文本编辑器时,常常会带有大量的 HTML 标签和样式,这可能导致不必要的格式…...
项目中如何配置数据可视化展现
在现今数据驱动的时代,可视化已逐渐成为数据分析的主要途径,可视化大屏的广泛使用便应运而生。很多公司及政务机构,常利用大屏的手段展现其实力或演示业务,可视化的效果能让观者更快速的理解结果并直观的看到数据展现。因此&#…...
ArkUI开发进阶—@Builder函数@BuilderParam装饰器的妙用与场景应用
ArkUI开发进阶—@Builder函数@BuilderParam装饰器的妙用与场景应用 HarmonyOS,作为一款全场景分布式操作系统,为了推动更广泛的应用开发,采用了一种先进而灵活的编程语言——ArkTS。ArkTS是在TypeScript(TS)的基础上发展而来,为HarmonyOS提供了丰富的应用开发工具,使开…...
大语言模型概述(三):基于亚马逊云科技的研究分析与实践
上期介绍了基于亚马逊云科技的大语言模型相关研究方向,以及大语言模型的训练和构建优化。本期将介绍大语言模型训练在亚马逊云科技上的最佳实践。 大语言模型训练在亚马逊云科技上的最佳实践 本章节内容,将重点关注大语言模型在亚马逊云科技上的最佳训…...
键入网址到网页显示,期间发生了什么?
文章目录 键入网址到网页显示,期间发生了什么?1. HTTP2. 真实地址查询 —— DNS3. 指南好帮手 —— 协议栈4. 可靠传输 —— TCP5. 远程定位 —— IP6. 两点传输 —— MAC7. 出口 —— 网卡8. 送别者 —— 交换机9. 出境大门 —— 路由器10. 互相扒皮 —…...
深度学习基于Python+TensorFlow+Django的水果识别系统
欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 文章目录 一项目简介简介技术组合系统功能使用流程 二、功能三、系统四. 总结 一项目简介 # 深度学习基于PythonTensorFlowDjango的水果识别系统介绍 简介 该水果识别系统基于…...
vs动态库生成过程中还存在静态库
为什么VS生成动态库dll同时还会生成lib静态库 动态库与静态库(Windows环境下) 动态库和静态库都是一种可执行代码的二进制形式,可以被操作系统载入内存执行。 静态库实际上是在链接时被链接到exe的,编译后,静态…...
P13 C++ 类 | 结构体内部的静态static
目录 01 前言 02 类内部创建静态变量的例子 03 在类的内部创建静态变量的作用 04 最后的话 01 前言 本期我们讨论 static 在一个类或一个结构体中的具体情况。 在几乎所有面向对象的语言中,静态在一个类中意味着特定的东西。这意味着在类的所有实例中ÿ…...
【腾讯云云上实验室-向量数据库】Tencent Cloud VectorDB在实战项目中替换Milvus测试
为什么尝试使用Tencent Cloud VectorDB替换Milvus向量库? 亮点:Tencent Cloud VectorDB支持Embedding,免去自己搭建模型的负担(搭建一个生产环境的模型实在耗费精力和体力)。 腾讯云向量数据库是什么? 腾…...
git clone -mirror 和 git clone 的区别
目录 前言两则区别git clone --mirrorgit clone 获取到的文件有什么不同瘦身仓库如何选择结语开源项目 前言 Git是一款强大的版本控制系统,通过Git可以方便地管理代码的版本和协作开发。在使用Git时,常见的操作之一就是通过git clone命令将远程仓库克隆…...
基于51单片机的公交自动报站系统
**单片机设计介绍, 基于51单片机的公交自动报站系统 文章目录 一 概要公交自动报站系统概述工作原理应用与优势 二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 很高兴为您介绍基于51单片机的公交自动报站系统: 公交自动报…...
NextJS开发:Image组件的使用及缺陷
Next.js 中的 Image 组件相比于传统的 img 标签有以下几个优点: 懒加载:Image 组件自带懒加载,当页面滚动到 Image 组件所在位置时才会加载图片,从而加快页面的渲染速度。自动优化:Image 组件会自动将图片压缩、转换格…...
网络安全面试经历
2023-11-22 X亭安全服务实习生面试 一面: 工作方向:偏蓝队 总结:实习蓝队面试没有什么难度,没有什么技术上的细节问题,之前准备的细节问题没有考 最后和面试官聊了聊对网安的认识,聊了聊二进制的知识…...
Rust语言入门教程(四) - 数据类型
标量类型(Scalar Types) 在Rust中,一共有4中标量类型, 也就是基本数据类型,分别是: 整型(Integers)浮点型(Floats)布尔型(Boolean)字符型(Chara…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
