makefile通用设计模板附详细解释

之前的项目今天出了点问题,编译的时候也出了点问题,需要看一下makefiel,但是之前写的makefile已经忘记了,所以今天将此makefile总结一下,避免下次忘记。

注:此mafile非常通用。

上次总结的makefile可以查看点击打开链接

#################################################################################################
# 规则文件
#################################################################################################
CURRENT_DIR_FILE := $(shell find . -maxdepth 1 -name '*.c' 2>/dev/null)
#$(shell )是指makefile中的shell函数,参数为find . -maxdepth 1 -name '*.c' 2>/dev/null,
#该makefile的shell函数作用是执行该shell函数中的参数作为shell命令执行。并将shell命令的结果作为该shell函数的返回值。
#这里执行的shell命令find。.代表当前目录下查找, -maxdepth 1代表查找的目录深度是1,即不向下延时到子目录。若是2则延伸一个子目录。
#-name '*.c'指根据文件名查找,'*.c'是通配符。2>/dev/null,2代表标准出错,>代表输出重定向,
#也就是标准出错重定向到/dev/null,即该命令如果出现错误,那么不显示。因为makefile在执行过程中不希望收到shell命令执行错误信息。
SPACE             =
CURRENT_PREFIX    = ./
#这里定义两个变量,一个是空,啥都没有,一个是./
FILE_NAME         = $(subst $(CURRENT_PREFIX),$(SPACE), $(CURRENT_DIR_FILE))
#这里调用makefile的subst函数,进行字符串的替换,意思是将$(CURRENT_PREFIX)替换成$(SPACE),在$(CURRENT_DIR_FILE)中
#这里做替换的原因是,因为$(CURRENT_DIR_FILE)是shell命令在当前目录下查找到的.c文件,包含前缀./
#我们要生成.o且放在另外的目录下,所以需要将这些文件名单独抽取出来,然后和我们的目标存放的路径相连接,生成我们的含路径的目标文件名。
#所以要将./替换成空(去掉./,才好和路径相连接。)
#思考?我当时为什么不直接将./替换成我们的路径,偏偏要去掉./后,再连接路径?是不是我当时没想到还是啥?具体忘记了。可能是没想到,
#可能还有其他作用。


BUILD_OBJS        = $(addprefix $(CURRENT_BUILD_PATH)/, $(FILE_NAME))
#这里将文件名和前缀路径连接起来


#实验过了,将上面那两行屏蔽掉,仅使用下面这一行代替上面的拆掉./再添加前缀,
#可行,编译能通过,说明应该是当时我在设计的时候大脑太机械化了没考虑到,或许考虑到了但是懒得改。
BUILD_OBJS        = $(subst $(CURRENT_PREFIX),$(CURRENT_BUILD_PATH)/, $(CURRENT_DIR_FILE))


BUILD_OBJS       := $(patsubst %.c,%.o,${BUILD_OBJS})
#这里将连接起来的那些.c替换成.o文件。
BUILD_OBJS_ALL    = $(shell find $(CURRENT_BUILD_PATH) -name '*.o' 2>/dev/null)
#这里找到了目标前缀路径下的所有.o文件
#问题:当还没有编译生成.o存放在目标目录下的时候,这里岂不是为空吗?
TARGET_TAIL_CHAR  = $(findstring .a,$(TARGET))
#匹配目标文件,看是否是要生成库,不是生成库就是生成可执行文件
#查看目标$(TARGET),中是否有.a文件。如果有那就是生成库,否则就是生成可执行文件。
#这里做区分的原因是因为库文件是采用link,而可执行文件是gcc -o 直接生成。
#我们这里统一了,也就是不管是生成库文件,还是可执行文件都统一,所以要区分做处理。


#默认目标,依赖三个目标,
all : DIR  SUB_DIR_MAKE $(BUILD_OBJS) $(TARGET)




DIR :
@mkdir -p $(CURRENT_BUILD_PATH)
#创建一个目标目录 -p选项是没有这个目录就创建。即使存在也不报警告


