linux驱动学习(二) Makefile高级【转】
转自:http://blog.csdn.net/ghostyu/article/details/6866863
版权声明:本文为博主原创文章,未经博主允许不得转载。
在我前一篇写的【 linux驱动学习(一)Makefile基础】中,Makefile写的中规中矩,其实Makefile写法很灵活,可以写得很简洁,而且减少出错的可能,现在就把之前写的Makefile改进一下。
[plain] view plain copy
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试试看
[plain] view plain copy
<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
[plain] view plain copy
[plain] view plain copy
<localhost.localdomain:/data/ghostyu/linuxc> which cc
/usr/bin/cc
事实上cc指向的也是gcc
其实,这是Makefile的内建隐含规则,然后make时,调用这些隐含规则。
[plain] view plain copy
# 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是一个变量,
[plain] view plain copy
OUTPUT_OPTION = -o $@
这边变量展开为:“-o main.o”
其次,展开COMPILE变量
[plain] view plain copy
# default
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
为:“cc -c”。中间有四个空格。
然后
[plain] view plain copy
%.o: %.c
这就相当于 main.o:main.c
最后
[plain] view plain copy
$(COMPILE.c) $(OUTPUT_OPTION) $<
注意开头的空白为tab键,8个字符,这是Makefile规定的,gcc命令等必须tab开头识别
展开为:
[plain] view plain copy
cc -c -o main.o main.c
完整的:
[java] view plain copy
main.o:main.h hello.h word.h
main.o:main.c
cc -c -o main.o main.c
这就隐含的包含了各个条件的编译
注意:上面之所以可以写成两行,是应为条件并不是一定要写在一行,可以分开写,但只能存在一条命令:
比如下列:
[plain] view plain copy
main.o: main.c main.h hello.h word.h
gcc -c main.c
可以写成:
[java] view plain copy
main.o:main.h hello.h word.h
main.o:main.c
gcc -c main.c
写规则的目的是让make建立依赖关系图,不管怎么写,只要把所有的依赖关系都描述清楚了就行。
****************************Makefile 变量**************************
[plain] view plain copy
var = $(gho)
gho = yu
all:
@echo $(var)
make all时,输出 yu
[plain] view plain copy
<localhost.localdomain:/data/ghostyu/linuxc/test> make all
yu
这就是Makefile中的变量,与TCL脚本的变量很类似
之所以输出yu 而非 gho,是因为‘=’不用立即展开,若果在第一等号前加‘:’,试试。
[plain] view plain copy
<pre name="code" class="plain" style="margin-top: 4px; margin-right: 0px; margin-bottom: 4px; margin-left: 0px; background-color: rgb(240, 240, 240); ">var := $(gho)
gho = yu
all:
@echo $(var)</pre>
<pre></pre>
<pre></pre>
<pre></pre>
这样make all 后输出为空,这是因为var:=$(gho),遇到‘:’将立即展开,gho此时又为定义,因此输出空,若gho=yu放在前面,则依然输出yu
还有一个比较有用的赋值运算符是?=,例如var ?= $(gho)的意思是:如果var没有定义过,那么?=相当于=,定义var的值是$(gho),但不立即展开;如果先前已经定义了var,则什么也不做,不会给var重新赋值。
+=运算符可以给变量追加值
[plain] view plain copy
var = main.o
var += $(gho)
gho = hello.o word.o
这是var的值为 main.o hello.o word.o
常用的特殊变量有四个,出去之前用的$@与$<,还有$? 和$^
$@,表示规则中的目标。
$<,表示规则中的第一个条件。
$?,表示规则中所有比目标新的条件,组成一个列表,以空格分隔。
$^,表示规则中的所有条件,组成一个列表,以空格分隔。
因此
[plain] view plain copy
main: main.o hello.o word.o
gcc main.o hello.o word.o -o main
可以改写为:
[plain] view plain copy
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。
***************************自动处理头文件的依赖关系*************************
[plain] view plain copy
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选项。
[plain] view plain copy
<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建议这样:
[plain] view plain copy
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 驱动学习笔记01--Linux 内核的编译
由于用的学习材料是<linux设备驱动开发详解(第二版)>,所以linux驱动学习笔记大部分文字描述来自于这本书,学习笔记系列用于自己学习理解的一种查阅和复习方式. #make confi ...
- 如何编写一个简单的Linux驱动(二)——完善设备驱动
前期知识 1.如何编写一个简单的Linux驱动(一)——驱动的基本框架 2.如何编写一个简单的Linux驱动(二)——设备操作集file_operations 前言 在上一篇文章中,我们编写设备驱动遇 ...
- 树莓派linux驱动学习之hello world
最近想学习一下linux驱动,看了一些书和教学视频,大概了解了一下,不过要想深入,肯定需要实践.手上有几块linux的板子,最终选择了树莓派作为我的实验平台,资料比较丰富,接口也比较简单. 程序员的入 ...
- Linux驱动学习之常用的模块操作命令
1.常用的模块操作命令 (1)lsmod(list module,将模块列表显示),功能是打印出当前内核中已经安装的模块列表 (2)insmod(install module,安装模块),功能是向当前 ...
- Linux驱动学习步骤(转载)
1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. 学会写驱动的makefile 4. 写一简单char驱动,makefile编译通过,可以insmod, ls ...
- Linux驱动学习之驱动开发准备工作
一.开启驱动开发之路 1.驱动开发的准备工作 (1)正常运行linux系统的开发板.要求开发板中的linux的zImage必须是自己编译的,不能是别人编译的.原因在于在安装模块的时候会进行安全性校验 ...
- Linux驱动学习之什么是驱动?
一.什么是驱动? 1: 驱动一词的字面意思 2: 物理上的驱动 3: 硬件中的驱动 4: linux内核驱动.软件层面上的驱动广义上是指:这一段代码操作了硬件去动,所以这一段代码就叫硬件的驱动程序. ...
- linux驱动系列之makefile
在linux环境下做嵌入式无论是编写应用程序还是驱动程序等等,都需要用make来进行程序的编译,就需要学会自己编写Makefile.Makefile主要的作用有3点:1.决定编译哪些文件 2.怎样编译 ...
- Linux驱动学习1.hello world;
最近项目需要使用Linux系统开发,借此机会学习一下Linux驱动开发 hello word代码hello.c #include <linux/module.h> #include < ...
随机推荐
- Python-学习-小例子练习
网上了点小例子,练习一下下,都是特别简单的.而且这些代码也都是找的网上的代码,目的是在于练习一下Python和熟悉下Python的编码风格等等 学习一门语言,最快的方法就是把它用在世界的开发中,这样才 ...
- 解决灰色shader与mask冲突的方案
Shader "Custom/Opaque" { Properties { [PerRendererData] _MainTex ("Sprite Texture&quo ...
- Tensorflow Serving介绍及部署安装
TensorFlow Serving 是一个用于机器学习模型 serving 的高性能开源库.它可以将训练好的机器学习模型部署到线上,使用 gRPC 作为接口接受外部调用.更加让人眼前一亮的是,它支持 ...
- 修复 Ubuntu 中“Unable to lock the administration directory (/var/lib/dpkg/)”
在 Ubuntu 或者它的衍生版如 Linux Mint(我已经作为日常工作使用的系统)中使用 apt-get 命令或者其相对更新的APT 管理工具时,你可能会在命令行中看到一个 unable to ...
- Spring Cloud文档地址大全
Spring Cloud:http://cloud.spring.io/spring-cloud-static/spring-cloud.html Spring Cloud Config:http:/ ...
- Alpha项目冲刺(团队作业5)
团队成员 组 员 学号 朱世杰 211414141 曹晔宁 211306302 一.冲刺(7次 Scrum) [Alpha版本]冲刺阶段--Day 1 [Alpha版本]冲刺阶段--Day 2 [Al ...
- OpenCV漫水填充算法示例代码
#include<cv.h> #include<highgui.h> int main(int argc, char** argv) { IplImage* img = cvL ...
- angular2采用自定义指令(Directive)方式加载jquery插件
由于angular2兴起不久,相关插件还是很少,所以有时候不得不用一些jquery插件来完成项目, 那么如何把jquery插件放到angular2中呢?采用自定义指令! 在上下文之前要引入jquery ...
- PHP整数取余返回负数解决办法
<?php $num1 = 1494313163777; $num2 = 9999; //直接计算取余会出错,出现负数 -8779 //echo $num1 % $num2;exit; //算上 ...
- 【WebService】——CXF整合Spring
相关博客: [WebService]--入门实例 [WebService]--SOAP.WSDL和UDDI 前言: 之前的几篇博客基本上都是使用jdk来实现WebService的调用,没有使用任何框架 ...