OpenHarmony下musl编译工具链普法

news2025/1/19 17:17:23

OpenHarmony下musl编译工具链普法



引言

欠的债总是要还的,这不前面欠的关于OpenHarmony下musl相关的还是要还的。这里我对其中的相关知识点,梳理,归纳重新消化下!



一.GCC/Clang/LLVM的区别与联系

说实话,这块我现在都木有搞清楚,GCC/Clang/LLVM之间的区别与联系!这里只能硬着头皮,捡一捡网上各路大神的总结,先理解一波有个基本概念!

先了解,后面再深入吗!先搞个普法,对概念先有个基本的认识!


1.1 GCC的简介

传统的编译器譬如gcc设计是分为三个部分,如下图所示:

  • 前端, front end:解析源码,检查错误(词法分析(lexical analysis), 语法分析(syntax analysis), 语义分析(semantic analysis)),所以前端又称为分析阶段。并且构建一个特定于语言的抽象语法树(Abstract Syntax Tree,AST)来代表输入的代码。

  • 优化器,optimizer :负责进行各种转换尝试,改善代码的执行时间,比如消除冗余计算。通常或多或少与语言及目标无关。

  • 后端,back end:代码产生器,将代码映射到目标指令集,除了编写正确的代码外,它还负责生成利用所支持体系结构的不寻常特性的良好代码。一个编译器后端的通用部分包含指令选择,寄存器分配,及指令调度(instruction selection, register allocation, and instruction scheduling)

image


1.2 GCC架构的优点

GCC架构的优点总结为如下几点:

  • 使用通用的中间代码,新增支持语言只需要新增一个前端,新增支持目标机器只需要新增一个后端
  • 针对前后端,开发人员技术栈不同,开发人员只需要关注自身的技术栈,有利于让更多人员参与进来

总结来说,前端+优化器+后端的结构有三大好处:灵活程度高,组件复用率高,维护成本低


1.3 GCC架构的缺点

  • GCC的三段式模块必须配套使用,很难做到部分重用
  • 不能将 GCC 部分功能作为库重用的原因有很多,包括滥用全局变量、不可变变量不能更改限制不严、设计不良的数据结构、庞大的代码库、以及使用宏来防止代码库一次编译可以支持多个编译前端-目标机对。不过,最难解决的问题是其早期设计和那个时代所固有的架构设计。具体来说,GCC 饱受分层问题和抽象漏洞的困扰:编译后端遍历编译前端抽象语法树(AST)来生成调试信息(debug info),编译前端生成编译后端数据的结构,整个编译器依赖命令行设置的全局数据结构。

上面的这些优缺点,不是专业人士基本是体会不到相关差异的。我是木有体会到!


1.4 LLVM介绍

LLVM是开源的编译器(compiler)架构,以cpp编写而成,用于优化以随意程序语言编写的程序的编译时间(compile-time)、链接时间(link-time)、执行时间(run-time)以及空暇时间(idle-time),对开发人员保持开放,并兼容已有脚本。LLVM的设计就采用了上述前端+优化器+后端的设计。如下图所示:

image

基于这个认知,我们可以认为 LLVM 包括了两个概念:一个广义的 LLVM 和一个狭义的 LLVM 。广义的 LLVM 指的是一个完整的 LLVM 编译器框架系统,包括了前端、优化器、后端、众多的库函数以及很多的模块;而狭义的 LLVM 则是聚焦于编译器后端功能的一系列模块和库,包括代码优化、代码生成、JIT 等。

整体的编译器架构就是 LLVM 架构:

  • Clang 大致可以对应到编译器的前端,主要处理一些和具体机器无关的针对语言的分析操作;
  • 编译器的优化器和后端部分就是之前提到的 LLVM 后端,即狭义的 LLVM。

