#Makefile小入门
要在Linux环境写自己的程序就需要自己写Makefile,远不如windows下各种IDE来的方便。
那就尝试写一个不要太麻烦的Makefile完成整个编译任务。
写makefile就像做菜一样,形式如下:
配方:材料 | 前置配方:
制作步骤1
制作步骤2
。。。
思路是这样的,如果是移植的软件包,放在一个目录下,例如littlevgl,自己码的程序放在另一个目录下,分开放。
先 arm-linux-gnueabihf-gcc -c -o ???.o ???.c ,进行 .c 编译成 .o 文件,按指定目录存放起来 ;
再 arm-linux-gnueabihf-gcc -o APP *.o ,把.o文件链接成执行文件。
按目录编写对应的makefile 规则:
举个例子:
列出需要的变量
LVGL_INC_DIR := #用来存放头文件的全路径
LVGL_SRC_DIR := #用来存放主目录的路径
LVGL_SRC_SUBDIRS := #用来存放源文件目录的路径
LVGL_CFILES := #用来存放源文件的文件名
LVGL_CFILES_PATH := #用来存放源文件的全路径
#LVGL_OBJS := #用来存放编译后的.o文件名
#LVGL_OBJS_PATH:= #用来存放编译后的.o文件全路径
LVGL_OUTPUTDIR := #设定输出文件的目录
LVGL_LIB_NAME := #设定输出库文件名
初始化变量:
这部分都需要手工填写的:
LVGL_LIB_NAME = lvgl_lib.a
LVGL_OUTPUTDIR = ./$(OUTPUTDIR)/LVGL_OUT
LVGL_SRC_DIR = ./lvgl/src
LVGL_SRC_SUBDIRS += $(LVGL_SRC_DIR)
LVGL_SRC_SUBDIRS += $(foreach dir, $(shell ls -l $(LVGL_SRC_DIR) | grep ^d | awk '{print $$9}'), $(LVGL_SRC_DIR)/$(dir))
接下来的是自动处理的配方:
先是扫描所有的C文件,用到了makefile 的 $(foreach ) $(shell ) ,shell 命令的 ls 、awk 、 grep,及管道 :
#C文件名
LVGL_CFILES += $(foreach dir ,$(LVGL_SRC_SUBDIRS) , \
$(foreach cfile ,$(shell ls -l $(dir)|awk '{print $$9}'|grep "\.c$$" ), $(cfile)) \
)
#C文件全路径
LVGL_CFILES_PATH = $(foreach dir ,$(LVGL_SRC_SUBDIRS) , \
$(foreach cfile ,$(shell ls -l $(dir)| awk '{print $$9}'|grep "\.c$$" ), $(dir)/$(cfile)) \
)
处理头文件路径,在路径前添加 -I :
#头文件路径
LVGL_INC_DIR = $(foreach dir , $(LVGL_SRC_SUBDIRS) , -I $(dir))
LVGL_INC_DIR += -I ./lvgl
输出路径,用到了shell命令的 mkdir :
#新建输出路径
$(LVGL_OUTPUTDIR):
mkdir $(LVGL_OUTPUTDIR)
制作.o文件,一个.c文件对应一个.o文件,对应输出目录不存在.o文件或者.c文件修改日期大于.o文件,则重新制作.o文件;用到了 shell 的 if 、 for 、 stat 、xargs等:
#制作.o文件
LVGL_OBJ_MAKE:$(LVGL_CFILES) $(LVGL_OUTPUTDIR)
for s in `echo $(LVGL_CFILES_PATH)|cut -d' ' -f 1-`; do\
if [ ! -f `echo $$s|awk '{gsub(/\//," ")}{print $$NF}'|awk '{gsub(/.c/,"")}{printf"%s/%s.o","$(LVGL_OUTPUTDIR)",$$0}'` ] \
|| [ `stat -c %Y $$s` -gt `echo $$s|awk '{gsub(/\//," ")}{print $$NF}'|awk '{gsub(/.c/,"")}{printf"%s/%s.o\n","$(LVGL_OUTPUTDIR)",$$0}'|xargs stat -c %Y` ] \
;then \
echo "\033[36m process $$s; \033[0m" \
#rm -f $(LVGL_OUTPUTDIR)/`echo $$s|awk '{gsub(/\//," ")}{print $$NF}'|awk '{gsub(/.c/,"")}{print $$0}'`.o ;\
$(CC) $(CFLAGS) $(LVGL_INC_DIR) -c -o $(LVGL_OUTPUTDIR)/`echo $$s|awk '{gsub(/\//," ")}{print $$NF}'|awk '{gsub(/.c/,"")}{print $$0}'`.o $$s ; \
fi \
done
.o文件名及路径处理 ,makefile 中 配方前置条件 “ 配方:材料 | 前置配方 ” :
#.o文件名
LVGL_OBJS = $(LVGL_CFILES:.c=.o)
LVGL_OBJS_PATH =$(foreach f , $(shell ls -l $(LVGL_OUTPUTDIR) |awk '{print $$9}'|grep "\.o$$" ) ,$(LVGL_OUTPUTDIR)/$(f))
$(LVGL_OBJS_PATH):|LVGL_OBJ_MAKE
#制作 .a库文件
$(LVGL_LIB_NAME):
ar rcs $(LVGL_LIB_NAME) `ls -l $(LVGL_OUTPUTDIR)|grep ".o$$"|awk '{printf"%s/%s ","$(LVGL_OUTPUTDIR)",$$9}'`
还需要一个清除的配方 ,使用shell 的 rm :
LVGL_LIB_CLEAN:
rm -r $(LVGL_OUTPUTDIR)
每个目录按法泡制 ,在最后:
X : | APP_OBJ_MAKE LVGL_OBJ_MAKE
$(CC) $(LDFLAGS) -o lvglapp $(APP_OBJS_PATH) $(LVGL_OBJS_PATH)
rm -f *.o
执行 make X ,搞定。