SUB_DIR_MAKE :
@for i in $(SUB_DIR) ; do\
make -C $$i all || exit $?; \
done
#这里的目的是遍历遍历SUB_DIR中的值,然后进入这些目录执行make all。
#后面的exit $?;不知道什么用,在项目中将它去掉也没影响代码的编译,估计是为了错误退出做处理吧。
#这里的$(SUB_DIR)是makefile里面定义的变量类型,将这条语句复制到ubuntu上直接执行是执行不了的。
#SUB_DIR在其他makefile中定义,定义自己这个目录下的子目录。然后通过include包含我们这个文件,实现编译。


$(BUILD_OBJS):$(CURRENT_BUILD_PATH)/%.o:%.c
@echo Compiling $^
@$(CC)  -DHAVE_CONFIG_H $(CFLAGS) -c `test -f '$<' || echo `$< -o $@
#这里-DHAVE_CONFIG_H表示在编译的时候,定义一个DHAVE_CONFIG_H宏,用来控制条件编译。在具体的代码中没有搜索到,应该是在最原始的代码中起作用。
#$(CFLAGS) 可以定义自己需要加进来的标记,如-I"路径"指明编译的查找路径,-g添加调试选项等。
#-c `test -f '$<' || echo `$< -o $@
#可以分成-c $< -o $@,也就是根据$<(依赖)生成$@(目标)
#中间的上撇号括起来的  `test -f '$<' || echo `不知道啥意思


$(TARGET) : $(BUILD_OBJS_ALL)
@if [ $(TARGET) != "" ]; then \
if [ -z "$(TARGET_TAIL_CHAR)"];then \
rm -f $(TARGET);\
echo $(CC) -g -O2 -o $(TARGET) $(BUILD_OBJS_ALL) $(LIB)  -lrt -lm -lcrypt  -pthread;\
$(CC) -g -O2 -o $(TARGET) $(BUILD_OBJS_ALL) $(LIB) -lrt -lm -lcrypt  -pthread;\
else \
echo $(lib_AR) $(TARGET) $(BUILD_OBJS_ALL);\
$(lib_AR) $(TARGET) $(BUILD_OBJS_ALL);\
ranlib $(TARGET);\
fi \
fi
#这里根据我们定义的目标。有依赖文件$(BUILD_OBJS_ALL),依赖文件在变量定义的时候,在目标文件夹下查找所有的.o。
#这里没有出现问题的原因是因为这个$(TARGET) : $(BUILD_OBJS_ALL) 在 $(BUILD_OBJS):$(CURRENT_BUILD_PATH)/%.o:%.c 之后,
#也就是all : DIR  SUB_DIR_MAKE $(BUILD_OBJS) $(TARGET)这里$(TARGET)在后面,all的时候,会先处理前面的目标,当前面的目标处理完成,
##(TARGET)也就有了依赖的文件。
#首先判断我们有没有目标文件(可执行文件或者.a文件)
#没有的化就不生成目标文件
#有的话,if [ -z "$(TARGET_TAIL_CHAR)"];判断$(TARGET_TAIL_CHAR)是否为空。
#如果为空,也就是前面变量定义的时候没有.a
#即目标文件是可执行文件。
#那么就用$(CC) -g -O2 -o $(TARGET) $(BUILD_OBJS_ALL) $(LIB) -lrt -lm -lcrypt  -pthread;\这条命令,生成目标文件。
#反之:生成的是静态库,那么就得用静态库的链接方式生成目标文件。




#声明clean目标为假目标。避免当前目录下存在clean这样的文件。
#那么当clean的时间戳没有改变小于依赖文件的时候,
#就不hi执行到下面的清除命令。
#下面的清除命令是直接删除掉了这个创建的目录,加上-rf选项,直接将里面的东西全部删除。
.PHONY : clean
clean : SUB_DIR_CLEAN OBJSCLEAN


SUB_DIR_CLEAN :
@for i in $(SUB_DIR) ; do\
make -C $$i clean || exit $?; \
done


OBJSCLEAN :
@rm -rf $(CURRENT_BUILD_PATH)


猜你喜欢

转载自blog.csdn.net/qq1319713925/article/details/80118528