#create on Oct25,2013
#CC := gcc
CC := arm-hisiv100nptl-linux-gcc
LINK := arm-hisiv100nptl-linux-g++
SRC_DIR := .
INC_DIR := .
TARGET := XiaobanRecorder
NFSPATH := /home/chenmin/nfs_share
INC := $(shell find $(INC_DIR) -name '*.h')
INCDIR := $(dir $(INC))
INCDIR := $(sort $(INCDIR))
INC := $(foreach dir,$(INCDIR),-I$(dir))
SRC := $(shell find $(SRC_DIR) -name '*.c')
SUBDIR := $(dir $(SRC))
SRCXX := $(shell find $(SRC_DIR) -name '*.cpp')
SUBDIR += $(dir $(SRCXX))
SUBDIR := $(sort $(SUBDIR))
OBJS_DIR := obj
EXE_PATH := bin
#$(patsubst %.c,%.o,$(SRC))”
OBJS := $(SRC:$(SRC_DIR)/%c=$(OBJS_DIR)/%o)
OBJSXX := $(SRCXX:$(SRC_DIR)/%cpp=$(OBJS_DIR)/%o)
DEPS := $(SRC:$(SRC_DIR)/%c=$(OBJS_DIR)/%d)
DEPSXX := $(SRCXX:$(SRC_DIR)/%cpp=$(OBJS_DIR)/%d)
NEWDIR := $(OBJS_DIR)
NEWDIR += $(SUBDIR:$(SRC_DIR)/%=$(OBJS_DIR)/%) #sub obj path
NEWDIR += $(EXE_PATH)
NEWDIR := $(sort $(NEWDIR))
CreateDir = $(shell [ -d $1 ] || mkdir -p $1 || echo ":mkdir '$1' fail")
RemoveDir = $(shell [ -d $1 ] && rm -rf $1 && echo -e "rmdir '$1'\t [ OK ]" || echo ":rm dir '$1' fail")
InitMake :=
creatsubdir := $(foreach dir,$(NEWDIR),InitMake = $(call CreateDir,$(dir)))
ifneq ($(strip InitMake),)
err = $(error $(InitMake))
endif
LIB := -lpthread -L./sqlite/lib/ -lsqlite3
EXEBIN = $(EXE_PATH)/$(TARGET)
COMPILEDEP = $(CC) -MM $< $(INC)
all:compiled_objs
@echo "############## compile success ###########"
@cp $(EXEBIN) $(NFSPATH)
@echo "copy executable bin file to nfs"
clean:
$(shell [ -d ./obj ] && rm ./obj/* -rf)
@echo "do the cleaning"
compiled_objs : $(OBJS) $(OBJSXX)
$(LINK) -o $(EXEBIN) $(OBJS) $(OBJSXX) $(LIB)
CFG := -c
$(OBJS) : $(OBJS_DIR)/%o : $(SRC_DIR)/%c
@echo "######$(NEWDIR)###########compile $< to obj file##########"
$(CC) $(CFG) $< -o $@ $(INC)
$(OBJSXX): $(OBJS_DIR)/%o:$(SRC_DIR)/%cpp
@echo "#######compile $<########"
$(CC) $(CFG) $< -o $@ $(INC)
$(DEPS) : $(OBJS_DIR)/%d : $(SRC_DIR)/%c
@echo "#################making dependence file ###########"
@set -e;$(COMPILEDEP) > $@.$$$$; \
sed 's,.*\.o[ :]*,$(@:%.d=%.o) $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
$(DEPSXX):$(OBJS_DIR)/%d:$(SRC_DIR)/%cpp
@echo "######making cpp dependce file######"
@set -e;$(COMPILEDEP) >$@.$$$$; \
sed 's,.*\.o[ :]*,$(@:%.d=%.o) $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
-include $(DEPS)
-include $(DEPSXX)
关于,sed,看下面,
其实这里主要是为每个C文件建立一个同名的后缀为.d。该文件的作用是使用gcc的-M属性来自动生成.o文件的头文件依赖关系。
1 %.d: %.c
2 $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
3 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
4 rm -f $@.$$$$
第1,2,4都好理解。
第2行解释: 使用gcc -M 的属性将 $<(第1行的第一个依赖文件,就是%.c。 查看静态模式)的C文件的依赖关系输出到一个临时文件。 这里有点疑惑。 书里面说 .$$$$是当前进程好。 然到Makefile这个脚本将$$$$当成进程号了。姑且这么认为吧。
第4行解释:将第2行产生的临时文件删除。
对于第3行, 我知道sed的s命令是一个替换命令。但是里面的用到了太多高深的匹配规则了。
首先,我们先要知道sed是什么概念。
sed是一个非交互式的流编辑器。所谓非交互式,是指使用sed只能在命令行下输入编辑命令来编辑文本,然后在屏幕上查看输出;而流编辑器是指sed每次只从文件(或输入)读入一行,然后对该行进行指定的处理,并将结果输出到屏幕,接着读入下一行。
为了简化的阐述,下面将静态模式用一个特例代替---main.c 。 通过第2行,针对main.c编译器生成了如下的依赖关系:
main.o:main.c defs.h
而通过第三行将会被替换成main.o:main.d:main.c defs.h, 并且把这个依赖关系输出到文件main.d中。
OK,大致知道了它的意思,接下在,就细细的分析第三行命令的整个执行过程,如下:
1:将($@.$$$$)的临时文件中的字符串信息(main.o:main.c defs.h)通过 “<” 输送到sed命令中.
2:sed中的s符号告诉sed命令,这次要做一个替换的任务。s符号的格式为:[address[,address]] s/pattern-to-find/replacement-pattern/[g p w n]。 下面来匹配上面的示例:
[address[,address]]:是指要处理的行的范围,在这次的操作中采用的是默认值。
pattern-to-find等价于\($*\)\.o[ :]*
replacement-pattern等价于\1.o $@ :
3:Makefile使用%=main进行替换后,命令变成了sed 's,\(main\)\.o[ :]*,\1.o main.d : ,g' < main.pid > main.d ;
接下来就比较好分析了,主要是正则表达式的知识了。 pattern-to-find使用到了4个正则表示式的知识点。
first, \(main\)为创建一个字符标签,给后边的replacement-pattern使用。如\1.o,展开后就是main.o
second, \. 在正则表达式中‘.’作用是匹配一个字符。所以需要使用转义元字符‘\’来转义。
third, [ :] 匹配一组字符里的任意字符 。
forth, *匹配0个或多个前一字符
4 : 通过sed的正则表达式,输入的main.o:main.c defs.h被替换成了main.o main.d : main.c defs.h