转载请标注:

全面剖析《自己动手写操作系统》第五章---makefile文件

http://blog.csdn.net/zgh1988/article/details/7338380

1、make概述

2、编译和链接

3、makefile规则

4、自己动手写makefile文件

5、后记

一、make概述

作为程序员,我们都有使用过Visualstdio 2005、VC6.0、eclipse等经典开发工具,使用它们,我们可以方便地建立和管理自己的工程,往往直接点击两个按钮,就完成了编译,链接,运行等功能。但是我们有没有过这样的疑问?它是怎样做到的,它是怎样将不在一起的文件组合到一起的,我们自己能不能管理自己的工程呢。是的,在Linux环境下使用GNU的make工具就可以构建和管理自己的工程,而且还可以自己操作它们的编译、链接等。

在了解make工具之前,我们需要知道makefile文件,该文件就是用来描述整个工程的编译、链接等规则,其中包括:工程中的哪些源文件需要编译以及如何编译、需要创建哪些库文件以及如何创建这些库文件、如何最后产生我们想要得到的可执行文件。我们的任务就是要掌握如何书写makefile文件。makefile文件有自己的书写格式、关键字、函数,而且可以使用系统shell所提供的任何命令(例如:nasm gcc等指令)。

make是一个命令工具,它解释makefile文件中的指令。在书写好makefile文件之后,我们只需要在shell提示符下输入make命令,整个工程就会按照makefile文件中的内容完全自动编译,极大的提高了效率。

二、编译和链接

传统意义上,在生成系统可执行文件之前,需要进行两步走战略:编译和链接。

编译(compile):指用编译器(compiler)将源代码(sourcecode)生成二进制目标文件(object file),在Windows下也就是 .obj 文件,Linux下是 .o 文件。编译时,编译器需要检查高级语言的语法,函数与变量的声明是否正确。只有所有语法正确,函数与变量声明正确,编译器就可以编译出二进制目标文件。为了和最终生成的可执行目标文件区别,我们暂且称编译后的目标文件为.o文件。

链接(link):找到所要用到函数所在的目标文件(.o文件),并把它们链接在一起合成为可执行文件(executable file),在Linux环境下,可执行文件的格式为“ELF”格式。链接时,要确保编译器能找到所有被用到了的函数所在的目标文件。链接过程中使用GNU的“ld”工具。

三、makefile规则

一个简单的makefile规则:

TARGET :PREREQUISITES

COMMAND

从这个形式上来看,我们可以得到两层含义:

(1) 要想得到TARGET,需要执行命令COMMAND。

(2) TARGET依赖于PREREQUISITES,当PREREQUISITES中至少有一个文件比TARGET文件新时,COMMAND才被执行。

TARGET :规则的目标。通常是最终可以在系统上运行的目标文件 或 实现这个目标文件所需要的中间过程文件。例如.o文件 或者 最后的可执行文件。另外,目标也可以是一个make执行的动作名称,如目标“clean”,不过我们称这样的目标为“伪目标”。

PREREQUISITES : 规则的依赖。生成规则目标所需要的文件列表,通常一个目标文件依赖于一个或者多个文件。

        COMMAND : 规则的命令行。是规则所要执行的动作。

(语法1)一个规则可以有多个命令行,每一条命令行占一行。注意:每一个命令行必须以【TAB】字符开始,【TAB】字符告诉make此行是一个命令行。

四、自己动手写makefile

1、一个简单的例子

目标:生成boot.bin和loader.bin文件

条件:boot.asm 包含 load.inc fat12hdr.inc

loader.asm 包含 load.incfat12hdr.inc pm.inc

下面我们开始写makefile文件:

(1) 首先我们要写出生成boot.bin 的规则:

boot.bin : boot.asm load.inc fat12hdr.inc

nasm–o boot.bin boot.asm

另外我们写出生成loader.bin的规则:

loader.bin : loader.asm load.incfat12hdr.inc pm.inc

nasm–o loader.bin loader.asm

