https://ke.qq.com/course/4032547?flowToken=1042705

目录

前言

一 Kconfig文件起步:bool实验

二 配置一个模块:tristate实验

三 配置一个菜单:menu实验

四 配置一个字符串:string实验

五 配置一个整数:int实验

六 添加一个带配置菜单:menuconfig实验

七 depends on实验

八 select实验

总结


前言

准备好了,这是一个实践文章,也可以说是实验指导手册。

阅读之前准备一个ubuntu虚拟机,准备一个内核源码,跟随我的脚步,动手一点一点测试,不要急慢慢来,保证自己确实看到了测试结果,如果遇到问题,欢迎评论区留言讨论。

众所周知,linux中有很多的kconfig文件,kconfig为Menuconfig提供菜单内容,执行make Menuconfig后,这些被配置的内容以CONFIG_XXX=VALUE,的形式保存到.config文件中,这些value可以使y,m,或者是数字,也可能是字符串,例如向内核传递一个名字,或者传递一个外设的初始主频等。

本文通过几个例子介绍Kconfig的使用方法

一 Kconfig文件起步:bool实验

首先,在内核中的drivers目录下创建mydir目录

其次,在其中创建Kconfig文件。注意Kconfig中的K是大写的。

第三,为了在make menuconfig时,能够找到我们创建的Kconfig文件,还需要在mydir所在目录的Kconfig中引用mydir/Kconfig,就是修改文件drivers/Kconfig,在其中添加如下一行内容,

source "drivers/mydir/Kconfig"

我想测试方便,就添加在了第一行,添加后如下所示

创建目录mydir和其子文件Kconfig后,如下。

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3/drivers/mydir$ ls
Kconfig

在Kconfig中添加内容如下:

# SPDX-License-Identifier: GPL-2.0-only
config LKMAO_HELLO_WORLDbool "hello"helpthis is hello world

然后再内核源码目录执行 make menuconfig,看到配置菜单,进入device drivers,如下所示,看到新的菜单hello,并且还有(NEW)字符串,光标停留在该配置项,按y,选中该模块,按n取消选中,按空格键对当前值取反。我们当前测试选y,代表将该模块集成到内核中。然后保存退出

选中配置项

保存.config文件退出以后,在.config文件中搜索HELLO,如下所示:

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -n HELLO .config
2159:CONFIG_LKMAO_HELLO_WORLD=y

搜索到变量CONFIG_LKMAO_HELLO_WORLD,并且值是y。这个变量名字就是由config LKMAO_HELLO_WORLD连接生成的。

如果hello选项选n,那么在.config中是否会出现呢?验证结果如下所示,它会在.config文件中添加

# CONFIG_LKMAO_HELLO_WORLD is not set

表示该变量对应的模块并不会被编译,更加不会被放到内核中。

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -n HELLO .config
2159:# CONFIG_LKMAO_HELLO_WORLD is not set

二 配置一个模块:tristate实验

上一节介绍的是bool类型,本家将它改成tristate类型,tristate三态类型,分别是集成到内核、不添加、编译成模块。修改前面的Kconfig中添加内容如下,修改后的Kconfig内容如下所示:

# SPDX-License-Identifier: GPL-2.0-only
config LKMAO_HELLO_WORLDbool "hello"helpthis is hello worldconfig LKMAO_HELLO_ASIAbool "lkmao asia"hellothis is hello asia

保存上述内容到Kconfig文件,然后make menuconfig,如下

看到了hello以后不带(NEW),后缀了,lkmao asia带有(NEW)后缀,下面将lkmao asia这个选项改为tristate,如下所示

# SPDX-License-Identifier: GPL-2.0-only
config LKMAO_HELLO_WORLDbool "hello"helpthis is hello worldconfig LKMAO_HELLO_ASIAtristate "lkmao asia"hellothis is hello asia

保存,并make menuconfig,如下图所示,看到lkmao asia 选项前面已经编程尖括号<>了,

这是有y,n,m三种操作,相比bool的多出了m操作,我们按m效果如下