此外,由于 LLVM 的命名最早源自于底层虚拟机(Low Level Virtual Machine) 的首字母缩写,但这个项目的范围并不局限于创建一个虚拟机,这个缩写导致了大量的疑惑。LLVM 成长之后已成为众多编译工具及低级工具技术的统称,使得这个名字变得更不贴切,所以开发者决定放弃这个缩写的涵义,现在 LLVM 已独立成为一个品牌,适用于 LLVM 下的所有项目,包括 LLVM 中介码、LLVM 除错工具、LLVM cpp 标准库等。

image


1.5 clang介绍

Clang 是一个 C、cpp、Objective-C 和Objective-cpp编程语言的编译器前端,采用底层虚拟机(LLVM)作为后端。

  • Clang 采用的是 BSD 协议的许可证,而 GCC 采用的是 GPL 协议,显然前者更为宽松;
  • Clang 是一个高度模块化开发的轻量级编译器,编译速度快、占用内存小、有着友好的出错提示
  • Clang项目包括Clang前端和Clang静态分析器等,目的是输出代码对应的抽象语法树并将代码编译成LLVM bitcode
  • 接着后端使用LLVM编译成平台相关的机器语言

1.6 gcc和clang的交叉编译

gcc和clang都支持交叉编译链,gcc这个就比较常见了像后面章节2.2所描述的就是gcc的一个交叉编译工具链!clang通过–target=基本选项是定义目标体系结构,triple 的一般格式为<sub>---,其中:

  • arch = x86_64、i386、arm、thumb、mips等。
  • sub = v5, v6m, v7a, v7m等。
  • vendor = pc, apple, nvidia, ibm,等。
  • sys = none, linux, win32, darwin, cuda等。
  • abi = eabi, gnu, android, macho, elf等。

譬如:

--target=arm-linux-gnueabihf

并且通常一个大型的编译工程,不会是上面这么直接裸写的,一般会通过环境变量进行控制的。

export LINUX_ROOT="$HOME/OH_V3.2_BETA2/code-v3.2-Beta2"
export SYSROOT="${LINUX_ROOT}/OpenHarmony/out/rk3568/obj/third_party/musl"
export LLVM_BUILD_DIR="${LINUX_ROOT}/llvm"
export PATH=${LINUX_ROOT}/OpenHarmony/prebuilts/clang/ohos/linux-x86_64/llvm/bin:$PATH
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-ohos-
export HOSTCC=clang
export BUILD=debug

1.使用Clang作为编译器 —— 使用 Clang 交叉编译
2. 使用 Clang 交叉编译
3. How To Cross-Compile Clang/LLVM using Clang/LLVM
4. LLVM cross-compiled Linux From Scratch: C & cpp libraries


1.7 小结

前面说了这么多,其实我也还还不是很清楚!先不管吗,先把参考的链接放上!

这里我对gcc,clang和llvm的理解可以用一句话来概括就是: gcc = clang(前端) + 狭义的llvm后端

1.经典编译器组成(前端+优化器+后端)以及LLVM和Clang简介
2.【编译原理】GCC/Clang/LLVM的区别与联系
3.请问LLVM与GCC之间的关系
4.GCC和clang/LLVM
5.详解三大编译器:gcc、llvm 和 clang




二.musl你究竟是个啥

musl你是个啥,还得从它的的出生,发展历程出发一一道来。这里我们就从各个方面来捋一捋它!musl 是基于 Linux 系统调用 API 之上实现的 C 语言标准库(libc),历史可以追溯到 2005 年,但在 2011 年才正式确定了 MUSL 这个名称,开始对标 glibc、uClibc,从 2012 年开始,musl 开始使用 MIT License。

musl 致力于简单、高效,凭借 libc 优秀的松耦合性,做到了静态版本最小10kB,即使添加了线程等高级特性,也可以控制到 50kB,所以特别适合嵌入式设备。为了控制资源的使用, musl自己竟然不做动态内存分配。


2.1 glibc和musl-libc

