Linux 是所有嵌入式软件工程师绕不过去的坎,
makefile 是在Linux系统中绕不过去的坎。
花了几天时间初步学习和了解了makefile 的作用以及功能,并且制作了一个通用型的makefile 用于管理后续可能的在Linux上独立开发的项目。
在此用笔记的方式记下。怕自己以后忘了。
makefile 思想: makefile 核心公式
<target_file> : <source_file>
command....
如果目标文件不存在或者 源文件中有 比目标文件修改日期还要新的,那么执行command 命令 ;
command命令的功能使用来更新生成目标文件
同时上一个 公式中的 源文件 又可以嵌套成为下一个公式的 目标文件。周而复始。
上述公式中,如果目标文件和源文件都是最新的,那么command命令就不会被执行。这样在很多大型项目中,会被更新的就只有修改了的文件和最终的输出文件大幅的降低的编译的时间。
同时makefile中支持丰富的逻辑、变换等。深入研究完全可以作为一门新的编程语言进行开发。
以下分享自己借助网络大牛的力量优化编写的一个makefile文件。
此makefile放置在项目的根目录下。
例如:Pro文件夹中有 Inc、Res、Img文件夹;
里面有 头文件、源码文件、图片文件、项目文件等;
所有关于Pro项目的文件都在Pro文件下,makefile文件应该被放置在Pro文件夹中
注意事项:获取绝对路径功能只适用于 GUN编译器
功能: 会将Pro文件中所有的*.c *.h 文件视为一个项目,整体编译、链接;
递归扫描各文件夹
只编译未编译的文件或者更新后与其相关的文件
clean命令 删除所有makefile会生成的文件
cleanO命令(大写字母 O) 删除除可执行文件外,makefile生成的文件。
des命令 打印当前项目中的绝对路径以及 所有源文件的绝对路径。
1 #此项目源文件后缀类型 2 PROJECTTYPE = .c 3 4 #您想要生成可执行文件的名字 5 BinName :=obj.out 6 7 8 #获取当前makefile绝对路径 9 pes_parent_dir:=$(shell pwd)/$(lastword $(MAKEFILE_LIST)) 10 pes_parent_dir:=$(shell dirname $(pes_parent_dir)) 11 12 #首先跳转到makefile目录下,然后获取该目录下所有子目录 13 AllDirs := $(shell cd $(pes_parent_dir); ls -R | grep '^\./.*:$$' | awk '{gsub(":","");print}') . 14 15 #添加成为绝对路径 16 AllDirs := $(foreach n,$(AllDirs),$(subst .,$(pes_parent_dir),$(n))) 17 18 #获取所有 .c/.cpp文件路径 19 Sources := $(foreach n,$(AllDirs) , $(wildcard $(n)/*$(PROJECTTYPE))) 20 21 #处理得到*.o 后缀文件名 22 OBJS = $(patsubst %$(PROJECTTYPE),%.o, $(Sources)) 23 24 #同理得到 *.d文件名 25 Deps := $(patsubst %$(PROJECTTYPE),%.d, $(Sources)) 26 27 #需要用到的第三方静态库 28 StaticLib := 29 30 #需要用到的第三方动态链接库 31 DynamicLib := 32 33 #真实二进制文件输出路径(绝对) 34 Bin :=$(pes_parent_dir)/$(BinName) 35 36 #C语言编译器 37 CC = gcc 38 39 #C++编译器 40 CXX = g++ 41 42 #简化rm -f 43 RM = -rm -f 44 45 #C语言配置参数 46 CFLAGS = -g -pedantic -std=c99 -Wall -o 47 48 #C++配置参数 49 CXXFLAGS = -g -Wall -std=c11 50 51 #头文件搜索路径 52 INCLUDE_PATH = $(foreach n,$(AllDirs) , -I$(n)) 53 54 55 LDFLAGS = 56 57 #指定AllLibs为终极目标 即:最新的Bin 58 AllLibs:$(Bin) 59 60 #声明这个标签 des 用于观察当前的路径是否正确 61 .PHONY:des 62 des: 63 @echo OBJS = $(OBJS) 64 @echo cur_makefile_path = $(pes_parent_dir) 65 @echo AllDirs = $(AllDirs) 66 @echo Sources = $(Sources) 67 @echo Deps = $(Deps) 68 69 #对应关系 在本makefile中以空格隔开的后缀为.c 都会为其生成一个新的.d文件 意图为更新所有*.c文件的include依赖关系 70 %.d : %.c 71 @echo 'finding $< depending head file' 72 @$(CC) -MT"$(<:.c=.o) $@" -MM $(INCLUDE_PATH) $(CPPFLAGS) $< > $@ 73 74 #对于include中的*.d文件,只要里面任意有一个文件被修改,那么就会触发此规则生成一个新的*.o文件 75 %.o: %.d 76 @echo compile $(<:d=c) 77 @$(CC) -c $(<:.d=.c) $(INCLUDE_PATH) $(CFLAGS) $@ 78 79 sinclude $(Sources:.c=.d) 80 81 $(Bin) : $(OBJS) 82 @echo bulding.... 83 @$(CC) $(OBJS) $(CFLAGS) $(Bin) 84 @echo created file: $(BinName) 85 86 .PHONY : clean 87 clean: 88 @echo '清理所有文件' 89 @$(RM) $(OBJS) $(Deps) $(Bin) 90 91 .PHONY : cleanO 92 cleanO: 93 @echo '清理Obj && Dep' 94 @$(RM) $(OBJS) $(Deps) 95 # ######################################################################### 96 # 单独的 < 符号代表 依存源文件(即冒号: 的左边) $< 代表将源文件展开成为字符 97 # 单独的 @ 符号代表 目标文件 (冒号 : 的右边) $@ 代表将目标文件名称展开成为字符 98 # 符号 @ 后接命令则表示:此语句执行,但并不现实 99 # 例如:@$(CC) $(OBJS) $(CFLAGS) $(Bin) 100 # 只执行链接命令,但是不将此字符串打印至终端 101 # 关键字:@echo 表示该行后的命令只显示 不执行。 102 # 注意:虽然只显示,但是他依旧会以执行命令的要求的解析文本, 103 # 只是不执行而已,如果需要输出字符串使用‘ ’将内容引用即可 104 # 重点符号 $ : 表示转义,在makefile中无论在哪里都会被识别为转义字符, 105 # 如果想表示 $符号,那么需要使用 $$ 106 # 例如:@echo ‘$$$$’ 终端将会输入 : "$$" 107 # 其余makefile 知识参考 《跟我一起写 MakeFile》 ----陈皓 108 # ######################################################################### 109