7 Linux 内核移植

一、编译 ST 的 Linux 系统

1. 压缩源码

  首先先下载 ST 官方源码,之前章节已经下载过了,直接输入以下命令:

cd linux/atk-mpl/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.4.31-r0/

  然后压缩  linux-5.4.31.tar.xz  源码包压缩包:

tar -vxf linux-5.4.31.tar.xz

2. 给内核打补丁

输入以下命令:

cd linux-5.4.31/
for p in `ls -1 ../*.patch`; do patch -p1 < $p; done //打补丁

# ls -1 ../*.patch:通过执行 ls 命令列出上一级目录(..)中以 .patch 结尾的所有文件,并使用 -1 选项确保每个文件显示为一行。这将生成一个包含所有补丁文件名的列表。
# for p in ...; do ...; done:通过循环结构遍历列表中的每个元素,并在循环体内执行相应的操作。这里对列表中的每个元素都被赋值给变量 p。
# patch -p1 < $p:对于每个补丁文件 $p,执行 patch 命令来应用补丁文件到当前目录。-p1 选项告诉 patch 命令去除补丁文件中的前缀路径(通常是一个目录),从而使补丁适用于当前目录。
# 循环遍历上一级目录中的所有以 .patch 结尾的文件,并使用 patch 命令将这些补丁文件应用到当前目录中,其中补丁文件的前缀路径被去除

3. 生成默认配置文件

  ST 原厂 Linux 内核需要先生成默认配置文件,并且对其进行打补丁,进入 Linux 内核源码根目录下,然后执行如下命令: 

make ARCH=arm multi_v7_defconfig "fragment*.config"

# multi_v7_defconfig:指定要使用的配置文件。
# "fragment*.config":用于指定附加的配置片段文件。这里的 "fragment*.config" 是通配符表达式,指定了以 fragment 开头且以 .config 结尾的文件名模式。

  .config 文件非常重要, Linux 内核的所有配置项最终都保存在.config 文件里面,最终编译Linux 内核的时候需要读取.config 里面的配置项!此时我们只是生成了.config,并没有将 fragment config 补丁文件打进去,执行如下命令: 

for f in `ls -1 ../fragment*.config`; do scripts/kconfig/merge_config.sh -m -r .config $f; done
yes '' | make ARCH=arm oldconfig

# scripts/kconfig/merge_config.sh -m -r .config $f:执行 merge_config.sh 脚本,将文件 $f 的配置合并到当前目录的 .config 文件中。-m 选项表示使用模块化配置,-r 选项表示要保留已经存在的配置。
# yes '':yes 命令会重复地输出指定的字符串(在本例中是空字符串 ''),直到被终止
# ARM 架构上使用旧的配置 .config 文件执行 make oldconfig,并在自动回答用户提示时使用空字符串来完成配置过程。这样可以自动化配置过程,减少了手动输入配置的需要

  至此, Linux 源码根目录下的.config 文件就已经保存了所有的配置项,所以只需要复制一份.config 作为我们的默认配置文件即可,复制命令如下: 

cp .config ./arch/arm/configs/stm32mp1_atk_defconfig

  Linux 内核全部打完补丁, linux-5.4.31 目录就是我们要移植的 Linux 源码。我们新建一个名为“my_linux”的目录来保存我们要移植的 linux 源码,然后将打完补丁的 linux 源码 linux-5.4.31 拷贝到“my_linux”目录下,命令如下: 

# 首先在/linux/atk-mpl创建 linux 目录,然后再linux目录下创建my_linux子目录
cd ~
cd linux/atk-mpl/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.4.31-r0/
cp linux-5.4.31 /linux/atk-mpl/linux/my_linux/ -rf //拷贝

二、编译 ST 官方 Linux 源码 

1. 修改Makefile

  其实跟uboot修改顶层 Makefile 一样,为了减少输入参数,就添加以下代码到顶层 Makefile 中。

  创建一个名为“stm32mp157d_atk.sh”的编译脚本,脚本内容如下: 

#!/bin/sh
make distclean
make stm32mp1_atk_defconfig
make menuconfig
make uImage dtbs LOADADDR=0XC2000040 -j16

  给 stm32mp157d_atk.sh  执行权限:

chmod 777 stm32mp157d_atk.sh     // 给予可执行权限
./stm32mp157d_atk.sh             // 运行编译脚本

  编译完成以后的到 uImage 镜像文件和设备树,其中 STM32MP157 系列的设备树有很多。

