makefile 笔记(中)

17. gcc的-M和-MM会列出一个源文件对其他文件的依赖关系,所不同的是-MM不会列出对于系统头文件的依赖关系
// screen content begin
$gcc -MM foo.c
foo.o: foo.c foo.h
// screen content end

说下sed,比如:
sed 's,\(.*\)\.o[:]*,objs/\1.o:,g'

上述属于sed的其中一种用法:sed 's/要替换的字符串/新的字符串/g'
1.并不是只有/可作为模式分割符,很多符合如,;都可以,尤其是模式中有/时使用其他分割符更方便;

2.

\(.*\)\.o 任意多个字符(至少一个)后面是.o,如abc.o

[ :]* 任意多个空格或:
\1 引用前面第一个出现的括号中内容,对abc.o,即abc
3. \(  \) 在替换命令中是“组”的用法(正则表达式中也是这样),后面可以用\1 \2 等来分别引用前面括起来的部分。( 指括号本身。


18. gcc还有一个非常有用的选项是-E,这个命令告诉gcc只做预处理,而不进行程序编译,在生成依赖关系时,我们不需要编译只需预处理即可。我们为每一个源文件通过采用gcc和sed生成一个依赖关系文件,这些文件采用.dep后缀结尾。
Makefile
--------
.PHONY: all clean
MKDIR = mkdir
RM = rm
RMFLAGS = -fr
CC = gcc
DIR_OBJS = objs
DIR_EXES = exes
DIR_DEPS = deps
DIRS = $(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS)
EXE = complicated
EXE := $(addprefix $(DIR_EXES)/, $(EXE))
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
DEPS = $(SRCS:.c=.dep)
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))

all: $(DIRS) $(DEPS) $(EXE)
$(DIRS):
        $(MKDIR) $@
$(EXE): $(OBJS)
        $(CC) -o $@ $^
$(DIR_OBJS)/%.o: %.c
        $(CC) -o $@ -c $^

$(DIR_DEPS)/%.dep: %.c

        @echo "Making $@ ..."

        @set -e; \

        $(RM) $(RMFLAGS) $@.tmp; \

        $(CC) -E -MM $^ > $@.tmp; \

        sed 's,\(.*\)\.o[ :]*,objs/\1.o: ,g' < $@.tmp >$@; \
        $(RM) $(RMFLAGS) $@.tmp
clean:
       $(RM) $(RMFLAGS) $(DIRS)

上面set -e的作用是告诉BASH Shell当生成依赖文件的过程中出现任何错误时,就直接退出,不然还会继续执行下去;这里有个需要注意的地方:对于规则中的每个命令,make都是在一个新的Shell上运行它的,如果希望多个命令在同一个Shell中运行,则需要用‘;’将这些命令连起来

19. 引入include,如同C/C++中的预编译,-include表示文件若不存在则忽略这一错误,将所有的目录创建都放到相应的规则中去,对18进行改进
Makefile
--------
.PHONY: all clean
MKDIR = mkdir
RM = rm
RMFLAGS = -fr
CC = gcc
DIR_OBJS = objs
DIR_EXES = exes
DIR_DEPS = deps
DIRS = $(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS)
EXE = complicated
EXE := $(addprefix $(DIR_EXES)/, $(EXE))
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
DEPS = $(SRCS:.c=.dep)
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))

all: $(EXE)
-include $(DEPS)

$(DIRS):
        $(MKDIR) $@
$(EXE): $(DIR_EXES) $(OBJS)
        $(CC) -o $@ $(filter %.o, $^)
$(DIR_OBJS)/%.o: $(DIR_OBJS) %.c
        $(CC) -o $@ -c $(filter %.c, $^)
$(DIR_DEPS)/%.dep: $(DIR_DEPS) %.c
        @echo "Making $@ ..."
        @set -e; \
        $(RM) $(RMFLAGS) $@.tmp; \
        $(CC) -E -MM $(filter %.c, $^) > $@.tmp; \
        sed 's,\(.*\)\.o[ :]*,objs/\1.o: ,g' < $@.tmp >$@; \
        $(RM) $(RMFLAGS) $@.tmp
