Makefile的使用
Makefile的基本使用:
Makefile文件格式如下:
# 放在第一个的是默认目标
# 目标是编译出main文件,依赖hello.o和main.o
# 编译的命令是gcc -o main hello.o main.o
main:hello.o main.ogcc hello.o main.o -o main# 目标是编译出main.o文件,依赖main.c
# 编译的命令是gcc -c main.c -o main.o/或gcc -c main.c 它会自动识别到名字并转换成main.o
main.o:main.cgcc -c main.c -o main.o# 目标是编译出hello.o文件,依赖hello.c
# 编译的命令是gcc -c hello.c -o hello.o/或gcc -c hello.c 它会自动识别到名字并转换成hello.o
hello.o:hello.cgcc -c hello.c -o hello.o
使用方法:
itcai@LAPTOP-AKHDRHHE:~/helloworld$ make
gcc -c hello.c -o hello.o
gcc -c main.c -o main.o
gcc -o main hello.o main.o
执行make命令之后,会把Makefile文件命令从下往上执行
clean命令的使用:
clean使用格式如下:
# Makefile的内容通常由以下3部分组成
# <目标名称>:<前置依赖>
# <TAB键><需要执行的命令># 放在第一个的是默认目标
# 目标是编译出main文件,依赖hello.o和main.o
# 编译的命令是gcc -o main hello.o main.o
main:hello.o main.ogcc hello.o main.o -o main# 目标是编译出main.o文件,依赖main.c
# 编译的命令是gcc -c main.c -o main.o/或gcc -c main.c 它会自动识别到名字并转换成main.o
main.o:main.cgcc -c main.c -o main.o# 目标是编译出hello.o文件,依赖hello.c
# 编译的命令是gcc -c hello.c -o hello.o/或gcc -c hello.c 它会自动识别到名字并转换成hello.o
hello.o:hello.cgcc -c hello.c -o hello.o
# 清除不需要的文件
clean:rm main.o hello.o
使用方法:
itcai@LAPTOP-AKHDRHHE:~/helloworld$ make clean
rm main.o hello.o
Makefile_引入变量
格式如下:
# Makefile的内容通常由以下3部分组成
# <目标名称>:<前置依赖>
# <TAB键><需要执行的命令># 定义变量 itcai
# 变量的值是 main.o hello.o 定义也可写为itcai := main.o hello.o
# 也可以写成多行的形式,在每一行的结尾加上反斜杠\
# 反斜杠\表示当前行未结束,下一行是当前行的延续
# 变量的引用方式是$(itcai)
itcai := main.o\hello.o# 放在第一个的是默认目标
# 目标是编译出main文件,依赖$(itcai)
# 编译的命令是gcc $(itcai) -o main
main:$(itcai)gcc $(itcai) -o main# 目标是编译出main.o文件,依赖main.c
# 编译的命令是gcc -c main.c -o main.o/或gcc -c main.c 它会自动识别到名字并转换成main.o
main.o:main.cgcc -c main.c -o main.o# 目标是编译出hello.o文件,依赖hello.c
# 编译的命令是gcc -c hello.c -o hello.o/或gcc -c hello.c 它会自动识别到名字并转换成hello.o
hello.o:hello.cgcc -c hello.c -o hello.o
# 清除不需要的文件
clean:rm $(itcai)
Makefile_自动推导
# 告诉 make:最终目标是 main,不能省略
main : main.o hello.o# 下面什么都不用写,make 会:
# 1) 自动推导 main.o <- main.c
# 2) 自动推导 hello.o <- hello.c
# 3) 自动链接 main <- main.o hello.o
# 故可省略
但其自动推导不出hello.h,故,hello.h仍需显式标明依赖,否则.h文件发生变化make不会察觉
可改为如下版本:
# Makefile的内容通常由以下3部分组成
# <目标名称>:<前置依赖>
# <TAB键><需要执行的命令># 定义变量 itcai
# 变量的值是 main.o hello.o 定义也可写为itcai := main.o hello.o
# 也可以写成多行的形式,在每一行的结尾加上反斜杠\
# 反斜杠\表示当前行未结束,下一行是当前行的延续
# 变量的引用方式是$(itcai)
itcai := main.o\hello.o# 放在第一个的是默认目标
# 目标是编译出main文件,依赖$(itcai)
# 编译的命令是gcc $(itcai) -o main
main:$(itcai)gcc $(itcai) -o main# 目标是编译出main.o文件,依赖hello.h,其他的依赖文件它会自动推导
main.o:hello.h# 目标是编译出hello.o文件,依赖hello.h,其他的依赖文件它会自动推导
hello.o:hello.h# 清除不需要的文件
clean:rm $(itcai)
Makefile_伪目标
作用: 防止目标名与同名文件冲突,并告诉 make“无论文件是否存在,每次都要执行”
# 声明伪目标 clean
.PHONY:cleanclean:rm main.o hello.o
若不显式声明伪目标,当所在路径中有与伪目标同名的文件时,伪目标命令就不会执行
.PHONY: clean 告诉 make:
“clean 不是一个文件名,请每次都执行它下面的命令。”
.PHONY
不是必须,但强烈推荐:防止文件夹里恰好出现同名文件导致规则失效
伪目标可以自定义
# 自定义伪目标
.PHONY: clean run qemu gdbclean:@echo "删除中间文件..."rm -f *.o *.korun:qemu-system-x86_64 -enable-kvm -m 2G -kernel mykernel.elfgdb:qemu-system-x86_64 -s -S -kernel mykernel.elf &gdb vmlinux -ex "target remote :1234"
名称随意:clean、run、qemu、gdb
都可以,完全自定义
Makefile_忽略错误
当连续执行同一条命令时,因为命令已经执行过一次且所操作文件没有改变,所以会报错
itcai@LAPTOP-AKHDRHHE:~/helloworld$ make clean
rm main.o hello.o
itcai@LAPTOP-AKHDRHHE:~/helloworld$ make clean
rm main.o hello.o
rm: cannot remove 'main.o': No such file or directory
rm: cannot remove 'hello.o': No such file or directory
make: *** [Makefile:22: clean] Error 1
可通过在要忽略此类错误的命令前加 -
来忽略该错误
如:
# 声明伪目标 clean
.PHONY:cleanclean:-rm main.o hello.o
再次连续执行该命令,结果如下:
itcai@LAPTOP-AKHDRHHE:~/helloworld$ make clean
rm main.o hello.o
itcai@LAPTOP-AKHDRHHE:~/helloworld$ make clean
rm main.o hello.o
rm: cannot remove 'main.o': No such file or directory
rm: cannot remove 'hello.o': No such file or directory
make: *** [Makefile:22: clean] Error 1
itcai@LAPTOP-AKHDRHHE:~/helloworld$ make clean
rm main.o hello.o
rm: cannot remove 'main.o': No such file or directory
rm: cannot remove 'hello.o': No such file or directory
make: [Makefile:24: clean] Error 1 (ignored)
在报错后会显示(已忽略)
Makefile_名称对应
目标名称必须和gcc命令生成的目标文件同名,即名称对应
若不对应,如下所示:
# Makefile的内容通常由以下3部分组成
# <目标名称>:<前置依赖>
# <TAB键><需要执行的命令># 放在第一个的是默认目标
# 目标是编译出main文件,依赖hello.o和main.o
# 编译的命令是gcc hello.o main.o -o main123
main:hello.o main.ogcc hello.o main.o -o main123
则连续执行同一条命令而不会报错
itcai@LAPTOP-AKHDRHHE:~/helloworld$ make
cc -c -o hello.o hello.c
cc -c -o main.o main.c
gcc hello.o main.o -o main123
itcai@LAPTOP-AKHDRHHE:~/helloworld$ make
gcc hello.o main.o -o main123
itcai@LAPTOP-AKHDRHHE:~/helloworld$ make
gcc hello.o main.o -o main123
原因:目标名称是追踪监控的目标,而gcc命令的生成目标是所生成文件的名字,当追踪不到追踪监控的目标时会一直执行后续的gcc命令
fopen_test: fopen_test.c
# 定义变量CC为gcc
CC := gcc
# $@ 指目标文件
# $^ 指依赖文件
# gcc -o fopen_test fopen_test.c-$(CC) -o $@ $^
#./fopen_test-./$@
#rm ./fopen_test-rm ./$@