2. 修改网络驱动

  文件均来自正点原子的包里,下载地址:STM32MP157开发板 — 正点原子资料下载中心 1.0.0 文档

  将 motorcomm.c 和 motorcomm_phy.h 分别拷贝到 Linux 源码下的 drivers/net/phy 和include/linux 目录下。拷贝完成以后修改 drivers/net/phy/Makefile 文件,加上下面这句: 

obj-$(CONFIG_MOTORCOMM_PHY) += motorcomm.o

# 如果定义了配置选项 CONFIG_MOTORCOMM_PHY 并且其值为 true,那么目标 motorcomm.o 将被添加到目标列表中,进而进行编译。

  还需要修改 drivers/net/phy/Kconfig 文件,添加以下代码:

config MOTORCOMM_PHY
    tristate "Motorcomm PHYs"
    ---help---
    Supports the YT8010, YT8510, YT8511, YT8512 PHYs.
    
/* config MOTORCOMM_PHY:定义了一个名为 MOTORCOMM_PHY 的配置选项。这个配置选项可用于在编译内核时启用或禁用与 Motorcomm PHY 相关的功能。

tristate "Motorcomm PHYs":配置选项的类型被设置为 tristate,即可以选择三个状态:y(编译进内核), m(编译为模块)和 n(禁用)。
"Motorcomm PHYs" 是配置选项的显示名称,将显示在配置界面上。

---help---:用来提供配置选项的帮助说明。该行以下的内容将被视为对配置选项的详细描述。

Supports the YT8010, YT8510, YT8511, YT8512 PHYs.:是对配置选项的详细描述,说明该选项的作用是支持 YT8010、YT8510、YT8511 和 YT8512 PHY 模块。
我们可以在 Linux 内核构建过程中选择是否编译或加载与 Motorcomm PHY 相关的功能模块*/

   在终端输入 make menuconfig,进入以下路径:

-> Device Drivers
    -> Network device support (NETDEVICES [=y])
        -> PHY Device support and infrastructure (PHYLIB [=y])
            -> <*> Motorcomm PHYs //将 YT8511 驱动编译进内核

3. 启动测试

  需要两个文件: uImage 和 stm32mp157d-ed1.dtb 

  首先将 /home/alientek/linux/tftpboot 文件删除,然后把这两个文件复制到tftp目录下并给予执行权限,命令如下:

cp stm32mp157d-ed1.dtb /home/alientek/linux/tftpboot/
cd ..
cp uImage /home/alientek/linux/tftpboot/
cd ~
cd linux/tftpboot/
chmod 777 stm32mp157d-ed1.dtb
chmod 777 uImage

  在 uboot 中输入:

tftp c2000000 uImage
tftp c4000000 stm32mp157d_ed1.dtb
bootm c2000000 - c4000000

三、在 Linux 中添加自己的开发板

1. 添加开发板对应的默认配置文件 

  首先添加开发板对应的默认配置文件,这里输入以下命令:

cd linux/atk-mpl/linux/my_linux/linux-5.4.31/arch/arm/configs
find stm32mp1_atk_defconfig

  就可以找到  stm32mp1_atk_defconfig  这个文件了。

2. 添加开发板对应的设备树 

 ① 新建设备树文件

   输入以下命令:

cd ~
cd linux/atk-mpl/linux/my_linux/linux-5.4.31/arch/arm/boot/dts/
cp stm32mp15xx-edx.dtsi stm32mp157d-atk.dtsi
cp stm32mp157d-ed1.dts stm32mp157d-atk.dts

  修改  stm32mp157d-atk.dts  文件:

 ② 修改 stm32mp157d-atk.dtsi 文件 

   跟uboot移植类似,PMIC 配置不需要,并在设备树里面添加电源节点信息。

#include "stm32mp157-m4-srm.dtsi"
#include "stm32mp157-m4-srm-pinctrl.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/mfd/st,stpmic1.h>