此时尖括号中出现M字符,这个在内核中表示该选项对应的文件会被编译为module即模块。save,然后退出,查看.config文件的变化。

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -n HELLO .config
2159:# CONFIG_LKMAO_HELLO_WORLD is not set
2160:CONFIG_LKMAO_HELLO_ASIA=m

如下所示,增加了变量CONFIG_LKMAO_HELLO_ASIA,且它的值是m。

三 配置一个菜单:menu实验

在drivers的Kconfig文件中,我们看到如下一行,这一行用于创建菜单,接下来,我们创建自己的菜单。

menu "Device Drivers"

修改我们的Kconfig文件如下所示:,新添加了一行menu "hello menu"

# SPDX-License-Identifier: GPL-2.0-only
menu "hello menu"
config LKMAO_HELLO_WORLDbool "hello"help this is hello worldconfig LKMAO_HELLO_ASIAtristate "lkmao asia"help this is hello asia

make menuconfig看看效果,报错如下:missing end statement for this entry 缺少结束字段,drivers/Kconfig,解决这个问题

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ make menuconfig
drivers/Kconfig:244: 'menu' in different file than 'menu'
drivers/mydir/Kconfig:2: location of the 'menu'
<none>:34: syntax error
drivers/Kconfig:2: missing end statement for this entry
make[1]: *** [scripts/kconfig/Makefile:48: menuconfig] Error 1
make: *** [Makefile:629: menuconfig] Error 2
lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ 

修改Kconfig如下所示

# SPDX-License-Identifier: GPL-2.0-only
menu "hello menu"
config LKMAO_HELLO_WORLDbool "hello"helpthis is hello worldconfig LKMAO_HELLO_ASIAtristate "lkmao asia"helpthis is hello asiaendmenu

重新make menuconfig

新增了hello menu菜单,按回车键进入该菜单,如下所示

看到其中,我们添加的的两个选项,验证效果很好。

四 配置一个字符串:string实验

配置字符串并不常用,为了让本文章看起来比较完整,添加一个测试的例子,其实我也不知道该怎么写?怎么办,百度吗,不用那么麻烦,我们在.config文件中找找有没有赋值为字符串的CONFIG_XXX变量,然后再搜索这个变量在哪里定义的,然后,再把定义的地方复制过来,其实语法看一眼,然后再实验一次,就知道是啥意思了。说干就干。使用more命令查看.config文件的前十行:好厉害,找到了,按q退出more命令,这里不是按Esc退出more命名的。

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ more -n 10 .config
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86 5.19.3 Kernel Configuration
#
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 11.2.0-19ubuntu1) 11.2.0"
CONFIG_CC_IS_GCC=y
CONFIG_GCC_VERSION=110200
CONFIG_CLANG_VERSION=0
CONFIG_AS_IS_GNU=y
CONFIG_AS_VERSION=23800

CONFIG_CC_VERSION_TEXT就是我们要找的字符串变量,CONFIG_GCC_VERSION就是我们下一小结要测试的整形变量,当然,这个可能还是字符串,我们就把它当做整形变量测试一下。

开始搜索CC_VERSION_TEXT,等等为什么不是搜索CONFIG_CC_VERSION_TEXT呢,CONFIG_被吃掉了吗?CONFIG_前缀是make menuconfig以后自动添加的,所以,搜索的时候要去掉CONFIG_前缀,如下所示:花的时间有点长。还是分析一下吧,CONFIG_CC_VERSION_TEXT看名字和值,应该是编译器版本信息,我猜它可能在init的Kconfig文件中定义的,试试