我们将这两条规则保存到makefile文件中,将makefile文件放在boot文件下。

此时,如果我们只输入命令行make,发现它只是执行了第一条规则,也就是只生成了boot.bin目标文件。(语法2)因为在默认情况下,make执行的是makefile中的第一个规则。如果想执行第二条规则,我们必须执行make loader.bin,才能够达到目的。

(2) 问题又来了,我们如何通过一条命令把两个规则都执行了呢?我在文件开始处,添加了这样的一条规则,作为该makefile的第一条规则。

everything : boot.bin loader.bin

这个规则虽然命令行为空,也就是不做任何工作,但是makefile中有这样一条规则,(语法3)make在执行一条规则所定义的命令之前,首先需要处理的是目标文件的所有的依赖文件,在此规则中,也就是boot.bin 和 loader.bin。如果依赖文件不存在,则make会按照依赖文件列表从左到右的顺序依次寻找创建这些依赖文件的规则。

所以在本例中,在执行everything: boot.bin loader.bin这条规则之前,make发现其依赖文件boot.bin 和loader.bin文件不存在,就会去寻找创建这些依赖条件的规则,即规则2,和规则3,分别执行规则2,3,完成boot.bin loader.bin的创建。

(3) 此时我们在输入命令make,会发现一个错误:make:`everything' is up to date。这是为什么呢?难道我们写的规则出现问题了吗?

我们写的makefile文件是正确的,下面我来告诉你makefile的另一条规则(语法4)在执行一条规则中,如果目标文件不存在,则执行该规则以创建目标文件;如果目标文件存在,其依赖文件中有一个或者多个文件比它“更新”—也就是说依赖文件中有一个或者多个文件在目标文件生成之后,进行了修改,则根据规则重新创建目标文件;如果目标文件存在,它比它的任何一个依赖文件都要“更新”—也就是说在生成目标文件之后,所有的依赖文件都没有发生修改,则什么都不做。

所以此时执行make命令会发生错误。因为之前我们已经生成了boot.bin 和 loader.bin文件,而且其依赖文件列表没有更新。

此时怎么办呢?让我们在写一条规则放在最后一行:

clean :

rm–f boot.bin loader.bin

它不存在依赖条件,它是一条伪规则,命令行的作用是删除文件boot.bin loader.bin。我们通常使用rm指令,来删除一些中间生成文件(例如.o文件)。

(4) 最终的makefile文件如下:

everything : boot.bin loader.bin

boot.bin : boot.asm load.inc fat12hdr.inc

nasm-o boot.bin boot.asm

loader.bin : loader.asm load.incfat12hdr.inc pm.inc

nasm-o loader.bin loader.asm

clean:

rm-f boot.bin loader.bin

现在我们就可以先执行一个make clean,将目标文件boot.bin loader.bin删除,然后再执行make命令。执行结果如下:

这样我们就完成了我们第一个最简单的例子。

下面让我们来回忆上面所提到的4条规则:

(语法1)一个规则可以有多个命令行,每一条命令行占一行。注意:每一个命令行必须以[TAB]字符开始,【TAB】字符告诉make此行是一个命令行。

(语法2)因为在默认情况下,make执行的是makefile中的第一个规则。

(语法3)make在执行一条规则所定义的命令之前,首先需要处理的是目标文件的所有的依赖文件,如果依赖文件不存在,则make会按照依赖文件列表从左到右的顺序依次寻找创建这些依赖文件的规则。

(语法4)在执行一条规则中,如果目标文件不存在,则执行该规则以创建目标文件;如果目标文件存在,其依赖文件中有一个或者多个文件比它“更新”—也就是说依赖文件中有一个或者多个文件在目标文件生成之后,进行了修改,则根据规则重新创建目标文件;如果目标文件存在,它比它的任何一个依赖文件都要“更新”—也就是说在生成目标文件之后,所有的依赖文件都没有发生修改,则什么都不做。

2、又是一个简单的问题

此时,为了让整个工程规范,我将头文件load.inc fat12hdr.inc pm.inc放在包含在include下的文件夹里面。此时的makefile文件还是在boot文件夹目录下,此时的makefile该怎么写呢?如果我们不加修改的话,运行make指令肯定会出问题。原因是无法找到依赖文件列表中的load.inc fat12hdr.inc pm.inc文件,因为它们的路径不在/boot下,而是搬到了boot/include下。所以修改makefile文件如下:

everything : boot.bin loader.bin

boot.bin : boot.asm include/load.incinclude/fat12hdr.inc

nasm-I include -o boot.bin boot.asm

loader.bin : loader.asm include/load.incinclude/fat12hdr.inc include/pm.inc

nasm-I include -o loader.bin loader.asm

clean:

rm-f boot.bin loader.bin

我们相当于添加了一个路径来帮助make自己寻找这些头文件。在nasm指令中,-I 指的就是路径。

下面是运行结果:

3、为makefile添加变量

这时候,你有没有想过,如果我的工程不断的扩大,到时候我这样一点点的写是不是很麻烦,还会出好多问题。

其实我还有一点没有告诉你呢,在makefile中,是可以添加变量的。所以我们就要将一些内容赋值给变量,在以后的道路上,我们就可以修改变量了。

在此问题上,我就要添加变量来简化makefile文件,使其更加清晰明了。

# Makefile for boot

# Programs, flags,etc.

ASM              = nasm

ASMFLAGS = -I include

# This Program

TARGET    =  boot.bin loader.bin

# All Phony Targets

.PHONY : everything clean all

# Default starting position

everything :      $(TARGET)

clean :

rm -f $(TARGET)

all :   clean everything

boot.bin : boot.asminclude/load.inc include/fat12hdr.inc

$(ASM)  $(ASMFLAGS) -o $@ $<

loader.bin :loader.asm include/load.inc include/fat12hdr.inc include/pm.inc

$(ASM)  $(ASMFLAGS) -o $@ $<

首先,我们看到的是两个命令行变量,ASM = nasm  ASMFLAGS = -Iinclude

在今后我们使用到nasm 和–I include 时,我们就只需要用$(ASM), $(ASMFLAGS)来代替,$这个符号的含义,就是取值操作。

其次是TARGET = boot.bin loader.bin,我们定义了一个目标变量,它的值保护boot.bin和loader.bin。所以在

everything :$(TARGET)  相当于everything : boot.bin loader.bin。

然后你注意到了我们将everything clean all定义为了.PHONY,我们知道everything clean all只是动作,它是伪规则,所以我们用.PHONY来定义它们。

最后是两个规则,一个是生成boot.bin,一个是loader.bin。

$(ASM) $(ASMFLAGS) –o $@ $< 相当于:

nasm -I include -o loader.bin loader.asm

S@ = loader.bin  $< = loader.asm

这时候我们发现,我们的第二个规则有点长,所以我们需要将其变短一些。(语法5)这时候我们需要使用反斜线(\)将一个较长的行分成多行,这样我们的makefile书写清晰、容易阅读理解。但需要注意:反斜线之后不能有空格(这也是大家最容易犯的错误,错误比较隐蔽)

loader.bin : loader.asm include/load.incinclude/fat12hdr.inc \

include/pm.inc

$(ASM)$(ASMFLAGS) -o $@ $<

4、一个复杂的问题

这是本章中最后生成的操作系统的工程目录表,通过它我们来熟悉书写makefile的步骤:
(1) 我们应该找到目标文件和依赖文件之间的关系
boot/boot.asm : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc
boot/loader.asm : boot/loader.asm boot/include/load.inc boot/include/fat12hdr.inc \
boot/include/pm.inc
kernel/kernel.o : kernel/kernel.asm
kernel/start.o : kernel/start.c  include/type.h  include/const.h  include/protect.h \include/proto.h  include/string.h  include/global.h
kernel/i8259.o : kernel/i8259.c include/type.h include/const.h include/protect.h \include/proto.h
kernel/global.o : kernel/global.c include/type.h include/const.h include/protect.h \include/proto.h include/global.h
kernel/protect.o : kernel/protect.c include/type.h include/const.h include/protect.h \include/global.h
lib/klib.o : lib/klib.asm
lib/string.o : lib/string.asm
lib/klibc.o : lib/klib.c include/type.h include/const.h include/protect.h include/string.h \include/proto.h include/global.h
kernel.bin : kernel/kernel.o kernel/start.o kernel/i8259.o kernel/global.o kernel/protect.o \
lib/klib.o lib/string.o lib/klibc.o

(2) 根据上面的目标文件,我们需要定义目标变量,此时不要求完整,随着思考一步步的去完善。

TINIXBOOT       = boot/boot.bin boot/loader.bin

TINIXKERNEL  = kernel.bin

OBJS                 = kernel/kernel.o kernel/start.okernel/i8259.o kernel/global.o kernel/protect.o lib/klib.o lib/string.olib/klibc.o

DASMOUTPUT= kernel.bin.asm

(3) 我们可以需要取定义一些命令变量,此时不要求完整,随着思考一步步的去完善。

ASM          =nasm

DASM       =ndisasm

CC             =gcc

LD              =ld

ASMBFLAGS     =-I boot/include

ASMKFLAGS     =-I include -f elf

ASMKLFLAGS   =-f elf

CFLAGS              =-I include -c -fno-builtin

LDFLAGS           =-s -Ttext $(ENTRYPOINT)

DASMFLAGS     =-u -o $(ENTRYPOINT) -e $(ENTRYOFFSET)

(4) 然后我们开始尝试组织这些变量,生成各种规则。

boot/boot.bin : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc$(ASM) $(ASMBFLAGS) -o $@ $<boot/loader.bin : boot/loader.asm boot/include/load.inc boot/include/fat12hdr.inc \boot/include/pm.inc$(ASM) $(ASMBFLAGS) -o $@ $<$(TINIXKERNEL) : $(OBJS)$(LD) $(LDFLAGS) -o $(TINIXKERNEL) $(OBJS)kernel/kernel.o : kernel/kernel.asm$(ASM) $(ASMKFLAGS) -o $@ $<kernel/start.o : kernel/start.c include/type.h include/const.h include/protect.h \include/string.h include/proto.h$(CC) $(CFLAGS) -o $@ $<kernel/i8259.o : kernel/i8259.c include/type.h include/const.h include/protect.h \include/proto.h$(CC) $(CFLAGS) -o $@ $<kernel/global.o : kernel/global.c include/type.h include/const.h include/protect.h \include/proto.h include/global.h$(CC) $(CFLAGS) -o $@ $<kernel/protect.o : kernel/protect.c include/type.h include/const.h include/protect.h \include/global.h$(CC) $(CFLAGS) -o $@ $<lib/klib.o : lib/klib.asm$(ASM) $(ASMKLFLAGS) -o $@ $<lib/string.o : lib/string.asm$(ASM) $(ASMKLFLAGS) -o $@ $<lib/klibc.o : lib/klib.c include/type.h include/const.h include/protect.h include/string.h \include/proto.h include/global.h$(CC) $(CFLAGS) -o $@ $<

(5) 最后需要完成一些不同的伪规则,也就是行为,将其中的某些行为进行组合。

# All Phony Targets
.PHONY : everything final image cleanrealclean disasm all buildimg
# Default starting position
everything : $(TINIXBOOT) $(TINIXKERNEL)
all : realclean everythingfinal : all cleanimage : final buildimgclean :rm -f $(OBJS)
realclean:rm -f $(OBJS)  $(TINIXBOOT)  $(TINIXKERNEL)
disasm :$(DASM) $(DASMFLAGS)  $(TINIXKERNEL) > $(DASMOUTPUT)# Write "boot.bin" &"loader.bin" into floppy image "TINIX.IMG"
# We assume that "TINIX.IMG"exists in current folder
buildimg:mount Tinix.vfd  /mnt/floppy -o loopcp -f  boot/loader.bin  /mnt/floppycp -f kernel.bin  /mnt/floppyumount /mnt/floppy

make+不同的伪规则形成不同的结果:

make everything:
nasm -I boot/include -o boot/boot.binboot/boot.asm
nasm -I boot/include -o boot/loader.binboot/loader.asm
nasm -I include -f elf -o kernel/kernel.o kernel/kernel.asm
gcc -I include -c -fno-builtin -okernel/start.o kernel/start.c
nasm -f elf -o lib/klib.o lib/klib.asm
nasm -f elf -o lib/string.o lib/string.asm
ld -s -Ttext 0x30400 -o kernel.binkernel/kernel.o kernel/start.o lib/klib.o lib/string.omake clean:
rm -f kernel/kernel.o kernel/start.o lib/klib.o lib/string.omake realclean:
rm -f kernel/kernel.o kernel/start.o lib/klib.o lib/string.o boot/boot.bin boot/loader.bin kernel.binmake buildimg:
mount Tinix.vfd /mnt/floppy -o loop
cp -f boot/loader.bin /mnt/floppy
cp -f kernel.bin /mnt/floppy
umount /mnt/floppymake all:
make realclean
make everythingmake final:
make all (make realclean make everything)
make cleanmake image:
make final (make all(make realclean makeeverything))
make buildimg

(6) 最后的结果如下:

# Makefile for TINIX# Entry Point of Tinix
# It must be as same as 'KernelEntryPointPhyAddr' in load.inc!!!
ENTRYPOINT  = 0x30400# Offset of entry point in kernel file
# It depends on ENTRYPOINT
ENTRYOFFSET = 0x400# Programs, flags, etc.
ASM     = nasm
DASM        = ndisasm
CC      = gcc
LD      = ld
ASMBFLAGS   = -I boot/include
ASMKFLAGS   = -I include -f elf
ASMKLFLAGS  = -f elf
CFLAGS      = -I include -c -fno-builtin
LDFLAGS     = -s -Ttext $(ENTRYPOINT)
DASMFLAGS   = -u -o $(ENTRYPOINT) -e $(ENTRYOFFSET)# This Program
TINIXBOOT   = boot/boot.bin boot/loader.bin
TINIXKERNEL = kernel.bin
OBJS        = kernel/kernel.o kernel/start.o kernel/i8259.o kernel/global.o kernel/protect.o lib/klib.o lib/string.o lib/klibc.o
DASMOUTPUT  = kernel.bin.asm# All Phony Targets
.PHONY : everything final image clean realclean disasm all buildimg# Default starting position
everything : $(TINIXBOOT) $(TINIXKERNEL)all : realclean everythingfinal : all cleanimage : final buildimgclean : rm -f $(OBJS)realclean:rm -f $(OBJS) $(TINIXBOOT) $(TINIXKERNEL)disasm :$(DASM) $(DASMFLAGS) $(TINIXKERNEL) > $(DASMOUTPUT)# Write "boot.bin" & "loader.bin" into floppy image "TINIX.IMG"
# We assume that "TINIX.IMG" exists in current folder
buildimg:mount Tinix.vfd /mnt/floppy -o loopcp -f boot/loader.bin /mnt/floppycp -f kernel.bin /mnt/floppyumount /mnt/floppyboot/boot.bin : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc$(ASM) $(ASMBFLAGS) -o $@ $<boot/loader.bin : boot/loader.asm boot/include/load.inc boot/include/fat12hdr.inc \boot/include/pm.inc$(ASM) $(ASMBFLAGS) -o $@ $<$(TINIXKERNEL) : $(OBJS)$(LD) $(LDFLAGS) -o $(TINIXKERNEL) $(OBJS)kernel/kernel.o : kernel/kernel.asm$(ASM) $(ASMKFLAGS) -o $@ $<kernel/start.o : kernel/start.c include/type.h include/const.h include/protect.h \include/string.h include/proto.h$(CC) $(CFLAGS) -o $@ $<kernel/i8259.o : kernel/i8259.c include/type.h include/const.h include/protect.h \include/proto.h$(CC) $(CFLAGS) -o $@ $<kernel/global.o : kernel/global.c include/type.h include/const.h include/protect.h \include/proto.h include/global.h$(CC) $(CFLAGS) -o $@ $<kernel/protect.o : kernel/protect.c include/type.h include/const.h include/protect.h \include/global.h$(CC) $(CFLAGS) -o $@ $<lib/klib.o : lib/klib.asm$(ASM) $(ASMKLFLAGS) -o $@ $<lib/string.o : lib/string.asm$(ASM) $(ASMKLFLAGS) -o $@ $<lib/klibc.o : lib/klib.c include/type.h include/const.h include/protect.h include/string.h \include/proto.h include/global.h$(CC) $(CFLAGS) -o $@ $<

五、后记

本着够用原则,只学习了这么一点关于makefile的知识,希望在以后的时间里,能够对makefile进行深入研究。

全面剖析《自己动手写操作系统》第五章---加载内核kernel.bin http://blog.csdn.net/zgh1988/article/details/7329941

全面剖析《自己动手写操作系统》第五章---Red Hat 9.0 的安装过程  http://blog.csdn.net/zgh1988/article/details/7315676

全面剖析《自己动手写操作系统》第四章---FAT12文件系统 http://blog.csdn.net/zgh1988/article/details/7284834

全面剖析《自己动手写操作系统》第四章---加载Loader.bin http://blog.csdn.net/zgh1988/article/details/7291909

全面剖析《自己动手写操作系统》第三章---进入保护模式   http://blog.csdn.net/zgh1988/article/details/7098981

全面剖析《自己动手写操作系统》第三章---“实模式--保护模式--实模式” http://blog.csdn.net/zgh1988/article/details/7255804

全面剖析《自己动手写操作系统》第三章---堆栈段的工作方式 http://blog.csdn.net/zgh1988/article/details/7256254

全面剖析《自己动手写操作系统》第三章---特权级以及不同特权级代码段之间的跳转 http://blog.csdn.net/zgh1988/article/details/7262901

全面剖析《自己动手写操作系统》第三章---分页机制 http://blog.csdn.net/zgh1988/article/details/7270748

全面剖析《自己动手写操作系统》第三章---中断机制 http://blog.csdn.net/zgh1988/article/details/7276259

全面剖析《自己动手写操作系统》第二章http://blog.csdn.net/zgh1988/article/details/7062065

全面剖析《自己动手写操作系统》第一章http://blog.csdn.net/zgh1988/article/details/7060032

《自己动手写操作系统》读后感http://blog.csdn.net/zgh1988/article/details/7059936

全面剖析《自己动手写操作系统》第五章---makefile文件相关推荐

  1. 自己动手写操作系统第三章pmtest7源码解析——检测系统内存

    摘要:在pmtest6.asm中,我们已经初步接触了分页机制,但是很显然,上述分页机制浪费比较严重,而且没有体现应有的用处.本节,我们主要介绍如何根据内存容量,恰当地分配页表. 一.理论基础 1.如何 ...

  2. 全面剖析《自己动手写操作系统》第四章---加载Loader.bin

    全面剖析<自己动手写操作系统>第四章--FAT12文件系统    http://blog.csdn.net/zgh1988/article/details/7284834 1.突破512字 ...

  3. 「操作系统」《自己动手写操作系统》1.1前期准备工作

    一.软硬件 1.硬件 一台计算机(笔者使用的是Win7 x64操作系统) 2.软件 点击此处下载<自己动手写操作系统>的光盘配套文件以及相应工具 汇编编译器:NASM(资源文件中有) 软盘 ...

  4. 磨刀不误砍柴工 —— 自己动手写操作系统 入门导引

    磨刀不误砍柴工 刺猬@http://blog.csdn.net/littlehedgehog <自己动手写操作系统>其实阅读所需要的前提不过只是C和汇编了,里面涉及到很多操作系统的东西.于 ...

  5. 磨刀不误砍柴工 ——《自己动手写操作系统》入门导引

    磨刀不误砍柴工 刺猬@http://blog.csdn.net/littlehedgehog <自己动手写操作系统>其实阅读所需要的前提不过只是C和汇编了,里面涉及到很多操作系统的东西.于 ...

  6. 自己动手写操作系统--个人实践

    近期開始看于渊的<自己动手写操作系统>这本书,刚開始看就发现做系统的引导盘居然是软盘!心里那个汗啊! 如今都是U盘了,谁还用软盘.于是考虑用U盘. 于是開始下面步骤: 1.既然书上说给先要 ...

  7. 自己动手写java虚拟机_自己动手写操作系统(要了解的知识点)

    自己动手写操作系统(开篇) 自己动手写操作系统(字符显示) 说明:Intel 8086 或者不同的处理器,开机寄存器数据可能不一样,但是大致原理差不多 了解过计算机启动的同学肯定知道,当计算机启动的时 ...

  8. 《自己动手写操作系统》读书笔记——初识保护模式

    <自己动手写操作系统>读书笔记--初识保护模式 http://www.cnblogs.com/pang123hui/archive/2010/11/27/2309930.html 书本第三 ...

  9. 自己动手写操作系统0

    文章目录 自己动手写操作系统0 环境搭建 NASM VirtualBox 添加软盘启动 VMware 开启虚拟机 其他软件 Floppy 自己动手写操作系统0 参考余渊老师写的<自己动手写操作系 ...

  10. 自己动手写操作系统之环境构建篇

    自己动手写操作系统之环境构建篇 最近开始看自己动手写操作系统,但是书中采用软盘启动很是郁闷,于是想是否可以从优盘启动呢?作为一名BIOS工程师,曾经用优盘启动过dos,linux等系统,于是做了如下尝 ...

最新文章

  1. java+hadoop配置参数_将Hadoop参数传递给Java代码
  2. 基于JAVA+SpringMVC+Mybatis+MYSQL的旅游景点门票售票管理系统
  3. 防火墙技术之--状态防火墙ASPF(2)
  4. 一步一步安装服务器监视软件MRTG
  5. caffe 使用自带的_net.py绘制网络图问题
  6. 数据挖掘 自习笔记 第三章 定性归纳实践(下)
  7. HTML5 新属性的讲解
  8. python 字符编码识别及转换
  9. 华为机试 - 数字涂色
  10. html短信验证登录
  11. 多台电脑共享上网的方法:在Windows XP中设置Internet连接共享
  12. 搭建Janus的HTTPS环境
  13. 开源动物园一日游!技术圈的这些“飞禽走兽”你认识多少?
  14. 通过okHttpUtils实现文件的上传下载
  15. Swagger 3.0
  16. 采集规则七:河溪小说网 www.518cqdl.com 适用于-易读系统小说站河溪小说网的采集规则
  17. 智能家居中的软件测试,智能家居测试思路
  18. [附源码]Java计算机毕业设计SSM电子工厂进销存管理系统
  19. navicat导出数据库表结构及数据
  20. python-类的继承和多态-继承父类方法和属性的多种方法-继承多个类,继承顺序的研究

热门文章

  1. 统计学习基础(ESL)中文版
  2. linux中ps-p,linux下ps命令
  3. dev万能头文件_Dev c++ 支持bits/stdc++.h万能头文件吗
  4. python 英语翻译 excel_Excel自动翻译
  5. win7系统补丁安装流程
  6. oracle查询undo表空间使用率,检查Undo表空间使用情况
  7. 关于DNF的多媒体包NPK文件的那些事儿(5)- IMG文件里的指向型索引项(指向帧)的深度与有向环检测
  8. Gaussian 安装
  9. 最近开发的NFC读写器控制软件
  10. 计算机开关机命令,电脑自动关机命令