clean:
        $(RM) $(RMFLAGS) $(DIRS)


20. 19所示代码有一个缺陷,其实依赖关系文件.dep本身也需要采用.o相类似的依赖规则,不然会得不到更新,比如第一次make后头文件中又增加了新的头文件,在第二次make后又对该新的头文件作更改,那么按照19的写法,make就不会去rebuild,解决的办法很简单,就是在sed中增加.dep本身的依赖规则,更新后的makefile如下
Makefile
--------
.PHONY: all clean
MKDIR = mkdir
RM = rm
RMFLAGS = -fr
CC = gcc
DIR_OBJS = objs
DIR_EXES = exes
DIR_DEPS = deps
DIRS = $(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS)
EXE = complicated
EXE := $(addprefix $(DIR_EXES)/, $(EXE))
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
DEPS = $(SRCS:.c=.dep)
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))

all: $(EXE)
-include $(DEPS)

$(DIRS):
        $(MKDIR) $@
$(EXE): $(DIR_EXES) $(OBJS)
        $(CC) -o $@ $(filter %.o, $^)
$(DIR_OBJS)/%.o: $(DIR_OBJS) %.c
        $(CC) -o $@ -c $(filter %.c, $^)
$(DIR_DEPS)/%.dep: $(DIR_DEPS) %.c
        @echo "Making $@ ..."
        @set -e; \
        $(RM) $(RMFLAGS) $@.tmp; \
        $(CC) -E -MM $(filter %.c, $^) > $@.tmp; \
        sed 's,\(.*\)\.o[ :]*,objs/\1.o $@: ,g' < $@.tmp >$@; \
        $(RM) $(RMFLAGS) $@.tmp
clean:
        $(RM) $(RMFLAGS) $(DIRS)


21. 19和20其实是有一个严重的Bug,就是在创建.dep文件时出现死循环,曾经我问过作者,但仅给出了原因和大致的做法,其原因是:因为.dep文件的创建会造成存放.dep文件的目录的时间戳也发生改变,于是Makefile认为目录的变化需要重新构建.dep文件,于是进入了死循环。解决的方法很简单,就是在发现存放.dep文件的目录已存在时,就不让.dep文件依赖于目录。后来,我看过他的c.rule后,知道了解法的详细操作
Makefile
--------
.PHONY: all clean
MKDIR = mkdir
RM = rm
RMFLAGS = -fr
CC = gcc
DIR_OBJS = objs
DIR_EXES = exes
DIR_DEPS = deps
DIRS = $(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS)
EXE = complicated
EXE := $(addprefix $(DIR_EXES)/, $(EXE))
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
DEPS = $(SRCS:.c=.dep)
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))

all: $(EXE)

ifeq ("$(wildcard $(DIR_DEPS))", "")
DEPS_DIR_DEPS := $(DIR_DEPS)
endif

ifneq ($(MAKECMDGOALS), clean)
-include $(DEPS)
endif

$(DIRS):
        $(MKDIR) $@
$(EXE): $(DIR_EXES) $(OBJS)
        $(CC) -o $@ $(filter %.o, $^)
$(DIR_OBJS)/%.o: $(DIR_OBJS) %.c
        $(CC) -o $@ -c $(filter %.c, $^)
$(DIR_DEPS)/%.dep: $(DEPS_DIR_DEPS) %.c
        @echo "Making $@ ..."
        @set -e; \
        $(RM) $(RMFLAGS) $@.tmp; \
        $(CC) -E -MM $(filter %.c, $^) > $@.tmp; \
        sed 's,\(.*\)\.o[ :]*,objs/\1.o $@: ,g' < $@.tmp >$@; \
        $(RM) $(RMFLAGS) $@.tmp
clean:
        $(RM) $(RMFLAGS) $(DIRS)

顺带提到这里的ifneq和ifeq条件语句,在这些语句块中是不能用自动变量的($@,$^,$<),另外要make clean的话不需要构建依赖文件
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值