Ubuntu虚拟机中使用QEMU搭建ARM64环境

Ubuntu虚拟机中使用QEMU搭建ARM64环境

通过本实验学习如何编译一个 ARM64 版本的内核 image,并且在QEMU 上运行起来。

文章目录

  • Ubuntu虚拟机中使用QEMU搭建ARM64环境
  • 一、安装aarch64交叉编译工具
  • 二、安装QEMU
  • 三、制作根文件系统
    • 1、根文件系统简介
    • 2、BusyBox构建根文件系统
      • 1)下载BusyBox源码
      • 2)制定编译工具链
      • 3)配置编译BusyBox
      • 4)创建需要的目录
        • (a) etc目录更新
        • (b) dev目录下的必要文件
        • (c) lib目录下的必要文件
  • 四、编译内核源码
    • 1、下载源码
    • 2、指定编译工具
    • 3、将根文件系统放到源码根目录
    • 4、配置生成.config
    • 5、编译
  • 五、启动QEMU
    • 1、创建共享文件目录
    • 2、运行QEMU模拟器
    • 4、编译一个简单的内核模块并在QEMU上运行
  • 六、实验过程中遇到的一些问题及解决办法
    • 1、本地下载压缩包如何上传Ubuntu中?
    • 2、make编译BusyBox出现的报错
    • 3、根文件系统放到源码根目录时报错
    • 4、关于内核模块在QEMU中运行出现的问题
  • 参考链接

一、安装aarch64交叉编译工具

搭建QEMU的模拟环境首先需要下载安装对应架构的交叉编译工具链(这里是arm64架构):

sudo apt-get install gcc-aarch64-linux-gnu
sudo apt-get install libncurses5-dev  build-essential git bison flex libssl-dev

image-20250307215602049

image-20250307215652241安装完成之后查看版本说明安装完成:

$ aarch64-linux-gnu-gcc -v

image-20250307215742797

二、安装QEMU

在终端中输入 sudo apt install qemu-system-arm安装

image-20250307215809308

安装完成后,输入 qemu-system-aarch64 --version 来查看 qemu版本

image-20250307215908572

三、制作根文件系统

1、根文件系统简介

Linux的根文件系统一般也叫做 rootfs,Linux的根文件系统更像是一个文件夹或者叫做目录,在这个目录里面会有很多的子目录。根目录下和子目录中会有很多的文件,这些文件是Linux运行所必须的,比如库、常用的软件和命令、设备文件、配置文件等等。

根文件系统的“根”字就说明了这个文件系统的重要性,它是其他文件系统的根,没有这个“根” ,其他的文件系统或者软件就别想工作。比如我们常用的 ls、mv、ifconfig 等命令其实就是一个个小软件,只是这些软件没有图形界面,而且需要输入命令来运行。这些小软件就保存在根文件系统中。

在构建根文件系统之前,先来看一下根文件系统里面都有些什么内容,根文件系统的目录名字为‘/’ ,就是一个斜杠。下面以Ubuntu为例,一些常用的子目录介绍如下表示:

image-20250307201933510

2、BusyBox构建根文件系统

1)下载BusyBox源码

BusyBox是一个集成了大量的Linux命令(如ls、mv、ifconfig 等命令)和工具的软件。借助BusyBox,进行配置和编译,就可以方便的构建一个嵌入Linux平台所需要的根文件系统。

可在BusyBox官网 https://busybox.net/ 下载源码。

将压缩包拖拽到Ubuntu虚拟机中的桌面或文件夹中,并解压

image-20250307222203393

tar -vxjf busybox-1.37.0.tar.bz2

解压后的文件如下:

image-20250307222336805

2)制定编译工具链

cd busybox-1.36.1
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
//检测是否配置成功
echo $ ARCH
echo $CROSS_COMPILE

image-20250307222735565

3)配置编译BusyBox

busybox中文字符支持:若直接编译busybox,使用串口工具时是不支持中文显示的,会显示为“?” ,可修改源码,取消 busybox对中文显示的限制

打开文件/libbb/printable_string.c,将函数printable_string()中的部分程序注释掉,修改后的函数内容如下:

/********** printable_string.c代码段 **********/
const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str)
{char *dst;const char *s;s = str;while (1) {......if (c < ' ')break;/* 注释掉下面这个两行代码,禁止字符大于0X7F以后 break *//* if (c >= 0x7f)   break; */s++;}#if ENABLE_UNICODE_SUPPORTdst = unicode_conv_to_printable(stats, str);
#else
{char *d = dst = xstrdup(str);while (1) {unsigned char c = *d;if (c == '\0')break;/* 修改下面代码,禁止字符大于0X7F以后输出‘?’ *//* if (c < ' ' || c >= 0x7f) */if( c < ' ')*d = '?';d++;
}
......
#endifreturn auto_string(dst);
}

接着打开文件/libbb/unicode.c,修改如下内容:

/********** unicode.c代码段 **********/
static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags)
{char *dst;unsigned dst_len;unsigned uni_count;unsigned uni_width;if (unicode_status != UNICODE_ON) {char *d;if (flags & UNI_FLAG_PAD) {d = dst = xmalloc(width + 1);....../* 修改下面一行代码 *//* *d++ = (c >= ' ' && c < 0x7f) ? c : '?'; */*d++ = (c >= ' ') ? c : '?';src++;}*d = '\0';} else {d = dst = xstrndup(src, width);while (*d) {unsigned char c = *d;/* 修改下面一行代码 *//* if (c < ' ' || c >= 0x7f) */if(c < ' ')*d = '?';d++;}}......return dst;}
......
return dst;
}
  • 配置busybox:有以下几种配置选项,一般使用默认配置即可

– defconfig:缺省配置,也就是默认配置选项
– allyesconfi:全选配置,即选中 busybox 的所有功能
– allnoconfig:最小配置

make defconfig  	#使用默认配置
make menuconfig		#打开图形化配置界面

在这里插入图片描述

设置Settings -> Build static binary (no shared libs)

image-20250307232958795

设置Settings -> Support Unicode,使能busybox的unicode编码以支持中文

image-20250307231300248

  • 编译busybox:配置好busybox以后就可以编译了,输入如下命令
make
make install CONFIG_PREFIX=/home/xlq/linux/rootfs
#CONFIG_PREFIX指定编译结果的存放目录

image-20250307233117424

编译完成以后,busybox的所有工具和文件就会被安装到rootfs目录中,如下图;rootfs目录下有bin、sbin和usr三个目录,以及linuxrc文件。

image-20250307233209439

4)创建需要的目录

cd  ~/linux/rootfs
mkdir dev etc lib sys proc tmp var home root mnt
(a) etc目录更新
  • 创建 profile 文件,添加下面内容
#!/bin/sh
export HOSTNAME=user
export USER=root
export HOME=/home
export PS1="[$USER@$HOSTNAME \W]\# "
PATH=/bin:/sbin:/usr/bin:/usr/sbin
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
export PATH LD_LIBRARY_PATH

用nano profile打开新建的文件后,Ctrl+O打开写入后直接回车,再点击Ctrl+x退出终端

回到文件夹下会出现新建的一个profile空白文件,将上述内容复制粘贴到该空白文件下即可。

后续创建操作皆可如此

  • 创建 inittab 文件,添加下面内容
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a -r
  • 创建 fstab 文件,添加下面内容,指定挂载的文件系统
#device  mount-point    type     options   dump   fsck order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
debugfs /sys/kernel/debug debugfs defaults 0 0
kmod_mount /mnt 9p trans=virtio 0 0
  • 创建init.d目录
mkdir  init.d
  • 在init.d下创建 rcS文件,添加下面内容
cd init.dmkdir -p /sys
mkdir -p /tmp
mkdir -p /proc
mkdir -p /mnt
/bin/mount -a
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
  • 添加权限
chmod 777 rcS
  • 利用tree命令查看etc下目录结构如下所示

image-20250307235749530

image-20250307235813055

(b) dev目录下的必要文件
cd dev
sudo mknod console c 5 1

image-20250308000013336

输出下面命令检查是否创建了console的设备文件:

ls -l /dev/console

image-20250308000143214

© lib目录下的必要文件

为了支持动态编译的应用程序的执行,根文件系统需要支持动态库,所以我们添加arm64相关的动态库文件到lib下