/ {
    memory@c0000000 {
        device_type = "memory";
        reg = <0xC0000000 0x40000000>;
    };

    reserved-memory {
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;

        mcuram2: mcuram2@10000000 {
            compatible = "shared-dma-pool";
            reg = <0x10000000 0x40000>;
            no-map;
        };

        vdev0vring0: vdev0vring0@10040000 {
            compatible = "shared-dma-pool";
            reg = <0x10040000 0x1000>;
            no-map;
        };

        vdev0vring1: vdev0vring1@10041000 {
            compatible = "shared-dma-pool";
            reg = <0x10041000 0x1000>;
            no-map;
        };

        vdev0buffer: vdev0buffer@10042000 {
            compatible = "shared-dma-pool";
            reg = <0x10042000 0x4000>;
            no-map;
        };

        mcuram: mcuram@30000000 {
            compatible = "shared-dma-pool";
            reg = <0x30000000 0x40000>;
            no-map;
        };

        retram: retram@38000000 {
            compatible = "shared-dma-pool";
            reg = <0x38000000 0x10000>;
            no-map;
        };
    };

    vddcore: buck1 {
        compatible = "regulator-fixed";
        regulator-name = "vddcore";
        regulator-min-microvolt = <1200000>;
        regulator-max-microvolt = <1350000>;
        regulator-always-on;
        regulator-boot-on;
    };

    v3v3: regulator-3p3v {
        compatible = "regulator-fixed";
        regulator-name = "v3v3";
        regulator-min-microvolt = <3300000>;
        regulator-max-microvolt = <3300000>;
        regulator-always-on;
        regulator-boot-on;
    };
};

&cpu0 {
    cpu-supply = <&vddcore>;
};

&crc1 {
    status = "okay";
};

&dma1 {
    sram = <&dma_pool>;
};

&dma2 {
    sram = <&dma_pool>;
};

&dts {
    status = "okay";
};

&ethernet0 {
    status = "okay";
    pinctrl-0 = <&ethernet0_rgmii_pins_a>;
    pinctrl-1 = <&ethernet0_rgmii_pins_sleep_a>;
    pinctrl-names = "default", "sleep";
    phy-mode = "rgmii-id";
    max-speed = <1000>;
    phy-handle = <&phy0>;

    mdio0 {
        #address-cells = <1>;
        #size-cells = <0>;
        compatible = "snps,dwmac-mdio";

        phy0: ethernet-phy@0 {
            reg = <0>;
        };
    };
};

&hash1 {
    status = "okay";
};

&ipcc {
    status = "okay";
};

&iwdg2 {
    timeout-sec = <32>;
    status = "okay";
};

&rng1 {
    status = "okay";
};

&rtc {
    status = "okay";
};

&sdmmc1 {
    pinctrl-names = "default", "opendrain", "sleep";
    pinctrl-0 = <&sdmmc1_b4_pins_a>;
    pinctrl-1 = <&sdmmc1_b4_od_pins_a>;
    pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>;
    broken-cd;
    st,neg-edge;
    bus-width = <4>;
    vmmc-supply = <&v3v3>;
    status = "okay";
};

&sdmmc2 {
    pinctrl-names = "default", "opendrain", "sleep";
    pinctrl-0 = <&sdmmc2_b4_pins_a>;
    pinctrl-1 = <&sdmmc2_b4_od_pins_a>;
    pinctrl-2 = <&sdmmc2_b4_sleep_pins_a>;
    non-removable;
    st,neg-edge;
    bus-width = <8>;
    vmmc-supply = <&v3v3>;
    keep-power-in-suspend;
    status = "okay";
};

&sram {
    dma_pool: dma_pool@0 {
        reg = <0x50000 0x10000>;
        pool;
    };
};

&uart4 {
    pinctrl-names = "default", "sleep", "idle";
    pinctrl-0 = <&uart4_pins_a>;
    pinctrl-1 = <&uart4_sleep_pins_a>;
    pinctrl-2 = <&uart4_idle_pins_a>;
    pinctrl-3 = <&uart4_pins_a>;
    /delete-property/dmas;
    /delete-property/dma-names;
    status = "okay";
};

  这里是替换整个文件的代码,直接复制进去即可。

 ③ 编译 stm32mp157d-atk.dts 设备树

  打开 arch/arm/boot/dts/Makefile,到“ dtb-$(CONFIG_ARCH_STM32)”配置项,在此配置项中加入“stm32mp157d-atk.dtb”, 表示编译的时候也将 stm32mp157datk.dts 编译为 stm32mp157d-atk.dtb 。

