转载地址: https://blog.csdn.net/mars1743/article/details/24180349
先贴出 rules.mk 源码:
#########################################################################
_depend: $(obj).depend
$(obj).depend: $(src)Makefile $(TOPDIR)/config.mk $(SRCS)
@rm -f $@
@for f in $(SRCS); do \
g=`basename $$f | sed -e 's/\(.*\)\.\w/\1.o/'`; \
$(CC) -M $(HOST_CFLAGS) $(CPPFLAGS) -MQ $(obj)
g
g
f >> $@ ; \
done
#########################################################################
哇,看着好复杂啊,头大了。
任何复杂的东西都是由简单的东西拼接而成的,别急,我们一点点来把它支解。
前面的
_depend: $(obj).depend
$(obj).depend: $(src)Makefile $(TOPDIR)/config.mk $(SRCS)
@rm -f $@
@for f in $(SRCS); do \
估计大家都懂,就不作过多解释了。
下面我们来看
g=`basename $$f | sed -e 's/\(.*\)\.\w/\1.o/'`; \
其目标是将把文件扩展名的首个字符替换成o。
main.c --->main.o
book@book-desktop:~/workspace/test/ex-1$ f=main.c; g=`basename $f | sed -e 's/.∗.∗\.\w/\1.o/'`;echo $g
main.o
究竟是怎样做到呢?
里面有个basename 函数
man basename:
NAME
basename - strip directory and suffix from filenames
SYNOPSIS
basename NAME [SUFFIX]
basename OPTION
DESCRIPTION
Print NAME with any leading directory components removed. If specified, also remove a trailing SUFFIX.
--help display this help and exit
--version
output version information and exit
EXAMPLES
basename /usr/bin/sort
Output "sort".
从上面的解说来看,就时去掉某个文件的路径名得来它的文件名。
接着这里使用了管道命令,前面命令的stdout 作出后面命令的stdin 。
对于 f=main.c; g=`basename $f
它的输出就是main.c
再看 sed -e 's/.∗.∗\.\w/\1.o/'`;
乍一看符合合sed 's/ word1/word2 /' 用word2替换word1的命令模式
word1 为.∗.∗\.\w
.*表示任意多个字符;
.∗.∗是用来做后向引用的,\1就是它了;
\.是一个点
\w用于匹配字母,数字或下划线字符;
word2为\1.o
所以上面的命令大意就是保留XXX.X 的"."前面部分。后面的X用o代替。
e.g:
main.c-->main.o
start.s--->start.o
至于sed 命令选项 -e 网上解释为:
sed选项
选项 功能
-e 进行多项编辑,即对输入行应用多条sed命令时使用
-n 取消默认的输出
-f 指定sed脚本的文件名
book@book-desktop:~/workspace/test/ex-1$ ls
1 2 include main.c main.o Makefile subdir test
book@book-desktop:~/workspace/test/ex-1$ ls
1 2 include main.c main.o Makefile subdir test
book@book-desktop:~/workspace/test/ex-1$ cat 2
just for check
just for test
just for CHECK
just for TEST
文件2里面的内容是上面那样的。
接下我们进行替换
book@book-desktop:~/workspace/test/ex-1$ sed -e 's/check/test/' -e 's/test/TEST/' 2
just for TEST
just for TEST
just for CHECK
just for TEST
我们先把check替换为test ,再基于上面的替换结果把test替换为TEST.
好了前面的一大堆目的就是为了得到XXX.o 的文件并赋值给g。我们继续看下面的。
$(CC) -M $(HOST_CFLAGS) $(CPPFLAGS) -MQ $(obj)
g
g
f >> $@ ;
我们翻译下得到,忽略$(HOST_CFLAGS) $(CPPFLAGS)
HOSTCFLAGS= -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
CPPFLAGS := $(DBGFLAGS) $(OPTFLAGS) $(RELFLAGS)\
-D__KERNEL__ -DTEXT_BASE=$(TEXT_BASE)\
gcc -M -MQ main.o main.c >> .depend
接下的疑问就是-M -MQ 选项了,翻译自GCC的帮助文档:
-M 不是输出预编译过程的结果,而是输出一个用于make的规则,该规则描述了这个main源文件的依赖关系。预编译器输出的这个make规则包含名字与原文件相同的目标文件,冒号和所有include文件的名字。这些include文件主要来自于-include或-imacros命令行选项。
除非明确的指定-MT或-MQ,否则目标文件名由两部分组成:源文件名加目标文件后缀和可以被删除的目标文件路径。如果有多个include的文件,该规则将使用\-newline将其分成几行。该规则并没用命令。
---------------------
作者:mars1743
来源:CSDN
原文:https://blog.csdn.net/mars1743/article/details/24180349
版权声明:本文为博主原创文章,转载请附上博文链接!