日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

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

發布時間:2023/12/10 windows 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 全面剖析《自己动手写操作系统》第五章---makefile文件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載請標注:?

全面剖析《自己動手寫操作系統》第五章---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文件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。