3. 关闭内核模块验证

  后续做 Linux 驱动实验的时候我们都是编译驱动模块,然后在系统里面加载,加载的时候系统会验证模块,有时候会验证出错。比如板子运行的系统和编译驱动模块所用的系统不一致的时候。为了方便开发,我们可以关闭内核模块验证。打开默认配置文件 stm32mp1_atk_defconfig,里面有如下所示配置项目: 

  我们也可以直接在 Linux 的图形化配置界面上关闭掉内核模块验证,输入如下命令打开 Linux 内核图形化配置界面: 

# 在 /linux/atk-mpl/linux/my_linux/linux-5.4.31 该目录下
make menuconfig

# 配置路径如下:
-> Enable loadable module support (MODULES [=y])
    ->Module signature verification

  只要通过图形化界面修改了 Linux 内核配置,最好及时将其保存到stm32mp1_atk_defconfig 文件。因为图形化界面修改的配置只是暂时保存到.config 文件里面,一旦使用“make clean”清理工程,那么.config 文件就会被删除掉,所有的配置也就丢失了!

4. 编译测试

  进入该目录 /linux/atk-mpl/linux/my_linux/linux-5.4.31,再编译 stm32mp157d_atk.sh。二、3启动测试类似,把文件拷贝到 tftp 服务器目录下。在uboot下输入以下命令。

tftp c2000000 uImage
tftp c4000000 stm32mp157d-atk.dtb
bootm c2000000 - c4000000

  有这样的 log 信息就启动成功。

四、烧写系统镜像到 EMMC  

  我们现在都是通过 tftp 命令从网络上下载测试的,实际产品开发中最终是要将系统烧写到外部 Flash 中的,比如 EMMC。现在我们将 uIamge 和 stm32mp157d-atk.dtb 打包成 ext4 格式,然后通过 STM32CubeProgrammer 烧写到 EMMC 里面,最终启动 EMMC 里面的 Linux 系统。

1. 系统镜像打包

  先在 linux/atk-mpl/linux/ 路径下创建子目录 bootfs,然后再把 /linux/tftpboot 路径下的 stm32mp157d-atk.dtb 和 uImage 文件拷贝到 bootfs 里面。

① 新建 ext4 格式磁盘

  首先新建一个 ext4 格式的磁盘,然后挂载这个 ext4 格式的磁盘,将 stm32mp157d-atk.dtb 和 uImage 拷贝到这个 ext4 磁盘即可。 

cd bootfs
dd if=/dev/zero of=bootfs.ext4 bs=1M count=10
mkfs.ext4 -L bootfs bootfs.ext4    # 使用 mkfs.ext4 将 bootfs.ext4 磁盘格式化为 ext4 格式

# 使用 dd 命令创建一个名为 bootfs.ext4 的磁盘, of 指定磁盘名字为“bootfs.ext4”;bs 指定磁盘输入/输出块大小为 1MB; count 指定磁盘的块数量为 10 个。
# 将会在当前目录下创建一个大小为10MB的bootfs.ext4文件,并用零填充它。

② 将系统镜像拷贝到 ext4 磁盘中

  首先创建一个目录用来挂载前面制作制作出来的 bootfs.ext4,比如我这里创建目录/mnt/bootfs,命令如下: 

cd /
sudo mkdir /mnt/bootfs

  使用 mount 命令将 bootfs.ext4 挂载到/mnt/bootfs 目录下,命令如下: 

cd /home/alientek/linux/atk-mp1/linux/bootfs
sudo mount bootfs.ext4 /mnt/bootfs

  挂载成功以后就将 uImage 和 stm32mp157d-atk.dtb 拷贝到/mnt/bootfs 目录下,命令如下: 

sudo cp uImage stm32mp157d-atk.dtb /mnt/bootfs/

  拷贝完成以后使用 umount 卸载/mnt/bootfs 即可,命令如下: 

sudo umount /mnt/bootfs

  这里我的理解是:先创建.ext4 磁盘,这个磁盘必须挂在到目录下,把需要放在这个磁盘下的东西放在挂载的目录里,最后再卸载该目录下的挂载。

2. 烧写到 EMMC 

  利用 FileZilla 将 bootfs.ext4 拷贝到 image 目录下:

  修改 Flashlayout:

  先把拨片波到USB,然后烧写,烧写完成后,把拨片拨到 EMMC 然后 RESET ,在 uboot 输入以下命令来验证是否烧写了  uImage 和stm32mp157d-atk.dtb 

ext4ls mmc 1:2

  设置 bootcmd 环境变量,从 EMMC 里面读取系统镜像和设备树并启动,命令如下:

setenv bootcmd 'ext4load mmc 1:2 c2000000 uImage;ext4load mmc 1:2 c4000000 stm32mp157d-atk.dtb;bootm c2000000 - c4000000'
saveenv
boot

  一般情况下,调试阶段都是用网络调试,也就是 tftp 或 nfs,当最终产品开发完成后,出厂的时候才烧写到 EMMC 里面。

五、文件系统缺失错误   

  Linux 内核启动以后是需要根文件系统的,根文件系统存在哪里是由 uboot 的 bootargs 环境变量指定的,它会传递给 Linux 内核作为命令行(command line)参数。  没有对应的根文件系统,必须要自己做根文件系统。 在没有根文件系统的情况下, Linux 内核启动的时候就会有下图所示的错误: 

  也就是提示内核崩溃, VFS(虚拟文件系统)不能挂载根文件系统,因为根文件系统目录不存在。解决方法就是制作根文件系统,并且设置 uboot 的 bootargs 环境变量,指定根文件系统所在的目录。 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SiteGround如何设置WordPress网站自动更新

SiteGround Autoupdate功能会自动帮我们更新在他们这里托管的所有WordPress网站&#xff0c;这样做是为了保证网站安全&#xff0c;并且让它们一直保持最新状态。他们会根据我们选择的设置自动更新不同版本的WordPress&#xff0c;包括主要版本和次要版本。在每次自动更新之前&…

【Docker】进阶之路:(十二)Docker Composer

【Docker】进阶之路&#xff1a;&#xff08;十二&#xff09;Docker Composer Docker Compose 简介安装 Docker Compose模板文件语法docker-compose.yml 语法说明imagecommandlinksexternal_linksportsexposevolumesvolunes_fromenvironmentenv_fileextendsnetpiddnscap_add,c…

Android---Kotlin 学习002

声明变量 在 Kotlin 中定义一个变量&#xff0c;通过关键字 var 开始。然后是变量名&#xff0c;在“:”后紧跟变量类型。 示例1&#xff1a;声明一个 int 类型的变量 var num:Int 1 示例2&#xff1a;声明一个 String 类型的变量 var str:String "Hello world&quo…

SpringBoot Maven 项目打包的艺术--主清单属性缺失与NoClassDefFoundError的优雅解决方案

Maven项目的Jar包打包问题-没有主清单属性&&ClassNotFoundException 与 NoClassDefFoundError 文章目录 Maven项目的Jar包打包问题-没有主清单属性&&ClassNotFoundException 与 NoClassDefFoundError1、问题出现1.1、Jar包运行&#xff1a;没有主清单属性解决方…

2023年华为HCIA认证H12-811题库讲解

在VRP平台上&#xff0c;可以通过下面哪种方式返回到上一条历史命令&#xff1f;&#xff08; &#xff09; A、Ctr1U B、Ctr1P C、左光标 D、上光标 试题答案&#xff1a;BD 试题解析&#xff1a;在VRP系统中&#xff0c;ctrlU为自定义快捷键&#xff0c;ct…

Python - 搭建 Flask 服务实现图像、视频修复需求

目录 一.引言 二.服务构建 1.主函数 upload_gif 2.文件接收 3.专属目录 4.图像修复 5.gif2mp4 6.mp42gif 7.图像返回 三.服务测试 1.服务启动 2.服务调用 四.总结 一.引言 前面我们介绍了如何使用 Real-ESRGAN 进行图像增强并在原始格式 jpeg、jpg、mp4 的基础上…

MAC配置环境变量

1、配置 JAVA JDK 1.1、查看 JDK 安装目录 &#xff08;1&#xff09;可以在Android Studio中查看&#xff0c;复制该路径 &#xff08;2&#xff09;也可以在官网下载 Java JDK下载地址 mac中的安装地址是"资源库->Java->JavaVirtualMachines"中 1.2、…

【Nacos】在Windows环境下搭建Nacos服务与Python开发示例

在Windows环境下搭建Nacos服务与Python开发示例 Nacos是一个开源的动态服务发现、配置和服务管理平台。本文将介绍在Windows环境下搭建Nacos服务&#xff0c;并提供一个简单的Python示例&#xff0c;演示如何通过Nacos实现服务注册与发现。 官方提示&#xff1a;Nacos定义为一…

nodejs+vue+微信小程序+python+PHP的外卖数据分析-计算机毕业设计推荐django