$ echo $(grep -nR CC_VERSION_TEX init/*) > result.txt

或者,这两个都可以,

$ grep -nR CC_VERSION_TEX init/* > result.txt

然后看到result.txt

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ cat result.txt
init/Kconfig:2:config CC_VERSION_TEXT
init/Kconfig:4: default "$(CC_VERSION_TEXT)"
init/Kconfig:10:            CC_VERSION_TEXT so it is recorded in include/config/auto.conf.cmd.
init/Kconfig:15:            line so fixdep adds include/config/CC_VERSION_TEXT into the
init/Makefile:35:       "$(CONFIG_CC_VERSION_TEXT)" "$(LD)"

在init/Kconfig文件中有五个地方使用到它了,我们接下来,我们会对他们全部设计测试例程。先分析一下如下所示的内容:

config CC_VERSION_TEXTstringdefault "$(CC_VERSION_TEXT)"helpThis is used in unclear ways:- Re-run Kconfig when the compiler is updatedThe 'default' property references the environment variable,CC_VERSION_TEXT so it is recorded in include/config/auto.conf.cmd.When the compiler is updated, Kconfig will be invoked.- Ensure full rebuild when the compiler is updatedinclude/linux/compiler-version.h contains this option in the commentline so fixdep adds include/config/CC_VERSION_TEXT into theauto-generated dependency. When the compiler is updated, syncconfigwill touch it and then every file will be rebuilt.

其中有一个string,我们看到的第三个数据类型,前两个是bool和tristate,它有一个默认值"$(CC_VERSION_TEXT)",这个我猜CC_VERSION_TEXT还是一个环境变量,为了验证这个猜想,创建一个Makefile,在其中添加如下内容:

all:@echo 'CC_VERSION_TEXT = '$(CC_VERSION_TEXT)
lkmao@lkmao-virtual-machine:~$ make
CC_VERSION_TEXT =
lkmao@lkmao-virtual-machine:~$

打印值是空的,这个不重要,我还是关心语法吧。无论它是什么default 后面的值,都是CONFIG_CC_VERSION_TEXT的默认值,除非我们给了它另外一个值。

help

后面是帮助信息,这里需要注意的是,

1 help单独占一行。

2 后来的帮助信息不需要双引号

根据分析,依照init/Kconfig文件修改我们自己的Kconfig内容如下所示:我们的Kconfig又丰富了。

这里需要注意的是:string 后面如果不加字符串,则menuconfig中是不会有这个子菜单项的。

# SPDX-License-Identifier: GPL-2.0-only
menu "hello menu"config LKMAO_HELLO_NAMEstring "input your name"default "ha li bo te"helpthis is your name.config LKMAO_HELLO_WORLDbool "hello"helpthis is hello worldconfig LKMAO_HELLO_ASIAtristate "lkmao asia"helpthis is hello asiaendmenu
~         

如下所示:多出一行input your name并且默认值是(ha li bo te)(哈利波特)

修改它的值为ba wang long (霸王龙)如下所示:

保存并退出,查看.config中新增的值:

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -nR HELLO .config
2163:CONFIG_LKMAO_HELLO_NAME="ba wanglong"
2164:# CONFIG_LKMAO_HELLO_WORLD is not set
2165:CONFIG_LKMAO_HELLO_ASIA=m

看到新增加了CONFIG_LKMAO_HELLO_NAME变量,且值是"ba wanglong",霸王龙字符串赋值完毕。

五 配置一个整数:int实验

上一节看到CONFIG_GCC_VERSION=110200,猜测它可能是整数,为什么?因为,根据我们自己的测试结果:看到了吧,霸王龙两边是有双引号的,110200两边没有双引号,所以猜它不是字符串。

2163:CONFIG_LKMAO_HELLO_NAME="ba wanglong"

开始验证之前,找找CONFIG_GCC_VERSION是在哪里定义的,搜索GCC_VERSION,还在init目录下找:如下所示

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -n GCC_VERSION init/Kconfig
22:config GCC_VERSION
895:    default y if CC_IS_GCC && GCC_VERSION >= 120000 && GCC_VERSION < 130000 && GCC12_NO_ARRAY_BOUNDS

定义在22行,看到895行了吗,这说明Kconfig文件中还可以使用if、&& 、>=、< ,如果百度的话,估计很难看到这些内容的。所以啊,宝藏就在内核目录里。init/Kconfig中是这样定义的

config GCC_VERSIONintdefault $(cc-version) if CC_IS_GCCdefault 0

我猜它的意思是,如果CC_IS_GCC为真,那么GCC_VERSION的值就是$(cc-version),否则的话,值就是0,这个要怎么验证呢,在根目录中的Makefile中打印CC_IS_GCC的值,在修改根目录的Makefile,在尾部添加内容:

hello_1:@echo 'CC_IS_GCC = '${CC_IS_GCC}

然后make hello_1:

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ make hello_1
CC_IS_GCC =
lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$

验证失败。直接在我们自己的Kconfig中做验证吧。

依照init/Kconfig文件修改我们自己的Kconfig内容如下所示:越来越多了。说明我们的经验越来越丰富了,继续下去,很快就变成高手了。

# SPDX-License-Identifier: GPL-2.0-only
menu "hello menu"config LKMAO_HELLO_VERSIONint "hello version"default $(cc-version) if CC_IS_GCCdefault 9527config LKMAO_HELLO_CHECKint "this is for test"default CC_IS_GCCconfig LKMAO_HELLO_NAMEstring "input your name"default "ha li bo te"helpthis is your name.config LKMAO_HELLO_WORLDbool "hello"helpthis is hello worldconfig LKMAO_HELLO_ASIAtristate "lkmao asia"helpthis is hello asiaendmenu

这个地方改了几次,得到上面代码,你如果在看我写的内容,并且也在测试,如果出问题,不要怕,多改一次,多验证,在出错中寻找经验,这样的经验,记忆最深刻。痛苦的回忆总是刻骨铭心的。新增两项,其中hello version的值是110200,CC_IS_GCC的值是n

查看.config的值

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -n HELLO .config
2163:CONFIG_LKMAO_HELLO_VERSION=110200
2164:CONFIG_LKMAO_HELLO_CHECK=n
2165:CONFIG_LKMAO_HELLO_NAME="ba wanglong"
2166:# CONFIG_LKMAO_HELLO_WORLD is not set
2167:CONFIG_LKMAO_HELLO_ASIA=m

重新make menuconfig,修改HELLO_VERSON的值为123456

验证结果:

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep -n HELLO .config
2163:CONFIG_LKMAO_HELLO_VERSION=123456
2164:CONFIG_LKMAO_HELLO_CHECK=n
2165:CONFIG_LKMAO_HELLO_NAME="ba wanglong"
2166:# CONFIG_LKMAO_HELLO_WORLD is not set
2167:CONFIG_LKMAO_HELLO_ASIA=m

关于CONFIG_LKMAO_HELLO_CHECK=n,这个估计是个很学术的话题啊,还是分析一下吧,Makefile中的变量是弱类型的,int、string等只是高速mecnuconfig,菜单应该以何种方式显示,例如如果是bool类型,子菜单就显示为中括号[ ],如果是tristate就显示为尖括号< >,如果是字符串或者int类型就显示为小括号( )。验证一下弱类型这种猜测:给hello verson输入三角龙:然后选择ok。

报错如下所示:

输入一个n

还是报错

那为什么2164:CONFIG_LKMAO_HELLO_CHECK=n就可以呢?上面至少验证了,普通的字符串是不能直接复制给int类型的。

六 添加一个带配置菜单:menuconfig实验

先看两个菜单选项的对比图

如上所示,hello menu菜单前面什么都没有,EISA support 前面有中括号,我们就要做一个这样的菜单,修改我们的Kconfig内容如下所示:注意menu "hello menu"和endmenu两行已经被#注释掉了,留在这里是为了对比。我们新增了LKMAO_HELLO_MENU,默认值是y

# SPDX-License-Identifier: GPL-2.0-only
#menu "hello menu"
menuconfig LKMAO_HELLO_MENUbool "hello worldd menu"default yhelpthis is for kconfig learn & testconfig LKMAO_HELLO_VERSIONint "hello version"default $(cc-version) if CC_IS_GCCdefault 9527config LKMAO_HELLO_CHECKint "this is for test"default CC_IS_GCCconfig LKMAO_HELLO_NAMEstring "input your name"default "ha li bo te"helpthis is your name.config LKMAO_HELLO_WORLDbool "hello"helpthis is hello worldconfig LKMAO_HELLO_ASIAtristate "lkmao asia"helpthis is hello asia#endmenu

make menuconfig验证如下:

这并不是我们想要的效果。看看init/Kconfig中的用法

lkmao@lkmao-virtual-machine:~/kernel/linux-5.19.3$ grep menuconfig init/Kconfig
menuconfig CGROUPS
menuconfig CGROUP_SCHED
menuconfig NAMESPACES
menuconfig EXPERT
menuconfig MODULES

里面有

menuconfig CGROUPSbool "Control Group support"select KERNFShelpThis option adds support for grouping sets of processes together, foruse with process control subsystems such as Cpusets, CFS, memorycontrols or device isolation.See- Documentation/scheduler/sched-design-CFS.rst  (CFS)- Documentation/admin-guide/cgroup-v1/ (features for grouping, isolationand resource control)Say N if unsure.
if CGROUPS
endif # CGROUPS

原来如此,需要加if 和endif,在菜单定义在if 和endif之间,修改我们自己的Kconfig

# SPDX-License-Identifier: GPL-2.0-only
#menu "hello menu"
menuconfig LKMAO_HELLO_MENUbool "hello worldd menu"default nhelpthis is for kconfig learn & testif LKMAO_HELLO_MENU
config LKMAO_HELLO_VERSIONint "hello version"default $(cc-version) if CC_IS_GCCdefault 9527config LKMAO_HELLO_CHECKint "this is for test"default CC_IS_GCCconfig LKMAO_HELLO_NAMEstring "input your name"default "ha li bo te"helpthis is your name.config LKMAO_HELLO_WORLDbool "hello"helpthis is hello worldconfig LKMAO_HELLO_ASIAtristate "lkmao asia"helpthis is hello asia
endif #LKMAO_HELLO_MENU
#endmenu

make menuconfig验证效果,如下所示,子菜单出现了

进入其中,看到了它的子菜单如下所示:

实验完毕。

七 depends on实验

这个没啥好说了,就是让A选项依赖于B选项,只有当B选中的时候,A才会出现,否则A处于隐藏状态。修改Kconfig代码如下所示

# SPDX-License-Identifier: GPL-2.0-only
#menu "hello menu"
menuconfig LKMAO_HELLO_MENUbool "hello world menu"default nhelpthis is for kconfig learn & testif LKMAO_HELLO_MENU
config LKMAO_HELLO_VERSIONint "hello version"default $(cc-version) if CC_IS_GCCdefault 9527config LKMAO_HELLO_NAMEstring "input your name"default "ha li bo te"helpthis is your name.config LKMAO_HELLO_BOSSbool "have a boss"helpthis is my boss.config LKMAO_HELLO_MISHUdepends on LKMAO_HELLO_MISHUtristate "have a mishu"default yhelpthis is boss's mishu,she work for boss.
endif #LKMAO_HELLO_MENU
#endmenu

have a mishu依赖于have a boss,只有have a boss被选中,have a mishu才会出现,make menuconfig如下所示

当前have a boss没有被选中,现在选中它。

选中了have a boss,have a mishu选项也出现了。

实验完毕。

八 select实验

就是选中一个选项的时候,也会将其他选项选中,修改Kconfig代码如下所示:

未选中Hava a boss的执行结果

选中Have a boss的执行结果

看buy a good car 前面是_*_,表示该选项是被另一个选项选中的。

当然,如果没有选中hava a boos,have a good car选线是作为普通的选项操作的。

实验完毕

总结

本来只是想把刚刚写的Kconfig文件记录一下,后来觉得这个东西还有很多没有吃透的知识,有必要挖掘一下,解决就真的挖出了不少的东西。

还是要多实践,所思考。

内核架构师必备技能:编写自己的kconfig框架plus相关推荐

  1. 安卓sdk开发!阿里面试100%会问到的JVM,架构师必备技能

    接触这一行也有很久了,从开始的实习到带团队,中间接触过很多人,前不久身边刚好有人去面试了阿里,抖音等这些公司还成功的面试上了,现在来分享一下面试前需要准备的知识点 很多人去面试之前,不知道会问到那些知 ...

  2. 互联网架构师必备技能

    一.每个好架构师都是一位出色的程序员 这一点毋庸置疑,如果不是写过N年代码的优秀程序员,一定不是好的架构师."架构师"这是一个听上去比较虚的职位,它的主要价值在于"落地& ...

  3. 架构师必备技能:Maven Archetype生成项目模板

    基本每个公司的项目都有一套模板,只要开新项目直接复制一份改改包名和一些配置就初始化了一个新项目.这种方式有点繁琐,有没有通过命令甚至是可视化的方式从一个模板项目初始化项目.Maven其实有提供这种能力 ...

  4. Android多线程实现方式及并发与同步,架构师必备技能

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8rwcQW4s-1620361703648)(//upload-images.jianshu.io/upload_ima ...

  5. 高级前端架构师必备技能(marksheng)

    首先,前端架构师肯定是掌握好基本的前端技术基础的,正所谓一转多长,首先你得先精通一门,其次,掌握前端技术的同时,还要了解前端技术之外的技能.跳出前端这个思维,才能看到的更多.总结起来有以下几点: 跨界 ...

  6. GitHub标星1w的安卓架构师必备技能,终获offer

    开头 移动应用开发从逐渐开始火爆到如今也有小十年了,大部分的学校还是没有开放专门的课程. 目前市场上的大部分 Android 开发工程师大多数是自学或者是培训出身,用一段时间上手 Android 开发 ...

  7. GitHub标星1w的Java架构师必备技能,Java岗

    一.Spring Cloud微服务概念定义 提起微服务,不得不提 Spring Cloud 全家桶系列,Spring Cloud 是一个服务治理平台,是若干个框架的集合,提供了全套的分布式系统解决方案 ...

  8. 山哥新作:架构师必备技能之业务分析

    1 业务分析 业务分析是应用系统的思想和方法,把复杂的需求分解成简单的对象,找出这些对象的基本属性以及彼此之间的关系,系统分析也是系统开发中最重要.也是最困难的阶段,最终的架构设计也要依据业务分析的结 ...

  9. 【大数据】年薪百万架构师必备技能

    搞Java开发的同学,目标都想成为Java架构师:搞大数据开发的同学,目标都想成为大数据架构师. 成为大数据架构师有什么好处呢? 归其原因: 1.技术上能达到一定的高度,被公司认可,也被社会认可,有成 ...

最新文章

  1. Mysql 分区介绍(二) —— RANGE分区
  2. 【机器学习】KNN算法代码练习
  3. 说说你对http、https、http2.0的理解【前端每日一题-25】
  4. 开源免费的HTML5游戏引擎
  5. spark实验遇到的问题
  6. android AVD详解
  7. maven单元测试报java.lang.IllegalStateException: Failed to load ApplicationContext
  8. update与fixedupdate差别
  9. 最大连续子数组和 动态规划_53. 最大子序和(动态规划)
  10. 4 pwm 什么时候采样电流_电机控制之电流采样及坐标变换第一部分
  11. 【文献阅读笔记】(2):使用IMPUTES2和minimac软件完成群体特异性的基因型填充(Imputation)
  12. 为什么越受重视的游戏项目越难开发好!
  13. BeatSaber节奏光剑双手柄MR教程
  14. 桌面计算机密码修改频率,教大家如何更改电脑的显示频率
  15. java ljava/lang/string_([Ljava/lang/String;)V的含义
  16. 数据分析[1.1]--拆解方法总结
  17. Categories各种举例
  18. Kubernetes 企业集群建设规划
  19. Nginx 简易教程
  20. PS如何快速找到对应的图层

热门文章

  1. 解决ERROR: cannot drop schema sc_base_1 because other objects depend on it.模式级联删除
  2. 蓝桥杯之单片机学习(二十一)——自动售水机(附题目和完整代码)
  3. 前端需要学习的东西好多,加油加油!
  4. 1.20 Python基础知识 - python常用模块-1
  5. 开发快手爬票项目(最终章)
  6. 3行代码建模,训练速度提升200%?这款时序开源神器PaddleTS太强了!
  7. 学编程到底需要什么计算机基础知识?
  8. CorelDraw9 ,12,X3打开文件慢,复制慢,文件打开加速补丁
  9. 今日的深圳早报新闻消息事件有几个版本?都在哪些地方同步更新?
  10. yolov5 windows 下训练+ c++ TensorRT 部署在qt (vs+qtcreator) 只要一篇文章即可