这个我们分别来介绍下:

  • glibc: glibc是GNU C Library 是GNU项目(GNU Project),所实现的 C语言标准库(C standard library)。 目前,常见的桌面和服务器中的GNU/Linux类的系统中,都是用的这套C语言标准库。 其实现了常见的C库的函数,支持很多种系统平台,功能很全,但是也相对比较臃肿和庞大

  • musl-libc:C语言标准库Musl-libc项目发布了1.0版。Musl是一个轻量级的C标准库,设计作为GNU C library (glibc)、 uClibc或Android Bionic的替代用于嵌入式操作系统和移动设备。它遵循POSIX 2008规格和 C99 标准,采用MIT许可证授权,使用Musl的Linux发行版和项目包括sabotage,bootstrap-linux,LightCube OS等等

musl libc 和 glibc 是两个常见的 C 标准库实现,它们有一些差异。下面列出了其中一些主要的差异:

  • 大小和速度:musl libc 要小得多,因为它没有像 glibc 那样提供大量的额外功能。相反,musl libc 专注于尽可能减少代码大小和函数调用开销,以提高性能。

  • 兼容性:glibc 是 Linux 系统上最常见的 C 标准库,并且具有广泛的兼容性,支持许多架构和操作系统。相比之下,musl libc 对其他平台和操作系统的移植性较差。

  • 实现方法:musl libc 是使用静态链接编译的,这使得它更易于构建和管理,并且不需要动态链接器。相反,glibc 使用动态链接器,这也使得它更灵活,因为它可以动态加载所需的库。

  • POSIX 标准:musl libc 更加严格地遵循 POSIX 标准,而glibc 则添加了一些扩展,以提供更多的功能和兼容性。

  • 错误处理:musl libc 实现的错误处理更严格和更规范,而 glibc 则有更多的错误处理选项,并且支持不同的语言环境。

  • 版权问题:由于采用了 BSD 许可证,musl libc 比 glibc 更容易以开源、商业和专有软件的形式使用。

综上所述,选择使用 musl libc 还是 glibc 取决于您的具体需求。如果您需要一个小巧且速度较快的 C 标准库,在 Linux 系统上使用,则可以考虑使用 musl libc。如果您需要更广泛的兼容性和功能,则可以使用 glibc。

  • 额外补充:两个都是C++标准库。libc++是针对clang编译器特别重写的cpp标准库,那libstdc++自然就是gcc的事儿了。

  • 无关的科普: libc.so.6是c运行时库glibc的软链接,而系统几乎所有程序都依赖C运行时库。程序启动和运行时,是根据libc.so.6软链接找到glibc库。删除libc.so.6将导致系统的几乎所有程序不能工作。如果程序编译的时候链接的libc库版本不在程序运行环境下的glibc库支持的libc版本之内,也会报错。于是,系统的所有命令 IS,cp,cd等等都无法使用了。

1.Musl libc:为什么我们会需要另一个 libc?
2.musl和glibc,性能区别到底有多大
3.理清gcc、glibc、libstdc++的关系
4.uclibc、eglibc、glibc、Musl-libc之间的区别和联系
5.如何紧急修复,当你在linux中干穿了libc丢了libc.so.6,ld-linux-x86-64.so.2其中一个

干穿了,我就提桶跑路,还修复个啥!

6.musl简介
7.glibc和musl libc的区别
8.在同一个进程中加载​​ musl libc.so 和 gcc libc.so?
9.musl 的 GCC 包装器与 musl 的交叉编译器有何不同?
10.gcc编译静态库到自己的程序 解决在不同linux下因libc版本问题而不能运行 版本兼容问题
11.glib和glibc的联系区别
12.libc、glibc 和 glib 的关系
13.glibc所包含的各个库


2.2 aarch64-linux-musl-xxx

前面搞完了一个musl-libc库,这里又来了一个aarch64-linux-musl-xxx。你们是逗比吗,来这么多。真的逗比,今天又联系补上!

