FreeBSD 9.1内核文件编译分析
本文不是叫大家怎么做FreeBSD内核,做内核太简单了,不管是Linux和Unix。
在网上找了好久,一点可用的文章都没有找到,FreeBSD的官网的文章也没有给出说法,只能自己在/usr/src和/usr/src/sys和/usr/src/sys/conf下面疯狂的grep,找文件,找引用,才有了自己的一些理解。
先说说Linux的内核文件的编译关联吧,Linux的每个文件的编译和是kconfig配置关联在一起的,kconfig在经过make menuconfig之后,得到一个.config文件,然后每个文件夹下面的Makefile,会check这个全局的.config文件,来决定哪些文件该编译,哪些不用编译。多说无益,参考代码即可。
FreeBSD的做法有些不一样了,Linux把哪些文件要编译分散到了每个文件夹,然后check Makefile。FreeBSD是做两个总的文件,决定哪些文件该编译哪些不该,这两个文件分别是这个路径下:
ztz0223@BTazuo:/usr/src/sys/conf % pwd
/usr/src/sys/conf
的两个文件:files,files.i386
files是与架构无关的,也就是不管代码在什么平台上面编译,i386或者power pc上面都靠这个文件控制编译。对应的files.i386,就是特定平台的编译控制。
我们来看一下,这两个文件里面是什么吧,首先是files:
2082 dev/xe/if_xe.c optional xe
2083 dev/xe/if_xe_pccard.c optional xe pccard
2084 dev/xl/if_xl.c optional xl pci
2085 dev/xl/xlphy.c optional xl pci
2086 fs/coda/coda_fbsd.c optional vcoda
2087 fs/coda/coda_psdev.c optional vcoda
2088 fs/coda/coda_subr.c optional vcoda
2089 fs/coda/coda_venus.c optional vcoda
2090 fs/coda/coda_vfsops.c optional vcoda
2091 fs/coda/coda_vnops.c optional vcoda
2092 fs/deadfs/dead_vnops.c standard
2093 fs/devfs/devfs_devs.c standard
2094 fs/devfs/devfs_dir.c standard
2095 fs/devfs/devfs_rule.c standard
2096 fs/devfs/devfs_vfsops.c standard
2097 fs/devfs/devfs_vnops.c standard
2098 fs/fdescfs/fdesc_vfsops.c optional fdescfs
2099 fs/fdescfs/fdesc_vnops.c optional fdescfs
2100 fs/fifofs/fifo_vnops.c standard
2101 fs/hpfs/hpfs_alsubr.c optional hpfs
2102 fs/hpfs/hpfs_lookup.c optional hpfs
"files" [readonly] 3544 lines --57%--
再看files.i386:
417 i386/i386/minidump_machdep.c standard
418 i386/i386/mp_clock.c optional smp
419 i386/i386/mp_machdep.c optional native smp
420 i386/xen/mp_machdep.c optional xen smp
421 i386/i386/mp_watchdog.c optional mp_watchdog smp
422 i386/i386/mpboot.s optional smp native
423 i386/xen/mptable.c optional apic xen
424 i386/i386/perfmon.c optional perfmon
425 i386/i386/pmap.c optional native
426 i386/xen/pmap.c optional xen
427 i386/i386/ptrace_machdep.c standard
428 i386/i386/stack_machdep.c optional ddb | stack
429 i386/i386/support.s standard
430 i386/i386/swtch.s standard
431 i386/i386/sys_machdep.c standard
432 i386/i386/trap.c standard
433 i386/i386/uio_machdep.c standard
434 i386/i386/vm86.c standard
435 i386/i386/vm_machdep.c standard
436 i386/ibcs2/ibcs2_errno.c optional ibcs2
437 i386/ibcs2/ibcs2_fcntl.c optional ibcs2
438 i386/ibcs2/ibcs2_ioctl.c optional ibcs2
439 i386/ibcs2/ibcs2_ipc.c optional ibcs2
440 i386/ibcs2/ibcs2_isc.c optional ibcs2
"files.i386" [readonly] 537 lines --71%--
对于上面的files,我要说的就是,后面带有standard的表明该文件一定会编译,不管是快速编译指定模块,还是全部完全编译。 二 optional xxx标识当xxx选项开启的时候,才会编译对应的文件。如果内核里指定了options,就会编译到内核文件里,而不是以模块方式可以动态加载的了,一般都会建议采用模块方式。
上面files.i386可以看出:
436 i386/ibcs2/ibcs2_errno.c optional ibcs2 只有在ibcs2选项开启的时候才会编译
而:
432 i386/i386/trap.c standard 在i386架构平台下编译的话,一定要编译的。
OK,说到这里,已经知道文件如何编译的了,那么在指定快速编译的时候,就是在make.conf里面指定编译的模块,就如官网文档所示:
------------------------------
联编内核
1. 进入 /usr/src 目录:
# cd /usr/src
2. 编译内核:
# make buildkernel KERNCONF=MYKERNEL
3. 安装新内核:
# make installkernel KERNCONF=MYKERNEL
注意: 使用这种方法联编内核时, 需要安装完整的 FreeBSD 源代码。
提示: 默认情况下, 在联编您所定制的内核时, 全部 内核模块也会同时参与构建。 如果您希望更快地升级内核, 或者只希望联编您所需要的模块, 则应在联编之前编辑 /etc/make.conf:
MODULES_OVERRIDE = linux acpi sound/sound sound/driver/ds1 ntfs
这个变量的内容是所希望构建的模块列表。
WITHOUT_MODULES = linux acpi sound ntfs
这个变量的内容是将不在联编过程中编译的顶级模块列表。 如果希望了解更多与构建内核有关的变量, 请参见 make.conf(5) 联机手册。
------------------------------
比如,我在/etc/make.conf里面指定:
MODULES_OVERRIDE = xfs
那么是不是仅仅编译xfs的文件吗?
当然不是,当我们执行
# make buildkernel KERNCONF=MYKERNEL
开始编译的时候,会发现打印里面有
cc -c -O -pipe -std=c99 -g -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Winline -Wcast-qual -Wundef -Wno-pointer-sign -fformat-extensions -Wmissing-include-dirs -fdiagnostics-show-option -nostdinc -I. -I/usr/src/sys -I/usr/src/sys/contrib/altq -D_KERNEL -DHAVE_KERNEL_OPTION_HEADERS -include opt_global.h -fno-common -finline-limit=8000 --param inline-unit-growth=100 --param large-function-growth=1000 -mno-align-long-strings -mpreferred-stack-boundary=2 -mno-mmx -mno-sse -msoft-float -ffreestanding -fstack-protector -Werror /usr/src/sys/cam/ata/ata_all.c
但是我们可以从files里面看出来:
110 cam/ata/ata_all.c optional scbus
scbus开启才会编译这个文件。
为什么他会编译?
很简单,我们看
# make buildkernel KERNCONF=MYKERNEL
的最开始有一些打印,是删除中间文件的:
--------------------------------------------------------------
>>> stage 2.1: cleaning up the object tree
--------------------------------------------------------------
cd /usr/obj/usr/src/sys/GENERIC_20130217; MAKEOBJDIRPREFIX=/usr/obj MACHINE_ARCH=i386 MACHINE=i386 CPUTYPE= GROFF_BIN_PATH=/usr/obj/usr/src/tmp/legacy/usr/bin GROFF_FONT_PATH=/usr/obj/usr/src/tmp/legacy/usr/share/groff_font GROFF_TMAC_PATH=/usr/obj/usr/src/tmp/legacy/usr/share/tmac _SHLIBDIRPREFIX=/usr/obj/usr/src/tmp _LDSCRIPTROOT= VERSION="FreeBSD 9.1-RELEASE i386 901000" INSTALL="sh /usr/src/tools/install.sh" PATH=/usr/obj/usr/src/tmp/legacy/usr/sbin:/usr/obj/usr/src/tmp/legacy/usr/bin:/usr/obj/usr/src/tmp/legacy/usr/games:/usr/obj/usr/src/tmp/usr/sbin:/usr/obj/usr/src/tmp/usr/bin:/usr/obj/usr/src/tmp/usr/games:/sbin:/bin:/usr/sbin:/usr/bin make KERNEL=kernel cleandir
rm -f *.o *.so *.So *.ko *.s eddep errs kernel.debug kernel kernel.symbols linterrs makelinks tags vers.c vnode_if.c vnode_if.h vnode_if_newproto.h vnode_if_typedef.h agp_if.c ata_if.c eisa_if.c miibus_if.c mmcbr_if.c mmcbus_if.c mvs_if.c card_if.c power_if.c pci_if.c pcib_if.c ppbus_if.c hdac_if.c ac97_if.c channel_if.c feeder_if.c mixer_if.c mpu_if.c mpufoi_if.c synth_if.c uart_if.c usb_if.c g_part_if.c g_raid_md_if.c g_raid_tr_if.c isa_if.c bus_if.c clock_if.c cpufreq_if.c device_if.c linker_if.c serdev_if.c acpi_if.c acpi_wmi_if.c agp_if.h ata_if.h eisa_if.h miibus_if.h mmcbr_if.h mmcbus_if.h mvs_if.h card_if.h power_if.h pci_if.h pcib_if.h ppbus_if.h hdac_if.h ac97_if.h channel_if.h feeder_if.h mixer_if.h mpu_if.h mpufoi_if.h synth_if.h uart_if.h usb_if.h g_part_if.h g_raid_md_if.h g_raid_tr_if.h isa_if.h bus_if.h clock_if.h cpufreq_if.h device_if.h linker_if.h serdev_if.h acpi_if.h acpi_wmi_if.h acpi_quirks.h aicasm* y.tab.h aic7xxx_seq.h aic7xxx_reg.h aic7xxx_reg_print.c aic79xx_seq.h aic79xx_reg.h aic79xx_reg_print.c feeder_eq_gen.h feeder_rate_gen.h snd_fxdiv_gen.h miidevs.h pccarddevs.h teken_state.h usbdevs.h usbdevs_data.h acpi_wakecode.o acpi_wakecode.bin acpi_wakecode.h acpi_wakedata.h
rm -f .depend machine x86
会删除一些生成的临时文件,和一些头文件,再生成这些头文件,FreeBSD的内核编译的时候,头文件变了,相关的c文件都是要重新编译过的。这就解释上面的增量编译xfs的时候,会要编译一些不相关的文件。
再回到上面的:
110 cam/ata/ata_all.c optional scbus
这个scbus option是在哪里开的?
很简单了,就是在文件夹/usr/src/sys/i386/conf/下面
ztz0223@BTazuo:/usr/src/sys/i386/conf %
打开GENERIC文件看就知道了:
18 #
19 # $FreeBSD: release/9.1.0/sys/i386/conf/GENERIC 235877 2012-05-24 03:45:13Z mav $
20
21 cpu I486_CPU
22 cpu I586_CPU
23 cpu I686_CPU
24 ident GENERIC
25
26 makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols
27
28 options SCHED_ULE # ULE scheduler
29 options PREEMPTION # Enable kernel thread preemption
30 options INET # InterNETworking
31 options INET6 # IPv6 communications protocols
32 options SCTP # Stream Control Transmission Protocol
33 options FFS # Berkeley Fast Filesystem
34 options SOFTUPDATES # Enable FFS soft updates support
35 options UFS_ACL # Support for access control lists
36 options UFS_DIRHASH # Improve performance on big directories
37 options UFS_GJOURNAL # Enable gjournal-based UFS journaling
38 options MD_ROOT # MD is a potential root device
39 options NFSCL # New Network Filesystem Client
40 options NFSD # New Network Filesystem Server
41 options NFSLOCKD # Network Lock Manager
42 options NFS_ROOT # NFS usable as /, requires NFSCL
43 options MSDOSFS # MSDOS Filesystem
44 options CD9660 # ISO 9660 Filesystem
45 options PROCFS # Process filesystem (requires PSEUDOFS)
46 options PSEUDOFS # Pseudo-filesystem framework
47 options GEOM_PART_GPT # GUID Partition Tables.
48 options GEOM_RAID # Soft RAID functionality.
49 options GEOM_LABEL # Provides labelization
50 options COMPAT_FREEBSD4 # Compatible with FreeBSD4
51 options COMPAT_FREEBSD5 # Compatible with FreeBSD5
52 options COMPAT_FREEBSD6 # Compatible with FreeBSD6
53 options COMPAT_FREEBSD7 # Compatible with FreeBSD7
54 options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI
55 options KTRACE # ktrace(1) support
56 options STACK # stack(9) support
"GENERIC" [readonly] 361L, 14505C
这里有options,标识对应的选项开启了。
还有一个问题,就是代码里面有一些:
137 #ifdef INET
138 int (*carp_iamatch_p)(struct ifnet *, struct in_ifaddr *, struct in_addr *,
139 u_int8_t **);
140 #endif
141 #ifdef INET6
142 struct ifaddr *(*carp_iamatch6_p)(struct ifnet *ifp, struct in6_addr *taddr6);
143 caddr_t (*carp_macmatch6_p)(struct ifnet *ifp, struct mbuf *m,
144 const struct in6_addr *taddr);
145 #endif
146
147 struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL;
148
"net/if.c" [readonly] 3419 lines --2%--
这个INET在哪里定义的呢?
回到路径::/usr/src/sys/conf ,查看两个文件:
-rw-r--r-- 1 root wheel 23377 Dec 4 06:11 options
-rw-r--r-- 1 root wheel 1563 Dec 4 06:11 options.i386
ztz0223@BTazuo:/usr/src/sys/conf % less options
388 DEVICE_POLLING
389 DEV_ENC opt_enc.h
390 DEV_PF opt_pf.h
391 DEV_PFLOG opt_pf.h
392 DEV_PFSYNC opt_pf.h
393 DEV_VLAN opt_vlan.h
394 DUMMYNET opt_ipdn.h
395 ETHER_8022 opt_ef.h
396 ETHER_8023 opt_ef.h
397 ETHER_II opt_ef.h
398 ETHER_SNAP opt_ef.h
399 INET opt_inet.h
400 INET6 opt_inet6.h
则可以知道INET就定义在opt_inet.h中,而在编译过FreeBSD内核之后,在/usr/obj/usr/src/sys/GENERIC生成的临时文件路径下面,就有这个opt_inet.h文件了,查看一下:
ztz0223@BTazuo:/usr/obj/usr/src/sys/GENERIC_20130217 % vim opt_inet.h
1 #define INET 1
同样options.i386里面也会指定一些平台代码需要的头文件和宏定义。
最后一个问题,就是在/etc/make.conf指定:
MODULES_OVERRIDE = xfs
标识增量编译xfs,那么xfs就是一个模块,该模块在哪里指定?在/usr/src/sys/modules下面,有很多文件夹:
ztz0223@BTazuo:/usr/src/sys/modules % ls -la | grep xfs
drwxr-xr-x 2 root wheel 512 Dec 4 05:09 xfs
ztz0223@BTazuo:/usr/src/sys/modules %
这个下面的文件夹里面只有Makefile,没有其他的东西的,这些Makefile就是指定编译模块增量编译内核的时候,指定编译的Makefile了。
这里看一下xfs下面的Makefile内容了:
ztz0223@BTazuo:/usr/src/sys/modules % cat xfs/Makefile
# $FreeBSD: release/9.1.0/sys/modules/xfs/Makefile 229734 2012-01-06 21:23:00Z dim $
.PATH: ${.CURDIR}/../../gnu/fs/xfs \
${.CURDIR}/../../gnu/fs/xfs/FreeBSD \
${.CURDIR}/../../gnu/fs/xfs/FreeBSD/support
KMOD= xfs
WERROR=
SRCS = vnode_if.h \
xfs_alloc.c \
xfs_alloc_btree.c \
xfs_bit.c \
xfs_bmap.c \
xfs_bmap_btree.c \
xfs_btree.c \
xfs_buf_item.c \
xfs_da_btree.c \
xfs_dir.c \
xfs_dir2.c \
xfs_dir2_block.c \
xfs_dir2_data.c \
xfs_dir2_leaf.c \
xfs_dir2_node.c \
xfs_dir2_sf.c \
xfs_dir2_trace.c \
xfs_dir_leaf.c \
xfs_error.c \
xfs_extfree_item.c \
xfs_freebsd_iget.c \
xfs_fsops.c \
xfs_ialloc.c \
xfs_ialloc_btree.c \
xfs_inode.c \
xfs_inode_item.c \
xfs_iocore.c \
xfs_itable.c \
xfs_dfrag.c \
xfs_log.c \
xfs_log_recover.c \
xfs_mount.c \
xfs_rename.c \
xfs_trans.c \
xfs_trans_ail.c \
xfs_trans_buf.c \
xfs_trans_extfree.c \
xfs_trans_inode.c \
xfs_trans_item.c \
xfs_utils.c \
xfs_vfsops.c \
xfs_vnodeops.c \
xfs_rw.c \
xfs_iget.c \
xfs_attr_leaf.c \
xfs_attr.c \
xfs_dmops.c \
xfs_qmops.c \
xfs_mountops.c \
xfs_vnops.c \
xfs_frw.c \
xfs_iomap.c \
xfs_buf.c \
xfs_globals.c \
xfs_dmistubs.c \
xfs_behavior.c \
xfs_super.c \
xfs_stats.c \
xfs_sysctl.c \
xfs_vfs.c \
xfs_vnode.c \
xfs_fs_subr.c \
xfs_ioctl.c \
debug.c \
ktrace.c \
mrlock.c \
uuid.c \
kmem.c \
kdb.c
SRCS+= opt_ddb.h
.include <bsd.kmod.mk>
CFLAGS+= -I${.CURDIR}/../../gnu/fs/xfs/FreeBSD \
-I${.CURDIR}/../../gnu/fs/xfs/FreeBSD/support \
-I${.CURDIR}/../../gnu/fs/xfs
CWARNFLAGS.xfs_ioctl.c= ${NO_WSELF_ASSIGN}
CWARNFLAGS+= ${CWARNFLAGS.${.IMPSRC:T}}
ztz0223@BTazuo:/usr/src/sys/modules %
再看一下,增量编译的过程打印,这里只附上xfs链接的相关的部分:
ld -d -warn-common -r -d -o xfs.kld xfs_alloc.o xfs_alloc_btree.o xfs_bit.o xfs_bmap.o xfs_bmap_btree.o xfs_btree.o xfs_buf_item.o xfs_da_btree.o xfs_dir.o xfs_dir2.o xfs_dir2_block.o xfs_dir2_data.o xfs_dir2_leaf.o xfs_dir2_node.o xfs_dir2_sf.o xfs_dir2_trace.o xfs_dir_leaf.o xfs_error.o xfs_extfree_item.o xfs_freebsd_iget.o xfs_fsops.o xfs_ialloc.o xfs_ialloc_btree.o xfs_inode.o xfs_inode_item.o xfs_iocore.o xfs_itable.o xfs_dfrag.o xfs_log.o xfs_log_recover.o xfs_mount.o xfs_rename.o xfs_trans.o xfs_trans_ail.o xfs_trans_buf.o xfs_trans_extfree.o xfs_trans_inode.o xfs_trans_item.o xfs_utils.o xfs_vfsops.o xfs_vnodeops.o xfs_rw.o xfs_iget.o xfs_attr_leaf.o xfs_attr.o xfs_dmops.o xfs_qmops.o xfs_mountops.o xfs_vnops.o xfs_frw.o xfs_iomap.o xfs_buf.o xfs_globals.o xfs_dmistubs.o xfs_behavior.o xfs_super.o xfs_stats.o xfs_sysctl.o xfs_vfs.o xfs_vnode.o xfs_fs_subr.o xfs_ioctl.o debug.o ktrace.o mrlock.o uuid.o kmem.o kdb.o
有这么多,我想足够理解了。
FreeBSD 9.1内核文件编译分析相关推荐
- Linux内核文件vmlinux 和压缩后的bzImage文件格式分析
Linux内核文件vmlinux 和压缩后的bzImage文件格式分析 ================= 1. 需要使用的命令 ================ readelf -- 显示el ...
- linux内核体系学习路径_Linux内核分析(一)linux体系简介|内核源码简介|内核配置编译安装...
从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底,同时在博文中如果那些地方有问题还请各位大神为我讲解. 今天我们会分析到以下内容: 1. Linux体系结构简介 ...
- 如何编译Linux内核文件
如何编译Linux内核文件 参考:朱有鹏Uboot的全集 前言:我们的Linux内核文件动则数万个文件,很多个子文件夹,当然是使用Makefile管理了,但是是不是真的仅仅只是make一下就可以了呢? ...
- C语言多文件编译的精神内核-讲透多文件编译攻略
本文讲述C语言多文件编译的精神内核,语法规则,应用场景等知识,旨在帮助初学者了解软件工程基本原理,多文件编译的优势和必然,从而更好的开发出可维护性更高,复杂度更高的有效程序. 一.为什么要多文件? 想 ...
- v18.02 鸿蒙内核源码分析(源码结构) | 内核文件各自含义 | 百篇博客分析HarmonyOS源码
子曰:"富而可求也,虽执鞭之士,吾亦为之.如不可求,从吾所好." <论语>:述而篇 百篇博客系列篇.本篇为: v18.xx 鸿蒙内核源码分析(源码结构篇) | 内核文件 ...
- v62.02 鸿蒙内核源码分析(文件概念) | 为什么说一切皆是文件 | 百篇博客分析OpenHarmony源码
司马牛忧曰:"人皆有兄弟,我独亡."子夏曰:"商闻之矣:死生有命,富贵在天.君子敬而无失,与人恭而有礼.四海之内,皆兄弟也.君子何患乎无兄弟也?" <论语 ...
- v50.03 鸿蒙内核源码分析(编译环境) | 编译鸿蒙防掉坑指南 | 百篇博客分析HarmonyOS源码
颜渊死.子曰:"噫!天丧予!天丧予!" <论语>:先进篇 百篇博客系列篇.本篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙防掉坑指南 编译构建相关篇 ...
- GCC的编译过程以及其同盟成员和ELF文件的分析
文章目录 一.GCC的同盟成员介绍 1.GCC的介绍 2.同盟成员之Binutils 3.同盟成员之C 运行库 二.GCC的详细编译过程 1.编译的简介 2.预处理(Preprocessing) 3. ...
- v58.03 鸿蒙内核源码分析(环境脚本) | 编译鸿蒙原来很简单 | 百篇博客分析HarmonyOS源码
颜渊问仁.子曰:"克己复礼为仁.一日克己复礼,天下归仁焉.为仁由己,而由人乎哉?"颜渊曰:"请问其目."子曰:"非礼勿视,非礼勿听,非礼勿言,非礼勿动 ...
- v57.02 鸿蒙内核源码分析(编译过程) | 简单案例说透中间过程 | 百篇博客分析HarmonyOS源码
子畏于匡,颜渊后.子曰:"吾以女为死矣."曰:"子在,回何敢死?" <论语>:先进篇 百篇博客系列篇.本篇为: v57.xx 鸿蒙内核源码分析(编译 ...
最新文章
- spark sql 本地调试_Spark精华问答|Spark的三种运行模式有何区别?
- 当思科交换机密码遗忘之后......(附图)
- OpenDDS安装与开发
- 【IT笔试面试题整理】给定二叉树,给每层生成一个链表
- linux nginx 503,GitLab网页500/502/503错误–Nginx无法启动问题排查
- 12星座的出生年月日性格_星座六点半/今日12月04日:双鱼、巨蟹、天蝎座运势...
- 版本控制工具(CVS、SVN、GIT)简介
- 未来会有特供iPhone 来针对各国调查法案?
- Java ResultSet教程
- MySQL源码调试入门
- K3CLOUD业务系统编码规则设置
- MATLBA中最小二乘支持向量机原理+实例分析
- python的turtle模块制作的打地鼠小游戏2019/4/9版
- 薛逸凡计算机生物学,北大的孤独专业:一人旷课全系放假,毕业照从来只有一人...
- Android 常用控件详解
- 用 Creator 写微信小游戏排行榜
- 【IOS】《捕鱼达人》的简单实现(一)
- 【树莓派初始化】教你从0开始搭建树莓派的使用环境
- 华盛顿大学计算机语言学,华盛顿大学人工智能专业排名2020年
- 系统总结深度学习的主要的损失函数和优化器
热门文章
- 一台机器启动相同服务导致端口占用,日志报错The Tomcat connector configured to listen on port 8090 failed to start.
- ad19pcb设置恢复默认_Oracle DB使用快速恢复区
- java 取上界_java 泛型中的上界(extend)和下界(super)
- java版 ide 卡_完美解决idea突然间很卡的问题
- webpack-dev-server的配置和使用——热更新、热替换、proxy代理
- 你应该了解的大数据10个新趋势
- H5页面直接扫码二维码插件
- python get hist data_[宜配屋]听图阁
- Maven clean
- gdc服务器硬盘修复,GDC环球数码SX-3000独立媒体模块AHCI设置