cd lib
cp /usr/aarch64-linux-gnu/lib/*.so* -a .

检查当前目录是否包含了.so文件:

image-20250308000449715

四、编译内核源码

1、下载源码

下载Linux的内核源码点击下载

很多教程是直接使用命令行下载,但我最初直接采用命令行方式下载Ubuntu内存爆红并且下载失败了,后面改用直接从网站下载比较稳妥。

在这里插入图片描述

同BusyBox放到Ubuntu合适位置进行解压

tar xvf linux-6.13.5.tar.xz

2、指定编译工具

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

3、将根文件系统放到源码根目录

cd linux-6.13.5
sudo cp  ~/linux/rootfs rootfs_arm64 -a

image-20250308002220347

4、配置生成.config

make defconfig
make menuconfig

添加hotplug支持

    Device Drivers                                                                                                 -> Generic Driver Options                                                                                             -> Support for uevent helper                                                                                                                (/sbin/hotplug) path to uevent helper

添加initramfs支持

General setup --->[*]Initial RAM filesystem and RAM disk(initramfs/initrd) support(_install_arm64) Initramfs souce file(s)

Virtual address space配置

    Kernel Features  ---> Page size(4KB)  --->Virtual address space size(48-bit)--->

5、编译

make all -j8

五、启动QEMU

1、创建共享文件目录

​ 在内核源码目录下创建目录

mkdir kmodules

2、运行QEMU模拟器

​ 在内核源码目录下执行下面命令

qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt  -m 1024 -smp 4 -kernel arch/arm64/boot/Image --append "rdinit=/linuxrc root=/dev/vda rw console=ttyAMA0 loglevel=8"  -nographic  --fsdev local,id=kmod_dev,path=$PWD/kmodules,security_model=none  -device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount

— machine virt:使用virt机器类型。
— cpu cortex-a57:使用Cortex-A57 CPU模型。
— -m 1024:设置虚拟机内存大小为1024MB。
— -smp 4:设置虚拟机使用4个CPU核心。
— -kernel arch/arm64/boot/Image:指定Linux内核镜像的路径。
— --append “rdinit=/linuxrc root=/dev/vda rw console=ttyAMA0 loglevel=8”:指定内核启动参数,其中rdinit指定init程序的路径,root指定根文件系统的设备,rw表示以读写模式挂载根文件系统,console指定控制台设备,loglevel指定内核日志级别。
— -nographic:禁用图形界面,使用纯文本控制台。
— --fsdev local,id=kmod_dev,path=$PWD/kmodules,security_model=none:创建一个本地文件系统设备,其中id指定设备ID,path指定设备挂载的本地路径,security_model指定安全模型。
— -device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount:将本地文件系统设备挂载到虚拟机中,其中fsdev指定设备ID,mount_tag指定设备挂载的标签。

启动成功后会打印下面内容,点击Enter进入控制台

image-20250308125559937

image-20250308125646865

退出QEMU模拟器

poweroff

4、编译一个简单的内核模块并在QEMU上运行

  • 在根目录下创建一个文件夹module_test,并编写一个简单的hello.c代码

    // 包含内核模块编程所需的头文件
    #include <linux/init.h>  // 包含模块初始化和退出函数的宏
    #include <linux/module.h>  // 包含模块相关的宏和函数
    #include <linux/kernel.h>  // 包含内核打印函数 printk 的头文件// 模块初始化函数
    // 当模块被加载到内核时,此函数会被调用
    static int __init test_init(void)
    {// 在内核日志中打印 "hello world!"printk("hello world!\n");// 返回 0 表示初始化成功return 0;
    }    // 模块退出函数
    // 当模块从内核中卸载时,此函数会被调用
    static void __exit test_exit(void)
    {// 在内核日志中打印 "hello exit!"printk("hello exit!\n");
    }// 注册模块的初始化函数
    // 当模块被加载时,test_init 函数会被调用
    module_init(test_init);// 注册模块的退出函数
    // 当模块被卸载时,test_exit 函数会被调用
    module_exit(test_exit);// 声明模块的许可证
    // GPL 是 GNU 通用公共许可证,表示这是一个开源模块
    MODULE_LICENSE("GPL");
    
  • 再编写Makefile文件

# 设置目标架构为 ARM64
export ARCH=arm64# 设置交叉编译工具链前缀为 aarch64-linux-gnu-
export CROSS_COMPILE=aarch64-linux-gnu-# 定义内核源码目录
KERNEL_DIR ?= /home/xlq/linux-6.13.5# 定义要编译的内核模块目标文件
# obj-m 表示将 hello.c 编译为内核模块 hello.ko
obj-m := hello.o# 默认目标:编译内核模块
modules:# 调用内核源码目录的 Makefile,编译当前目录下的模块$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules# 清理目标:删除编译生成的文件
clean:# 调用内核源码目录的 Makefile,清理当前目录下的生成文件$(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean# 安装目标:将编译好的内核模块复制到指定目录
install:# 将当前目录下所有的 .ko 文件复制到内核源码目录的 kmodules 子目录中cp *.ko $(KERNEL_DIR)/kmodules
  • 编译module,拷贝到共享目录
make modules
make install 
  • 启动QEMU

    启动命令:

qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt  -m 1024 -smp 4 -kernel arch/arm64/boot/Image --append "rdinit=/linuxrc root=/dev/vda rw console=ttyAMA0 loglevel=8"  -nographic  --fsdev local,id=kmod_dev,path=$PWD/kmodules,security_model=none  -device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount
回车后进入控制台,以防万一可以检查一下挂载点是否成功
ls /mnt

image-20250308163114922

​ 可以成功看到.ko文件。

  • 在QEUM执行module的插入与卸载,可以看到成功执行并打印log
[xlq@xlq-virtual-machine ]$ cd mnt
[xlq@xlq-virtual-machine mnt]$ ls /mnt
hello.ko  kmod_mount
[xlq@xlq-virtual-machine mnt]$ insmod hello.ko
[ 3679.306752] hello: loading out-of-tree module taints kerne
[ 3679.322242] hello world!
[xlq@xlq-virtual-machine mnt]$ rmmod hello.ko
3732.515746] hello exit!

image-20250308164115326

六、实验过程中遇到的一些问题及解决办法

1、本地下载压缩包如何上传Ubuntu中?

1、本地电脑上下载的busybox和Linux内核源码在移动到Ubuntu虚拟机上时拖到到主文件夹即可

在这里插入图片描述

2、make编译BusyBox出现的报错

2、出现问题:在使用命令make编译BusyBox时,出现报错信息如下

libbb/hash_md5_sha.c:1316:35: error: 'sha1_process_block64_shaNI' undeclared (first use in this function);did you mean 'sha1 process block64'?

解决办法nano libbb/hash_md5_sha.c 进入函数中,查找sha1_process_block64_shaNI,将所有的sha1_process_block64_shaNI修改成sha1_process_block64。保存后退出,再使用make编译即可通过。

3、根文件系统放到源码根目录时报错

3、出现问题:在将根文件系统放到源码根目录的时候,参考命令为:cp ~linux/rootfts rootfs_arm64 -a,但出现报错“‘无法创建特殊文件’”,原因是因为普通用户没有足够的权限来创建,设备文件和特殊文件通常需要root权限来创建或修改。

解决办法:使用sudo来提升权限

sudo cp ~/linux/rootfs rootfs_arm64 -a

4、关于内核模块在QEMU中运行出现的问题

4、当我在编译一个简单内核模块hello.c在QEMU运行测试的过程中,出现了很大问题:

出现问题:通过编译生成的内核模块hello.ko文件在成功拷贝到共享目录kmodules下时,启动QEMU,在mnt文件夹下无法看到hello.ko文件。

问题排查:合理利用大模型提出问题,主要从下面几个点来排查问题

  • 共享目录未正确挂载
//检查是否执行了挂载命令
mount -t 9p -o trans=virtio kmod_mount /mnt
//如果没有挂载,需要先挂载
mkdir -p /mnt/kmod_mount
mount -t 9p -o trans=virtio kmod_mount /mnt/kmod_mount
cd /mnt/kmod_mount
ls
//检测挂载是否成功
mount | grep kmod_mount    //如果没有输出,说明挂载失败
  • 挂载点错误(共享目录挂载到了其他目录,而不是/mnt)
//检查挂载点
mount | grep kmod_mount
//输出示例
kmod_mount on /mnt type 9p (trans=virtio)
  • 共享目录路径出错

    本人觉得这个问题可能性不大,在上面执行make install命令后,可以回到内核源码目录下的kmodules文件下查看是否存在.ko文件

    如果路径错误,修改QEMU启动命令中的path参数。
    
  • 如果上述问题都没有可以再文件系统权限问题和内核未启用9p文件系统支持问题

解决办法:本人最初遇到的问题是挂载失败,重新挂载后还是无法看到挂载点下的.ko文件,进入kmodules文件下,正确的挂载应该出现一个kmod_mount的挂载标签,和一个.ko文件,如下(不要把.ko文件放到kmod_mount文件夹中

image-20250308163512591

回到QEMU中检查目录内容:

image-20250308163749586

参考链接

用BusyBox构建根文件系统

QEMU搭建ARM64+Linux系统

qemu搭建ARM Linux环境

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL经典查询

查询不在表里的数据&#xff0c;一张学生表&#xff0c;一张学生的选课表&#xff0c;要求查出没有选课的学生&#xff1f; select students.student_name from students left join course_selection on students.student_idcourse_selection.student_id where course_selecti…

【神经网络】python实现神经网络(一)——数据集获取

一.概述 在文章【机器学习】一个例子带你了解神经网络是什么中&#xff0c;我们大致了解神经网络的正向信息传导、反向传导以及学习过程的大致流程&#xff0c;现在我们正式开始进行代码的实现&#xff0c;首先我们来实现第一步的运算过程模拟讲解&#xff1a;正向传导。本次代…

黑金风格人像静物户外旅拍Lr调色教程,手机滤镜PS+Lightroom预设下载!

调色教程 针对人像、静物以及户外旅拍照片&#xff0c;运用 Lightroom 软件进行风格化调色工作。旨在通过软件中的多种工具&#xff0c;如基本参数调整、HSL&#xff08;色相、饱和度、明亮度&#xff09;调整、曲线工具等改变照片原本的色彩、明度、对比度等属性&#xff0c;将…

Kubernetes中的 iptables 规则介绍

#作者&#xff1a;邓伟 文章目录 一、Kubernetes 网络模型概述二、iptables 基础知识三、Kubernetes 中的 iptables 应用四、查看和调试 iptables 规则五、总结 在 Kubernetes 集群中&#xff0c;iptables 是一个核心组件&#xff0c; 用于实现服务发现和网络策略。iptables 通…

C语言_数据结构总结5:顺序栈

纯C语言代码&#xff0c;不涉及C 想了解链式栈的实现&#xff0c;欢迎查看这篇文章&#xff1a;C语言_数据结构总结6&#xff1a;链式栈-CSDN博客 这里分享插入一下个人觉得很有用的习惯&#xff1a; 1. 就是遇到代码哪里不理解的&#xff0c;你就问豆包&#xff0c;C知道&a…

STM32之ADC

逐次逼近式ADC&#xff1a; 左边是8路输入通道&#xff0c;左下是地址锁存和译码&#xff0c;可将通道的地址锁存进ADDA&#xff0c;ADDB&#xff0c;ADDC类似38译码器的结构&#xff0c;ALE为锁存控制键&#xff0c;通道选择开关可控制选择单路或者多路通道&#xff0c;DAC为…

Magento2根据图片文件包导入产品图片

图片包给的图片文件是子产品的图片&#xff0c;如下图&#xff1a;A104255是主产品的sku <?php/*** 根据图片包导入产品图片&#xff0c;包含子产品和主产品* 子产品是作为主图&#xff0c;主产品是作为附加图片*/use Magento\Framework\App\Bootstrap;include(../app/boot…

初学STM32之简单认识IO口配置(学习笔记)

在使用51单片机的时候基本上不需要额外的配置IO&#xff0c;不过在使用特定的IO的时候需要额外的设计外围电路&#xff0c;比如PO口它是没有内置上拉电阻的。因此若想P0输出高电平&#xff0c;它就需要外接上拉电平。&#xff08;当然这不是说它输入不需要上拉电阻&#xff0c;…

图像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image

图像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image 文章目录 图像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image主要创新点模型架构图生成器生成器源码 判别器判别器源码 损失函数需要源码讲解的私信我 S…

STM32之I2C硬件外设

注意&#xff1a;硬件I2C的引脚是固定的 SDA和SCL都是复用到外部引脚。 SDA发送时数据寄存器的数据在数据移位寄存器空闲的状态下进入数据移位寄存器&#xff0c;此时会置状态寄存器的TXE为1&#xff0c;表示发送寄存器为空&#xff0c;然后往数据控制寄存器中一位一位的移送数…

Git - 补充工作中常用的一些命令

Git - 补充工作中常用的一些命令 1 一些场景1.1 场景11.2 场景21.3 场景31.4 场景41.5 场景51.6 场景61.7 场景71.8 场景81.9 场景91.10 场景101.11 场景111.12 场景121.13 场景131.14 场景141.15 场景15 2 git cherry-pick \<commit-hash\> 和 git checkout branch \-\-…

AI 驱动的软件测试革命:从自动化到智能化的进阶之路

&#x1f680;引言&#xff1a;软件测试的智能化转型浪潮 在数字化转型加速的今天&#xff0c;软件产品的迭代速度与复杂度呈指数级增长。传统软件测试依赖人工编写用例、执行测试的模式&#xff0c;已难以应对快速交付与高质量要求的双重挑战。人工智能技术的突破为测试领域注…

Unity--Cubism Live2D模型使用

了解LIVE2D在unity的使用--前提记录 了解各个组件的作用 Live2D Manuals & Tutorials 这些文件都是重要的控制动画参数的 Cubism Editor是编辑Live2D的工具&#xff0c;而导出的数据的类型&#xff0c;需要满足以上的条件 SDK中包含的Cubism的Importer会自动生成一个Pref…

Windows 系统 Docker Desktop 入门教程:从零开始掌握容器化技术

文章目录 前言一、Docker 简介二、Docker Desktop 安装2.1 系统要求2.2 安装步骤 三、Docker 基本概念四、Docker 常用命令五、实战&#xff1a;运行你的第一个容器5.1 拉取并运行 Nginx 容器5.2 查看容器日志5.3 停止并删除容器 六、总结 前言 随着云计算和微服务架构的普及&…

Lab17_ Blind SQL injection with out-of-band data exfiltration

文章目录 前言&#xff1a;进入实验室构造 payload 前言&#xff1a; 实验室标题为&#xff1a; 带外数据泄露的 SQL 盲注 简介&#xff1a; 本实验包含一个SQL盲目注入漏洞。应用程序使用跟踪Cookie进行分析&#xff0c;并执行包含提交的Cookie值的SQL查询。 SQL查询是异…

Vue 框架深度解析:源码分析与实现原理详解

文章目录 一、Vue 核心架构设计1.1 整体架构流程图1.2 模块职责划分 二、响应式系统源码解析2.1 核心类关系图2.2 核心源码分析2.2.1 数据劫持实现2.2.2 依赖收集过程 三、虚拟DOM与Diff算法实现3.1 Diff算法流程图3.2 核心Diff源码 四、模板编译全流程剖析4.1 编译流程图4.2 编…

Linux基本指令

一&#xff1a;Xshell相关快捷键 1.AltEnter进入Xshell全屏模式&#xff0c;再按一次AltEnter退出Xshell全屏模式 2.Ctrl Insert复制 3.Shift Insert粘粘 二&#xff1a;Linux基本指令 1.clear&#xff1a; 清屏&#xff1a;即将屏幕框上的所有内容删除 2.pwd&#xf…

Python基于Django的医用耗材网上申领系统【附源码、文档说明】

博主介绍&#xff1a;✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…

计算机视觉|3D卷积网络VoxelNet:点云检测的革新力量

一、引言 在科技快速发展的背景下&#xff0c;3D 目标检测技术在自动驾驶和机器人领域中具有重要作用。 在自动驾驶领域&#xff0c;车辆需实时、准确感知周围环境中的目标物体&#xff0c;如行人、车辆、交通标志和障碍物等。只有精确检测这些目标的位置、姿态和类别&#x…

【AD】5-13 特殊粘贴使用

同等间距复制很多过孔 复制之后进行特殊性粘贴&#xff0c;选择阵列粘贴 将元件带位号、带网络从PCB复制粘贴到另一个PCB 全选PCB并复制&#xff0c;来到另一个PCB&#xff0c;点击特殊性粘贴