这里我们对aarch64-linux-musl其简单介绍下:

  • aarch64 是随 ARMv8 ISA 一起引入的 64 位架构,用于执行 A64 指令的计算机。而且在 aarch64 状态下执行的代码只能使用 A64 指令集。,而不能执行 A32 或 T32 指令。但是,与 AArch32 中不同,在64位状态下,指令可以访问 64 位和 32 位寄存器。

  • aarch64-linux-musl 是一个交叉编译工具链,可以在其他架构的系统中,编译安装 64 位 arm 架构的程序。常用在嵌入式代码的移植中。aarch64-linux-musl 是由musl官网基于 GCC 推出的的 ARM 交叉编译工具。可用于交叉编译 ARMv8 64 位目标中的裸机程序、u-boot、Linux kernel、filesystem 和 App 应用程序。aarch64-linux-musl 交叉编译器必须安装在 64 位主机上,才能编译目标代码。

aarch64-linux-musl-xxx如下所示:

$/opt/musl/bin$ ls
aarch64-linux-musl-addr2line  aarch64-linux-musl-gcc-9.4.0   aarch64-linux-musl-nm
aarch64-linux-musl-ar         aarch64-linux-musl-gcc-ar      aarch64-linux-musl-objcopy
aarch64-linux-musl-as         aarch64-linux-musl-gcc-nm      aarch64-linux-musl-objdump
aarch64-linux-musl-c++        aarch64-linux-musl-gcc-ranlib  aarch64-linux-musl-ranlib
aarch64-linux-musl-cc         aarch64-linux-musl-gcov        aarch64-linux-musl-readelf
aarch64-linux-musl-c++filt    aarch64-linux-musl-gcov-dump   aarch64-linux-musl-size
aarch64-linux-musl-cpp        aarch64-linux-musl-gcov-tool   aarch64-linux-musl-strings
aarch64-linux-musl-elfedit    aarch64-linux-musl-gprof       aarch64-linux-musl-strip
aarch64-linux-musl-g++        aarch64-linux-musl-ld
aarch64-linux-musl-gcc        aarch64-linux-musl-ld.bfd

这里我们可以把 aarch64-linux-musl-xxx和aarch64-linux-gnu-gcc做对比。它是一个gcc交叉编译工具链。

XXX:/opt/musl$ tree -L 1
.
├── aarch64-linux-musl
├── bin
├── include
├── lib
├── libexec
└── share

#其中git仓库地址如下,对应的

https://github.com/richfelker/musl-cross-make.git
https://gitee.com/stesen/musl-cross-make_for_openharmony.git



三.其它关于工具链知识的一些普法

工具链的知识真多,搞了一个又是一个!搞不完,记不住。但是还是木的办法,只能硬着头皮上!我不入地狱谁入地狱。我是超人!


3.1 什么是sysroot

sysroot 被称为逻辑根目录,只在链接过程中起作用,作为交叉编译工具链搜索库文件的根路径,如配置–sysroot=dir,则dir作为逻辑根目录,链接器将在dir/usr/lib中搜索库文件。

export LINUX_ROOT="$HOME/xxx/linux"
export SYSROOT="${LINUX_ROOT}/sysroot-ubuntu-20.04-arm64"


export LINUX_ROOT="$HOME/OH_V3.2_BETA2/code-v3.2-Beta2"
export SYSROOT="${LINUX_ROOT}/OpenHarmony/out/rk3568/obj/third_party/musl"

只有链接器开启了–with-sysroot选项,–sysroot=director才生效

1.编译链接实战(4)–sysroot和-isysroot选项对编译的影响
2.GCC编译选项和环境变量
3.sysroot位何物


3.2 pkg-config是个什么东东?

pkg-config的功能主要是在编译应用程序和库的时候作为一个工具来使用。pkg-config可以使用第三方库编译程序,指定库文件和头文件的位置。pkg-config就是通过.pc文件获取库的各种必要信息,包括版本信息、编译和链接需要的参数等。不同的系统的库文件的路径不同,用户也可以把库安装到不同的目录下

