第08章上 makefile
Posted perfy576
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第08章上 makefile相关的知识,希望对你有一定的参考价值。
通常一个大型程序有多个程序模块文件构成,按照功能划分,模块文件分布在不同的目录中,模块文件之间需要包含头文件,函数调用的情况,它们之间存在依赖关系。通常情况下,我么你编写程序只是修改了某些文件,并不是更新所有的文件,因此只需要重新编译修改过的文件然后进行连接就可以了。
通过make工具来实现只编译改动过的文件,而文件之间的编译规则和依赖关系定义在一个命名为makefile文件中。
make程序的工作原理:
linux中,文件分为属性和数据两部分 ,每个文件有三中时间,分别记录与文件属性和文件数据相关的时间:
- atime,access time表示访问文件数据部分的时间,每次读取文件都会更新改时间,cat等,但是ls不改变
- ctime,change time,表示文件属性或是数据改变的时间,当文件属性或是数据被修改时,就会更新ctime
- mtime,modify time,表示文件数据部分被修改的时间,每次修改数据都会更新此时间
make程序粉笔获取以来文件和目标文件的mtime,对比以来文件的的mtime是否新于目标文件,当新的时候,则需要重新编译目标文件。
1 makefile基本语法
1.1 基本语法
基本语法为:
目标文件:以来文件
[tab]命令
目标文件是最终要生成的文件,可以是以.o
结尾的目标文件,也可以是可执行文件,也可以是伪目标文件。
依赖文件主要是指申城此规则中的目标文件,需要那些文件。
命令是值此规则中要执行的动作,这些动作是指各种shell命令。
1.2 命令
test1.o:test.c
gcc -c -o test1.o test.c
test2.o:test.c test1.o
gcc -c -o test2.o test2.c test1.o
test2.out:test1.o test2.o
gcc -o test2.out test1.o test2.o
也就是说,最终的编译指令还是需要我们来编写的。
1.3 伪目标
伪目标不产生真是的目标文件,只定义了规则。因此不存在以来文件。伪目标文件纯粹的执行命令,只要给make指定改为目标名作参数,就能让为目标名的中命令直接执行。
伪目标名不能与真是文件名同名。但是当同名的时候可以通过.PHONY:伪目标名
来定义一个伪目标
.PHONY:clean
clean:
rm ./build/*.o
常用的伪目标名有:
- all,所有需要最终生成的文件都在这里,如果要最终生成多个,那么就在这里定义。
- cleam,清空辨已完成的所有目标文件
- dist,将打包后的tar文件,在压缩
- install,将编译好的程序复制到安装目录下
- printf,打印已经发生改变的文件
- tar,将文件大宝
- test,测试makefile流程
makeflie中的目标,是以递归的方式逐层向上查找目标的。
1.4 变量
makefile中可以定义变量
变量的定义格式为:变量名=值 ,值是一个字符串,多个值之间用空格分开,值已经被当做字符串处理,所以不需要加引号
使用变量的时候:$(变量名)
make定义了一些系统级的变量:
变量名 | 描述 |
---|---|
AR | 打包程序,默认ar |
AS | 汇编语言编译器 |
CC | C语言编译器,默认cc |
CXX | C++语言编译其,默认g++ |
RM | 删除命令,默认rm -f |
一些参数类型的变量:
变量名 | 描述 |
---|---|
ARFLAGS | 打包程序AR的参数 |
ASFLAGS | 汇编编译其的参数 |
CFLAGS | C语言编译器参数 |
CXXFLAGS | c++编译器参数 |
CPPFLAGS | C预处理器参数 |
LDFLAGS | 链接器参数 |
1.5 隐含规则
注释使用#
1.6 自动化变量
自动化变量,代表一组文件名。此变量值是这组文件名的一个子集,自动化变量相当于对文件名集合循环遍历一遍。
其含义其实是,在项规则中,下面的这些变量分别指代一些文件。
[email protected]
,表示规则中的目标文件名的集合,如果有多个目标文件,[email protected]
表示其中的每一个文件名- $<,表示规则中以来文件的第一个文件
- $^,表示规则中所有依赖文件的集合。自动去重
- $?,表示规则中比目标文件新的以来文件的集合。
通常的用法是:
test.o:test1.c
$(CC) -o [email protected] $^
1.7 模糊规则
%用来匹配任意多个非空字符,比如,g%.o
表示以g
开头,.o
结尾的文件。make,会在当前目录下使用该规则匹配所有文件:
test.o:%.c
$(CC) -o [email protected] $^
2 代码
我们是用make代替start.h
在根目录下创建一个makefile
文件,然后创建build
文件夹,注意,make并不能自动的去创建文件夹.
然后在该目录下使用make
命令,完成编译和刻录.紧接着手动执行bochs
BUILD_DIR=./build
AS=nasm
NASM_ELF=-f elf
INCLUDE=-I./lib -I ./lib/kernel
ASINCLUDE=-I./boot/include/
CFLAGS=-m32
LDFLAGS=-Ttext 0xc0001500 -m elf_i386 -e main
CC=gcc
# 注意这里: $(BUILD_DIR)/kernel.o 一定要放在第一个上,因此,这个变量是为连接器准备的.如果不放在第一项,保证错
OBJ=$(BUILD_DIR)/kernel.o $(BUILD_DIR)/print.o $(BUILD_DIR)/idt.o $(BUILD_DIR)/interrupt.o $(BUILD_DIR)/init.o
# 最终要生成的文件,
all: $(BUILD_DIR)/kernel.bin $(BUILD_DIR)/loader.bin $(BUILD_DIR)/mbr.bin
# 编译 并刻录 loader.bin
$(BUILD_DIR)/loader.bin: ./boot/loader.asm
$(AS) -o [email protected] $^ $(ASINCLUDE)
dd if=$(BUILD_DIR)/loader.bin of=./hd60m.img bs=512 count=4 seek=2 conv=notrunc
# 编译 并刻录 mbr.bin
$(BUILD_DIR)/mbr.bin: ./boot/mbr.asm
$(AS) -o [email protected] $^ $(ASINCLUDE)
dd if=$(BUILD_DIR)/mbr.bin of=./hd60m.img bs=512 count=1 conv=notrunc
# 编译 print.asm
$(BUILD_DIR)/print.o:./lib/kernel/print.asm
$(AS) $(NASM_ELF) -o [email protected] $^ $(ASINCLUDE)
# 编译 idt.asm
$(BUILD_DIR)/idt.o:./kernel/idt.asm
$(AS) $(NASM_ELF) -o [email protected] $^ $(ASINCLUDE)
# 编译 interrupt.c
$(BUILD_DIR)/interrupt.o:./kernel/interrupt.c
$(CC) -o [email protected] $(CFLAGS) -fno-stack-protector -c $^ $(INCLUDE)
# 编译 init.c
$(BUILD_DIR)/init.o:./kernel/init.c
$(CC) -o [email protected] $(CFLAGS) -c $^ $(INCLUDE)
# 编译 main.c
$(BUILD_DIR)/kernel.o:./kernel/main.c
$(CC) -o [email protected] $(CFLAGS) -c $^ $(INCLUDE)
# 最终链接
$(BUILD_DIR)/kernel.bin:$(OBJ)
$(LD) -Ttext 0xc0001500 -m elf_i386 -e main -o ./build/kernel.bin $(OBJ)
dd if=./build/kernel.bin of=./hd60m.img bs=512 count=40 seek=9 conv=notrunc
clean:
rm -rf ./build/*
以上是关于第08章上 makefile的主要内容,如果未能解决你的问题,请参考以下文章