构建一种完全可实现、可操作的开放源代码信息收集系统&#xff0c;帮助记者完成工作任务。采编人员仅需输入所收集到的网址及题目即可迅速启动收集工作并进行信息归类。 2.根据新的数据收集要求&#xff0c;采用云计算技术实现新的收集器的迅速部署。对于资料采集点的改版&…

IoTDB控制台工具Workbench

文章目录 概述环境要求安装下载启动服务 登录用户界面主界面 连接 概述 Workbench是一个可创建多个连接的图形化数据库管理工具&#xff0c;用于管理IoTDB&#xff0c;提供元数据的可视化与管理、数据的增删改查以及权限控制等功能。Workbench不仅满足专业开发人员的所有需求&…

读程序员的README笔记08_依赖管理

1. 行为准则 2. 依赖管理 2.1. 在现有的代码上增加一个依赖似乎是一个简单的决定 2.2. 不要重复自己”(Don’t repeat yourself&#xff0c;DRY)是一个通常被教导的原则 2.3. 依赖关系带来了风险 2.3.1. 不兼容的变化 2.3.2. 循环依赖 2.3.3. 版本冲突 2.3.4. 缺乏控制 …

<url-pattern>/</url-pattern>与<url-pattern>/*</url-pattern>的区别

<url-pattern>/</url-pattern> servlet的url-pattern设置为/时&#xff0c; 它仅替换servlet容器的默认内置servlet&#xff0c;用于处理所有与其他注册的servlet不匹配的请求。直白点说就是&#xff0c;所有静态资源&#xff08;js&#xff0c;css&#xff0c;ima…

nodejs+vue+微信小程序+python+PHP基于spark的酒店管理系统-计算机毕业设计推荐

通过管理系统进行全面的线上管理。管理者可以通过基于spark的酒店管理系统&#xff0c;全面掌握酒店客房的各项状态&#xff0c;会员通过系统查询酒店客房信息&#xff0c;在线预定。 酒店作为旅游过程必须的设施&#xff0c;也逐渐需需要进行信息化管理&#xff0c;把酒店类型…

【PyTorch】现代卷积神经网络

文章目录 1. 理论介绍1.1. 深度卷积神经网络&#xff08;AlexNet&#xff09;1.1.1. 概述1.1.2. 模型设计 1.2. 使用块的网络&#xff08;VGG&#xff09;1.3. 网络中的网络&#xff08;NiN&#xff09;1.4. 含并行连结的网络&#xff08;GoogLeNet&#xff09; 2. 实例解析2.1…

连连看游戏

连通块记忆性递归的综合运用 这里x&#xff0c;y的设置反我平常的习惯&#xff0c;搞得我有点晕 实际上可以一输入就交换x&#xff0c;y的数据的 如果设置y1为全局变量的话会warning&#xff1a; warning: built-in function y1 declared as non-function 所以我改成p和q了…

Python---综合案例

一、系统需求分析 1、需求分析 使用面向对象编程思想完成学员管理系统的开发&#xff0c;具体如下&#xff1a; ① 系统要求&#xff1a;学员数据存储在文件中 ② 系统功能&#xff1a;添加学员、删除学员、修改学员信息、查询学员信息、显示所有学员信息、保存学员信息及退…

Kotlin基础——基础内容

文章目录 1 函数和变量1.1 基本程序1.2 函数1.3 变量1.3.1 变量的类型推导1.3.2 可变变量和不可变量1.3.3 变量使用规则 1.4 字符串模板 2 类和属性2.1 属性2.2 自定义访问器2.3 目录和包2.3.1 同包访问2.3.2 不同包导入2.3.3 包名类名定义规则 3 枚举和“when”3.1 声明枚举类…

软件测试之压力测试详解

一、什么是压力测试 软件测试中&#xff1a;压力测试&#xff08;Stress Test&#xff09;&#xff0c;也称为强度测试、负载测试。压力测试是模拟实际应用的软硬件环境及用户使用过程的系统负荷&#xff0c;长时间或超大负荷地运行测试软件&#xff0c;来测试被测系统的性能、…

leetcode-19-删除链表的倒数第N个节点

题目&#xff1a; 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5]示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[]示…

深度学习 Day15——P4猴痘病识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 文章目录 前言1 我的环境2 代码实现与执行结果2.1 前期准备2.1.1 引入库2.1.2 设置GPU&#xff08;如果设备上支持GPU就使用GPU,否则使用C…