对于一个比较大第三方库,其头文件和库文件的数量是比较多的。如果我们一个个手动地写,那将是相当麻烦的。所以,pkg-config就应运而生了。大家应该都知道一般用第三方库的时候,就少不了要使用到第三方的头文件和库文件。我们在编译、链接的时候,必须要指定这些头文件和库文件的位置。对于一个比较大的第三方库,其头文件和库文件的数量是比较多的,如果我们一个个手动地写,那将是相当的麻烦的。因此,pkg-config就应运而生了。pkg-config能够把这些头文件和库文件的位置指出来,给编译器使用。pkg-config主要提供了下面几个功能:

  • 检查库的版本号。 如果所需要的库的版本不满足要求,它会打印出错误信息,避免链接错误版本的库文件
  • 获得编译预处理参数,如宏定义、头文件的位置
  • 获得链接参数,如库及依赖的其他库的位置,文件名及其他一些链接参数
  • 自动加入所依赖的其他库的设置

pkg-config能够把这些头文件和库文件的位置指出来,给编译器使用。如果你的系统装有libdrm,可以尝试一下下面的命令$pkg-config --cflags libdrm。可以看到其输出是gtk的头文件的路径。

我们平常都是这样用pkg-config的。

$gcc main.c `pkg-config --cflags --libs libdrm` -o main

$pkg-config --cflags --libs libdrm
-I/usr/local/include -I/usr/local/include/libdrm -L/usr/local/lib -ldrm

上面的编译命令中,`pkg-config --cflags --libs libdrm`的作用就如前面所说的,把gtk的头文件路径和库文件列出来,让编译去获取。–cflags和–libs分别指定头文件和库文件。

