linux驱动学习(二) Makefile高级
2011-10-12 17:17
253 查看
在我前一篇写的【 linux驱动学习(一)Makefile基础】中,Makefile写的中规中矩,其实Makefile写法很灵活,可以写得很简洁,而且减少出错的可能,现在就把之前写的Makefile改进一下。
这是不是比以前简单多了,但是main.o hello.o word.o这三个目标的编译命令都没有,怎么会编译呢,执行make试试看
cc是什么呢,执行下which cc
其实,这是Makefile的内建隐含规则,然后make时,调用这些隐含规则。
‘#’为注释符,跟‘//’一样
‘CC’为Makefile变量
'$@'与‘$<’为特殊变量,'$@'的取值为规则的目标,‘$<’取值为规则的第一个条件。
CFLAG CPPFLAG TARGET_ARCH未定义,展开为空,
现在来分析一下,隐含规则是怎样解析Makefile的。
首先,OUTPUT_OPTION是一个变量,
其次,展开COMPILE变量
然后
最后
展开为:
这就隐含的包含了各个条件的编译
注意:上面之所以可以写成两行,是应为条件并不是一定要写在一行,可以分开写,但只能存在一条命令:
比如下列:
写规则的目的是让
****************************Makefile 变量**************************
之所以输出yu 而非 gho,是因为‘=’不用立即展开,若果在第一等号前加‘:’,试试。
这样make all 后输出为空,这是因为var:=$(gho),遇到‘:’将立即展开,gho此时又为定义,因此输出空,若gho=yu放在前面,则依然输出yu
还有一个比较有用的赋值运算符是
常用的特殊变量有四个,出去之前用的$@与$<,还有$? 和$^
因此
$?也很有用,有时候希望只对更新过的条件进行操作。
之前我们看到
静态库打包命令的名字,缺省值是
静态库打包命令的选项,缺省值是
汇编器的名字,缺省值是
汇编器的选项,没有定义。
CC
C编译器的名字,缺省值是
CFLAGS
C编译器的选项,没有定义。
CXX
C++编译器的名字,缺省值是
CXXFLAGS
C++编译器的选项,没有定义。
CPP
C预处理器的名字,缺省值是
CPPFLAGS
C预处理器的选项,没有定义。
LD
链接器的名字,缺省值是
LDFLAGS
链接器的选项,没有定义。
TARGET_ARCH
和目标平台相关的命令行选项,没有定义。
OUTPUT_OPTION
输出的命令行选项,缺省值是
LINK.o
把
LINK.c
把
LINK.cc
把
COMPILE.c
编译
COMPILE.cc
编译
RM
删除命令的名字,缺省值是
***************************自动处理头文件的依赖关系*************************
现在Makefile写成上面的形式,默认make all,这样有个确定,写Makefile时要查个每个源文件,确定其包含的头文件,很容易出错,为了解决这个问题,可用用gcc -M查看源文件的依赖关系,-M选项会把系统头文件也找出来,如果不需要,可以用-MM选项。
现在的问题是怎样将上述依赖包含在Makefile中。
GNUlinux建议这样:
main: main.o hello.o word.o gcc main.o hello.o word.o -o main main.o:main.h hello.h word.h hello.o:hello.h word.o:word.h clean: echo "cleanning project" -rm main *.o echo "clean completed" .PHONY:clean
这是不是比以前简单多了,但是main.o hello.o word.o这三个目标的编译命令都没有,怎么会编译呢,执行make试试看
<localhost.localdomain:/data/ghostyu/linuxc> make cc -c -o main.o main.c cc -c -o hello.o hello.c cc -c -o word.o word.c gcc main.o hello.o word.o -o main <localhost.localdomain:/data/ghostyu/linuxc>
cc是什么呢,执行下which cc
<localhost.localdomain:/data/ghostyu/linuxc> which cc /usr/bin/cc事实上cc指向的也是gcc
其实,这是Makefile的内建隐含规则,然后make时,调用这些隐含规则。
# default OUTPUT_OPTION = -o $@ # default CC = cc # default COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c %.o: %.c # commands to execute (built-in): $(COMPILE.c) $(OUTPUT_OPTION) $<以上是内建规则中关于隐含规则的部分
‘#’为注释符,跟‘//’一样
‘CC’为Makefile变量
'$@'与‘$<’为特殊变量,'$@'的取值为规则的目标,‘$<’取值为规则的第一个条件。
%.o: %.c是一种特殊的规则,称为模式规则(Pattern Rule)。
CFLAG CPPFLAG TARGET_ARCH未定义,展开为空,
现在来分析一下,隐含规则是怎样解析Makefile的。
首先,OUTPUT_OPTION是一个变量,
OUTPUT_OPTION = -o $@这边变量展开为:“-o main.o”
其次,展开COMPILE变量
# default COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c为:“cc -c”。中间有四个空格。
然后
%.o: %.c这就相当于 main.o:main.c
最后
$(COMPILE.c) $(OUTPUT_OPTION) $<注意开头的空白为tab键,8个字符,这是Makefile规定的,gcc命令等必须tab开头识别
展开为:
cc -c -o main.o main.c完整的:
main.o:main.h hello.h word.h main.o:main.c cc -c -o main.o main.c
这就隐含的包含了各个条件的编译
注意:上面之所以可以写成两行,是应为条件并不是一定要写在一行,可以分开写,但只能存在一条命令:
比如下列:
main.o: main.c main.h hello.h word.h gcc -c main.c可以写成:
main.o:main.h hello.h word.h main.o:main.c gcc -c main.c
写规则的目的是让
make建立依赖关系图,不管怎么写,只要把所有的依赖关系都描述清楚了就行。
****************************Makefile 变量**************************
var = $(gho) gho = yu all: @echo $(var)make all时,输出 yu
<localhost.localdomain:/data/ghostyu/linuxc/test> make all yu这就是Makefile中的变量,与TCL脚本的变量很类似
之所以输出yu 而非 gho,是因为‘=’不用立即展开,若果在第一等号前加‘:’,试试。
var := $(gho) gho = yu all: @echo $(var)
这样make all 后输出为空,这是因为var:=$(gho),遇到‘:’将立即展开,gho此时又为定义,因此输出空,若gho=yu放在前面,则依然输出yu
还有一个比较有用的赋值运算符是
?=,例如
var ?= $(gho)的意思是:如果
var没有定义过,那么
?=相当于
=,定义
var的值是
$(gho),但不立即展开;如果先前已经定义了
var,则什么也不做,不会给var重新赋值。
+=运算符可以给变量追加值
var = main.o var += $(gho) gho = hello.o word.o这是var的值为 main.o hello.o word.o
常用的特殊变量有四个,出去之前用的$@与$<,还有$? 和$^
$@,表示规则中的目标。
$<,表示规则中的第一个条件。
$?,表示规则中所有比目标新的条件,组成一个列表,以空格分隔。
$^,表示规则中的所有条件,组成一个列表,以空格分隔。
因此
main: main.o hello.o word.o gcc main.o hello.o word.o -o main可以改写为:
main: main.o hello.o word.o gcc $^ -o $@这样的好处是,即使以后又往条件里加了新的目标,编译命令也不需要修改,既省事,又减少出错。
$?也很有用,有时候希望只对更新过的条件进行操作。
之前我们看到
make的隐含规则数据库中用到了很多变量,有些变量没有定义(例如
CFLAGS),有些变量定义了缺省值(例如
CC),我们写Makefile时可以重新定义这些变量的值,也可以在缺省值的基础上追加。以下列举一些常用的变量。
AR
静态库打包命令的名字,缺省值是
ar。
ARFLAGS
静态库打包命令的选项,缺省值是
rv。
AS
汇编器的名字,缺省值是
as。
ASFLAGS
汇编器的选项,没有定义。
CC
C编译器的名字,缺省值是
cc。
CFLAGS
C编译器的选项,没有定义。
CXX
C++编译器的名字,缺省值是
g++。
CXXFLAGS
C++编译器的选项,没有定义。
CPP
C预处理器的名字,缺省值是
$(CC) -E。
CPPFLAGS
C预处理器的选项,没有定义。
LD
链接器的名字,缺省值是
ld。
LDFLAGS
链接器的选项,没有定义。
TARGET_ARCH
和目标平台相关的命令行选项,没有定义。
OUTPUT_OPTION
输出的命令行选项,缺省值是
-o $@。
LINK.o
把
.o文件链接在一起的命令行,缺省值是
$(CC) $(LDFLAGS) $(TARGET_ARCH)。
LINK.c
把
.c文件链接在一起的命令行,缺省值是
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)。
LINK.cc
把
.cc文件(C++源文件)链接在一起的命令行,缺省值是
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)。
COMPILE.c
编译
.c文件的命令行,缺省值是
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c。
COMPILE.cc
编译
.cc文件的命令行,缺省值是
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c。
RM
删除命令的名字,缺省值是
rm -f。
***************************自动处理头文件的依赖关系*************************
all:main
main: main.o hello.o word.o gcc main.o hello.o word.o -o main main.o:main.h hello.h word.h hello.o:hello.h word.o:word.h clean: echo "cleanning project" -rm main *.o echo "clean completed" .PHONY:clean
现在Makefile写成上面的形式,默认make all,这样有个确定,写Makefile时要查个每个源文件,确定其包含的头文件,很容易出错,为了解决这个问题,可用用gcc -M查看源文件的依赖关系,-M选项会把系统头文件也找出来,如果不需要,可以用-MM选项。
<localhost.localdomain:/data/ghostyu/linuxc> gcc -MM *.c hello.o: hello.c hello.h main.o: main.c main.h hello.h word.h word.o: word.c word.h
现在的问题是怎样将上述依赖包含在Makefile中。
GNUlinux建议这样:
all:main
main: main.o hello.o word.o gcc main.o hello.o word.o -o main
sources = main.c hello.c word.c
include $(sources:.c=.d)
%.d: %.c
set -e; rm -f $@; \
$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
相关文章推荐
- linux驱动学习(二) Makefile高级
- linux驱动学习(二) Makefile高级【转】
- Linux设备驱动程序学习笔记 高级字符驱动学习--阻塞型I/0
- linux驱动学习(一) Makefile基础
- linux驱动学习(三) helloword 和 驱动Makefile
- linux驱动学习(一) Makefile基础
- Linux驱动学习(四)——高级字符设备驱动程序
- [Linux驱动]字符设备驱动学习笔记(三)———高级
- 一步一步学习 Linux 驱动之(Kconfig、Makefile)
- linux驱动学习(三) helloword 和 驱动Makefile
- Linux设备驱动程式学习(5)-高级字符驱动程式操作[(2)阻塞型I/O和休眠]
- Linux设备驱动程式学习(6)-高级字符驱动程式操作[(3)设备文档的访问控制]
- [Linux驱动]字符设备驱动学习笔记(三)———高级
- [学习]Linux--驱动
- Linux驱动学习(四)
- Linux下的I2S驱动学习
- 嵌入式Linux驱动学习之路(十)字符设备驱动-my_led
- (学习)linux驱动程序之字符驱动
- Linux驱动学习9(同步/异步与阻塞/非阻塞的区别 )
- Linux驱动学习10(异步通知 )