命令中的`不是引号,而是数字1左边那个键位的那个符号。

其实,pkg-config同其他命令一样,有很多选项,不过我们一般只会用到–libs和–cflags选项。

$pkg-config --help
Usage:
  pkg-config [OPTION?]

Help Options:
  -h, --help                              Show help options

Application Options:
  --version                               output version of pkg-config
  --modversion                            output version for package
  --atleast-pkgconfig-version=VERSION     require given version of pkg-config
  --libs                                  output all linker flags
  --static                                output linker flags for static linking
  --short-errors                          print short errors
  --libs-only-l                           output -l flags
  --libs-only-other                       output other libs (e.g. -pthread)
  --libs-only-L                           output -L flags
  --cflags                                output all pre-processor and compiler flags
  --cflags-only-I                         output -I flags
  --cflags-only-other                     output cflags not covered by the cflags-only-I option
  --variable=NAME                         get the value of variable named NAME
  --define-variable=NAME=VALUE            set variable NAME to VALUE
  --exists                                return 0 if the module(s) exist
  --print-variables                       output list of variables defined by the module
  --uninstalled                           return 0 if the uninstalled version of one or more module(s) or their dependencies will be used
  --atleast-version=VERSION               return 0 if the module is at least version VERSION
  --exact-version=VERSION                 return 0 if the module is at exactly version VERSION
  --max-version=VERSION                   return 0 if the module is at no newer than version VERSION
  --list-all                              list all known packages
  --debug                                 show verbose debug information
  --print-errors                          show verbose information about missing or conflicting packages (default unless --exists or --atleast/exact/max-version given on the command line)
  --silence-errors                        be silent about errors (default when --exists or --atleast/exact/max-version given on the command line)
  --errors-to-stdout                      print errors from --print-errors to stdout not stderr
  --print-provides                        print which packages the package provides
  --print-requires                        print which packages the package requires
  --print-requires-private                print which packages the package requires for static linking
  --validate                              validate a package's .pc file
  --define-prefix                         try to override the value of prefix for each .pc file found with a guesstimated value based on the location of the .pc file
  --dont-define-prefix                    don't try to override the value of prefix for each .pc file found with a guesstimated value based on the location of the .pc file
  --prefix-variable=PREFIX                set the name of the variable that pkg-config automatically sets

3.2.1 pkg-config配置环境变量

事实上,pkg-config只是一个工具,所以不是你安装了一个第三方库,pkg-config就能知道第三方库的头文件和库文件的位置的。为了让pkg-config可以得到一个库的信息,就要求库的提供者提供一个.pc文件。默认情况下,比如执行如下命令:

# pkg-config --libs --cflags glib-2.0
-I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -lglib-2.0

pkg-config会到/usr/lib/pkconfig/目录下去寻找glib-2.0.pc文件。也就是说在此目录下的.pc文件,pkg-config是可以自动找到的。然而假如我们安装了一个库,其生成的.pc文件并不在这个默认目录中的话,pkg-config就找不到了。此时我们需要通过PKG_CONFIG_PATH环境变量来指定pkg-config还应该在哪些地方去寻找.pc文件。

我们可以通过如下命令来设置PKG_CONFIG_PATH环境变量:

# export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig/

这样pkg-config就会在/usr/local/lib/pkgconfig/目录下寻找.pc文件了。另外还需要注意的是,上述环境变量的设置只对当前的终端窗口有效。为了让其永久生效,我们可以将上述命令写入到/etc/bash.bashrc等文件中(配置环境变量有很多方法,不止这一种),以方便后续使用。


3.3 pc文件是个什么东东?

pc文件是个什么东东,这里我用一句话来概括就是pkg-config用来在PKG_CONFIG_PATH查找库相关依赖的,一种特殊格式文件!既然是OpenHarmony系统,这里我们就以OpenHarmony下开源mesa3d里面的pc文件为例来举例说明:

$pwd
/home/xxx/xxx/third_party/mesa3d
$cat ohos/pkgconfig_template/zlib.pc 
prefix=ohos_project_directory_stub
exec_prefix=${prefix}
libdir=${prefix}/out/ohos-arm-release/obj/third_party/zlib
sharedlibdir=${libdir}
includedir=${prefix}/third_party/zlib

Name: zlib
Description: zlib compression library
Version: 1.2.12

Requires:
Libs: -L${libdir} -L${sharedlibdir} -lz

下面我们简单描述一下pc文件中的用到的一些关键词:

  • Name: 一个针对library或package的便于人阅读的名称。这个名称可以是任意的,它并不会影响到pkg-config的使用,pkg-config是采用pc文件名的方式来工作的。

  • Description: 对package的简短描述

  • URL: 人们可以通过该URL地址来获取package的更多信息或者package的下载地址

  • Version: 指定package版本号的字符串

  • Requires: 本库所依赖的其他库文件。所依赖的库文件的版本号可以通过使用如下比较操作符指定:=,<,>,<=,>=

  • Requires.private: 本库所依赖的一些私有库文件,但是这些私有库文件并不需要暴露给应用程序。这些私有库文件的版本指定方式与Requires中描述的类似。

  • Conflicts: 是一个可选字段,其主要用于描述与本package所冲突的其他package。版本号的描述也与Requires中的描述类似。本字段也可以取值为同一个package的多个不同版本实例。例如: Conflicts: bar < 1.2.3, bar >= 1.3.0

  • Cflags: 编译器编译本package时所指定的编译选项,和其他并不支持pkg-config的library的一些编译选项值。假如所需要的library支持pkg-config,则它们应该被添加到Requires或者Requires.private中

  • Libs: 链接本库时所需要的一些链接选项,和其他一些并不支持pkg-config的library的链接选项值。与Cflags类似

  • Libs.private: 本库所需要的一些私有库的链接选项



1.pkg-config 与.pc文件
2.pkgconfig和环境变量PKG_CONFIG_PATH和PKG_CONFIG_LIBDIR
3.Linux中pkg-config的使用
4.Linux修改环境变量的4种方法


3.4 怎么通过OpenHarmony源码编译ohos-sdk

很简单,如下:

./build/prebuilts_download.sh
./build.sh --product-name ohos-sdk –ccache  --target-cpu arm64


1.Musl-libc库编译

该博客,简单介绍了怎么编译生成musl libc库!
2.OpenHarmony富设备移植指南—开源GPU驱动编译
这篇博客我们并不是学习怎么编译GPU,而是学习musl + clang配置编译

3.aarch64-linux-ohos交叉编译rust
4.ohos_cross_tools交叉编译工具链
5.一文带你读懂如何移植三方库到OpenHarmony

++参考价值不大,已经完全过时了!主要描述了,如何移植第三方库到OH平台,这个可以为后续vivante GPU移植到OH参考使用++

6.基于OpenHarmony的第三方库编译移植环境(arm-linux-ohos平台)
7.交叉编译 Arm64 OHOS(鸿蒙系统)版本
8.OpenHarmony musl交叉编译

这篇博客可以参考,可以怎么使用musl + gcc编译

9.clang交叉编译Android clang交叉编译使用musl库
10.Building Linux with Clang/LLVM

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

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

相关文章

streamlit学习-如何播放HLS视频(streamlit嵌入html)

streamlit学习-如何播放HLS视频 一.效果二.直播环境搭建(仅供演示)1.生成m3u82.搭建http服务器(支持跨域)3.验证hls(VLC播放 http://localhost:8000/playlist.m3u8) 三.streamlit demo 本文演示了streamlit如何实现hls直播[streamlit中嵌入html] 一.效果 二.直播环境搭建(仅供演…

vue+Nodejs+Koa搭建前后端系统(九)-- 上传图片

web2.0的到来使网页世界正式进入了寒武纪&#xff0c;各式各样的多媒体资源屡见不鲜&#xff0c;上传资源变得刻不容缓&#xff01; 前言 本文是在该系列的基础上&#xff0c;针对前后端代码的修改。 准备 HTTP上传图片时Content-Type值常见的有2种&#xff1a;application…

spring boot3token拦截器链的设计与实现

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 &#x1f30a;山高路远&#xff0c;行路漫漫&#xff0c;终有归途。 目录 写在前面 流程分析 需要清楚的 实现步骤 1.定义拦截器 2.创建拦截器链配置类 3.配置拦截器链顺序 4.配置拦截…

OpenAI反击Elon Musk

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Ribbon实现Cloud负载均衡

安装Zookeeper要先安装JDK环境 解压 tar -zxvf /usr/local/develop/jdk-8u191-linux-x64.tar.gz -C /usr/local/develop 配置JAVA_HOME vim /etc/profile export JAVA_HOME/usr/local/develop/jdk1.8.0_191 export PATH$JAVA_HOME/bin:$PATH export CLASSPATH.:$JAVA_HOM…

力扣515. 在每个树行中找最大值(BFS,DFS)

Problem: 515. 在每个树行中找最大值 文章目录 题目描述思路复杂度Code 题目描述 思路 思路1&#xff1a;BFS 套用BFS模板&#xff0c;直接在遍历树的某一层时将当前层的最大值存入数组中 思路2&#xff1a;DFS 回溯思想&#xff0c;在递归时不断更新可选列表&#xff08;根据…

【word】引用文献如何标注右上角

一、在Word文档中引用文献并标注在右上角的具体步骤如下 1、将光标移动到需要添加文献标注的位置&#xff1a; 2、在文档上方的工具栏中选择“引用”选项&#xff1a; 3、点击“插入脚注”或“插入尾注”&#xff1a; ①如果选择的是脚注&#xff0c;则脚注区域会出现在本页的…

git:git revert 和git reset 回退版本的使用方式

目录 git revert还原某些现有提交git reset删除提交参考 git revert还原某些现有提交 中文文档&#xff1a;https://git-scm.com/docs/git-revert/zh_HANS-CN 版本会递增&#xff0c;不影响之前提交的内容 例如&#xff1a;撤销记录为 abc123 的提交 git revert abc123git r…

企微hook源码

企微hook源码已经在QQ群内开源。速度进群下载&#xff0c;避免和谐。 QQ群&#xff1a;649480745

【sgPhotoPlayer】自定义组件:图片预览,支持点击放大、缩小、旋转图片

特性&#xff1a; 支持设置初始索引值支持显示标题、日期、大小、当前图片位置支持无限循环切换轮播支持鼠标滑轮滚动、左右键、上下键、PageUp、PageDown、Home、End操作切换图片支持Esc关闭窗口 sgPhotoPlayer源码 <template><div :class"$options.name"…

【JS】关于this的使用

this 前言一、this是什么&#xff1f;二、做什么&#xff1f;1.全局环境2.函数环境3.new实例对象4.apply、bind、call绑定4.1 apply()4.2 call()4.3 bind() 三、为什么用this&#xff1f;四、如何改变this&#xff1f;五、应用场景&#xff1f;总结 前言 痛点 经常写Vue项目&a…

springboot集成logback打印彩色日志

一、logback介绍 Logback是由log4j创始人设计的另一个开源日志组件,官方网站&#xff1a; logback.qos.ch。它当前分为以下三个模块&#xff1a; logback-core&#xff1a;其它两个模块的基础模块。logback-classic&#xff1a;它是log4j的一个改良版本&#xff0c;同时它完整实…

qt练习案例

记录一下qt练习案例&#xff0c;方便学习qt知识点 基本部件 案例1 需求&#xff0c;做一个标签&#xff0c;显示"你好"知识点&#xff0c;QLabel画面 4. 参考&#xff0c;Qt 之 QLabel 案例2 需求&#xff0c;做一个标签&#xff0c;显示图片 知识点&#xff0c;…

【linux进程信号(二)】信号的保存,处理以及捕捉

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; 进程信号 1. 前言2. 信号阻塞…

仅通过头部便可控制机器人实现生活自理!四肢瘫患者福音真的来了?

运动功能障碍对个体执行基本日常生活活动&#xff08;如沐浴、更衣、用餐&#xff09;以及进行工具性日常生活活动&#xff08;包括娱乐和社交互动&#xff09;造成了显著影响&#xff0c;不仅限制了他们的活动范围&#xff0c;而且削弱了他们维持独立生活的基础。受此类障碍困…

Netty架构

Netty逻辑架构 Netty 的逻辑处理架构为典型网络分层架构设计&#xff0c;网络通信层、事件调度层、服务编排层。 一、 网络通信层 网络通信层的职责是执行网络 I/O 的操作。它支持多种网络协议和 I/O 模型的连接操作。当网络数据读取到内核缓冲区后&#xff0c;会触发网络事件…

还在用Jenkins?试试这款阿里出品的IDEA插件,部署项目贼香

CloudToolkit简介 CloudToolkit是阿里出品的一款IDEA插件,通过它我们可以更方便地实现自动化部署,其内置的终端工具和文件上传功能,即使用来管理服务器也非常方便!这款IDEA插件不仅功能强大,而且完全免费! 安装 CloudToolkit的安装是非常简单的,直接在IDEA的插件市场…

如何在Vue中实现拖拽功能?

Vue.js是一款流行的JavaScript框架&#xff0c;用于构建用户界面。其中一个常见的需求是在Vue中实现拖拽功能&#xff0c;让用户可以通过拖拽元素来进行交互。今天&#xff0c;我们就来学习如何在Vue中实现这一功能。 首先&#xff0c;我们需要明白拖拽功能的基本原理&#xf…

yduibuilder,拖拽式开发轻松高效自动生成前端代码

给大家分享一个#开源项目# &#xff1a;#yduibuilder# &#xff0c;他可以通过拖拽式的开发方式自动生成前端代码&#xff0c;这种#低代码开发工具# 已经很多了&#xff0c;没什么新鲜的&#xff1b; 但yduibuilder式通过编译的方式#生成终端代码# &#xff0c;没有预设各种功能…

2.2 评估方法 机器学习

我们若有一个包含m个样例的数据集&#xff0c;若我们既需要训练&#xff0c;也需要测试&#xff0c;我们该如何处理呢&#xff1f;下面是几种方法&#xff1a; 2.2.1 留出法 “留出法”直接将数据集D划分为两个互斥的集合&#xff0c;其中一个作为训练集S&#xff0c;另一个作…