linux编程写一个用户程序及字符设备驱动?

本章将简要介绍一下什么是Linux,C语言的特点,程序开发的预备知识,Linux下C语言开发的环境,程序设计的特点和原则以及编码风格等。通过本章的学习,可以对在Linux下使用C语言编程有一个基本的了解。

Linux是能够自由传播并继承了UNIX内核的操作系统,是对UNIX的简化和改进,它既保留了UNIX系统的高安全性,同时也使其操作更加简单方便,从而使单机用户也可以使用。UNIX内核指的是操作系统底层的核心程序代码。

因为 Linux本身脱胎于UNIX系统,所以Linux程序与UNIX程序是十分相似的。事实上,UNIX下编写的各种程序基本上都可以在 Linux下编译和运行。此外,许多在UNIX操作系统下创建的一些商业化应用软件,其二进制形式几乎可以在不作任何修改的情况下直接运行在 Linux系统上。

Linux是由芬兰的赫尔辛基大学 (Helsinki)学生Linus Torvalds把Minix 系统向x86移植的结果。当时 Linus 手边有个 Minix 系统(UNIX 的一个分支),他对这个操作系统相当有兴趣,由于当时他正好有一台个人计算机,他想把这个系统移植到该计算机(x86 架构)上来使用。由于受益于Stallman提倡的开放源代码(Open Source)思想,他得以接触到UNIX操作系统的一些源代码,并仔细研读了UNIX 的核心,然后去除较为繁复的核心程序,将它改写成能够适用于一般个人计算机的一种操作系统,即Linux系统的雏形。

1992年1月,大概只有100人开始使用Linux,但他们为Linux的发展壮大作出了巨大贡献。他们对一些不合理的代码进行了改进,修补了代码错误并上传补丁。Linux的腾飞最关键的因素是获得了自由软件基金(FSF)的支持,他们制定了一个GNU计划,该计划的目标就是要编写一个完全免费的 UNIX版本——包括内核及所有相关的组件,可以让用户自由共享并且改写软件,而Linux正好符合他们的意愿。他们将Linux与其现有的GNU应用软件很好地结合起来,使Linux拥有了图形用户界面。

Linux 实际上只是提供了操作系统的内核;它实现了多任务和多用户功能,管理硬件,分配内存,激活应用程序的运行。对初学者来说,最重要的是要明白奇数的内核版本(比如

还是先来看一看常用的隐含规则。

1. 编译C程序的隐含规则

2. 编译C++程序的隐含规则

7. 汇编和汇编预处理的隐含规则

这个规则对于只有一个源文件的工程有效,同时也对多个Object文件(由不同的源文件生成)有效。例如如下规则:

并且x.c、y.c和z.c都存在时,隐含规则将执行如下命令:

如果没有一个源文件(如上例中的x.c)和目标名字(如上例中的x)相关联,最好写出自己的生成规则,不然,隐含规则会报错。

12. 从C程序、Yacc文件或Lex文件创建Lint库的隐含规则

在隐含规则的命令中,基本上都使用了一些预先设置的变量。可以在makefile文件中改变这些变量的值,或是在make的命令行中传入这些值,或是在环境变量中设置这些值。无论怎么样,只要设置了这些特定的变量,其就会对隐含规则起作用。当然,也可以利用make的-R或--no–builtin-variables参数来取消所定义的变量对隐含规则的作用。

例如,第一条隐含规则——编译C程序的隐含规则的命令是$(CC)–c $(CFLAGS) $(CPPFLAGS)。Make默认的编译命令是cc,如果把变量$(CC)重定义成gcc,把变量$(CFLAGS)重定义成-g,隐含规则中的命令全部会以gcc –c -g $(CPPFLAGS)的样子来执行了。

可以把隐含规则中使用的变量分成两种:一种是命令相关的,如CC;一种是参数相的关,如CFLAGS。下面是所有隐含规则中会用到的变量。

2. 关于命令参数的变量

下面的这些变量都是上面的命令相关的参数。如果没有指明其默认值,其默认值都是空。

有些时候,一个目标可能被一系列的隐含规则所作用。例如,一个.o的文件生成,可能会是先被Yacc的.y文件先成.c,然后再被C的编译器生成。这一系列的隐含规则叫做“隐含规则链”。

在上面的例子中,如果文件.c存在,就直接调用C的编译器的隐含规则;如果没有.c文件,但有一个.y文件,Yacc的隐含规则会被调用,生成.c文件,然后,再调用C编译的隐含规则,最终由.c生成.o文件,达到目标。

这种.c的文件(或是目标)叫做中间目标。不管怎么样,make会努力自动推导生成目标的一切方法。不管中间目标有多少,其都会执着地把所有的隐含规则和书写的规则全部合起来分析,努力达到目标。所以,有些时候,可能会觉得奇怪,怎么目标会这样生成?怎么makefile文件发疯了?

在默认情况下,中间目标和一般的目标有两个位置不同:第一个不同是除非中间的目标不存在,才会引发中间规则;第二个不同是,只要目标成功产生,产生最终目标的过程中,所产生的中间目标文件会被rm -f删除。

通常,一个被makefile文件指定成目标或是依赖目标的文件不能当作中介。然而,可以显式地说明一个文件或是目标是中介目标,可以使用伪目标.INTERMEDIATE来强制声明(如.INTERMEDIATE:mid )。

也可以阻止make自动删除中间目标。要做到这一点,可以使用伪目标.SECONDARY来强制声明(如.SECONDARY : sec)。还可以把目标以模式的方式来指定(如%.o)成伪目标.PRECIOUS的依赖目标,以保存被隐含规则所生成的中间文件。

在隐含规则链中,禁止同一个目标出现两次或两次以上,这样一来,就可防止在make自动推导时出现无限递归的情况。

Make会优化一些特殊的隐含规则,而不生成中间文件。如,从文件foo.c生成目标程序foo。按道理,make会编译生成中间文件foo.o,然后链接成foo,但在实际情况下,这一动作可以被一条cc命令完成(cc –o foo foo.c),于是优化过的规则就不会生成中间文件。 

可以使用模式规则来定义一个隐含规则。一个模式规则跟一般的规则类似,只是在规则中,目标的定义需要有“%”字符。“%”的意思是表示一个或多个任意字符。在依赖目标中同样可以使用“%”,只是依赖目标中的“%”的取值取决于其目标。

有一点需要注意的是,“%”的展开发生在变量和函数的展开之后,变量和函数的展开发生在make载入makefile文件时,而模式规则中的“%”则发生在运行时。

模式规则中,至少在规则的目标定义中要包含“%”,否则,就是一般的规则。目标中的“%”定义表示对文件名的匹配,“%”表示长度任意的非空字符串。例如: %.c表示以.c结尾的文件名(文件名的长度至少为3),而s.%.c则表示以s.开头,.c结尾的文件名(文件名的长度至少为5)。

如果“%”定义在目标中,目标中的“%”的值决定了依赖目标中的“%”的值,也就是说,目标中的模式的“%”决定了依赖目标中“%”的样子。例如有一个模式规则如下:

其含义是,指出了从所有的.c文件生成相应的.o文件的规则。如果要生成的目标是a.o b.o,%c就是“a.c b.c”。

一旦依赖目标中的“%”模式被确定,make会被要求去匹配当前目录下所有的文件名。在模式规则中,目标可能会是多个,如果有模式匹配出多个目标,make就会产生所有的模式目标,此时,make关心的是依赖的文件名和生成目标的命令这两件事。

下面这个例子表示了把所有的.c文件都编译成.o文件。

其中,“$@”表示所有的目标的逐个值,“$<”表示了所有依赖目标的逐个值。这些奇怪的变量叫“自动化变量”。

下面的这个例子中有两个目标是模式的:

在上述的模式规则中,目标和依赖文件都是一系例的文件,如何书写一个命令来完成从不同的依赖文件生成相应的目标?因为在每一次的对模式规则的解析时,都会是不同的目标和依赖文件。

自动化变量就是完成这个功能的。在前面,已经对自动化变量有所提及,相信看到这里已对它有一个感性认识了。所谓自动化变量,就是这种变量会把模式中所定义的一系列的文件自动地逐个取出,直至所有符合模式的文件都取完。这种自动化变量只应出现在规则的命令中。

下面是所有的自动化变量及其说明:

表示规则中的目标文件集。在模式规则中,如果有多个目标,“$@”就是匹配于目标中模式定义的集合。

仅当目标是函数库文件时,表示规则中的目标成员名。例如,如果一个目标是foo.a(bar.o),“$%”就是bar.o,“$@”就是foo.a。如果目标不是函数库文件(如Unix下是.a,Windows下是.lib),其值为空。

依赖目标中的第一个目标名字。如果依赖目标是以模式(即“%”)定义的,“$<”将是符合模式的一系列的文件集。注意,其是一个一个地取出来的。

所有比目标新的依赖目标的集合,以空格分隔。

所有的依赖目标的集合,以空格分隔。如果在依赖目标中有多个重复的,那么这个变量会去除重复的依赖目标,只保留一份。

这个变量很像“$^”,也是所有依赖目标的集合。只是它不去除重复的依赖目标。

这个变量表示目标模式中“%”及其之前的部分。如果目标是dir/a.foo.b,并且目标的模式是a.%.b,“$*”的值就是dir/a.foo。这个变量对于构造有关联的文件名比较有效。如果目标中没有模式的定义,“$*”也就不能被推导出,但是,如果目标文件的后缀是make所识别的,“$*”就是除了后缀的那一部分。例如:如果目标是foo.c,因为.c是make所能识别的后缀名,所以,“$*”的值就是foo。这个特性是GNU make的,很有可能不兼容于其他版本的make,所以,应该尽量避免使用“$*”,除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不能识别的,“$*”就是空值。

当希望只对更新过的依赖文件进行操作时,“$?”在显式规则中很有用。例如,假设有一个函数库文件叫lib,其由其他几个object文件更新,把object文件打包的比较有效率的makefile文件规则是:

在上述所列出来的自动变量中,4个变量($@、$<、$%、$*)在扩展时只会有1个文件,而另3个的值是一个文件列表。这7个自动化变量还可以取得文件的目录名或是在当前目录下的符合模式的文件名,只需要搭配上“D”或“F”字样。这是GNU make中老版本的特性,在新版本中,使用函数dir或notdir就可以做到了。D的含义是Directory,就是目录;F的含义是File,就是文件。

下面是对上面的7个变量分别加上“D”或是“F”的含义:

表示“$@”的目录部分(不以斜杠作为结尾),如果“$@”值是dir/foo.o,“$(@D)”就是dir,而如果“$@”中没有包含斜杠,其值就是“.”(当前目录)。

和上面所述的同理,也是取文件的目录部分和文件部分。对于上面的那个例子,“$(*D)”返回dir,而“$(*F)”返回foo。

分别表示了函数包文件成员的目录部分和文件部分。这对于形同archive(member)形式的目标中的member中包含了不同的目录很有用。

分别表示依赖文件的目录部分和文件部分。

分别表示所有依赖文件的目录部分和文件部分(无相同的)。

分别表示所有依赖文件的目录部分和文件部分(可以有相同的)

分别表示被更新的依赖文件的目录部分和文件部分。

最后提醒一下的是,对于“$<”,为了避免产生不必要的麻烦,最好给“$”后面的那个特定字符都加上圆括号,比如,“$(<)”就要比“$<”好一些。

还要注意的是,这些变量只使用在规则的命令中,而且一般都是“显式规则”和“静态模式规则”,其在隐含规则中并没有意义。

一般来说,一个目标的模式有一个带有前缀或是后缀的“%”,或是没有前后缀,直接就是一个“%”。因为“%”代表一个或多个字符,所以在定义好了的模式中,把“%”所匹配的内容叫做“茎”,例如“%.c”所匹配的文件test.c中test就是“茎”。因为在目标和依赖目标中同时有“%”时,依赖目标的“茎”会传给目标,当做目标中的“茎”。

当一个模式匹配包含有斜杠(实际也不经常包含)的文件时,在进行模式匹配时,目录部分会首先被移开,然后进行匹配,成功后,再把目录加回去。在进行“茎”的传递时,需要知道这个步骤。例如有一个模式e%t,文件src/eat匹配于该模式,于是src/a就是其“茎”。如果这个模式定义在依赖目标中,而依赖于这个模式的目标中又有个模式c%r,目标就是src/car (“茎”被传递)。

5. 重载内建隐含规则

可以重载内建的隐含规则(或是定义一个全新的),例如可以重新构造和内建隐含规则不同的命令,如:

可以取消内建的隐含规则,只要不在后面写命令就行。如:

同样,也可以重新定义一个全新的隐含规则,其在隐含规则中的位置取决于在哪里写下这个规则。朝前的位置就靠前。

比如有一个目标叫T,下面是搜索目标T的规则的算法。请注意,在下面没有提到后缀规则,原因是所有的后缀规则在makefile文件被载入内存时,会转换成模式规则。如果目标是archive(member)的函数库文件模式,这个算法会运行两次,第一次是找目标T,如果没有找到,进入第二次,第二次会把member当作T来搜索。

(1) 把T的目录部分分离出来,叫D,而剩余部分叫N(例如,如果T是src/foo.o,D就是src/,N就是foo.o)。

(2) 创建所有匹配于T或是N的模式规则列表。

(3) 如果在模式规则列表中有匹配所有文件的模式,如“%”,从列表中移除其他的模式。

(4) 移除列表中没有命令的规则。

(5) 对于第一个在列表中的模式规则:

●       计算依赖文件。把依赖文件中的“%”都替换成“茎”S。如果目标模式中没有包含斜框字符,就把D加在第一个依赖文件的开头。

●       测试是否所有的依赖文件都存在或是理当存在(如果有一个文件被定义成另外一个规则的目标文件,或者是一个显式规则的依赖文件,这个文件就叫“理当存在”)。

●       如果所有的依赖文件存在或是理当存在,或是就没有依赖文件,这条规则将被采用,退出该算法。

(6) 如果经过第5步,没有找到模式规则,就作更进一步的搜索。对于存在于列表中的第一个模式规则:

●       如果所有的依赖文件存在或是理当存在,或是就根本没有依赖文件。这条规则被采用,退出该算法。

(7) 如果没有隐含规则可以使用,查看.DEFAULT规则,如果有,就采用,把.DEFAULT的命令给T使用。

一旦规则被找到,就会执行其相当的命令,而此时,自动化变量的值才会生成。

使用make更新函数库文件

函数库文件也就是对Object文件(程序编译的中间文件)的打包文件。在Unix下,一般是由命令ar来完成打包工作。

一个函数库文件由多个文件组成。可以以如下格式指定函数库文件及其组成:

这不是一个命令,而是一个目标和依赖的定义。一般来说,这种用法基本上就是为了ar命令来服务的。如:

如果要指定多个member,那就以空格分开,如:

还可以使用Shell的文件通配符来定义,如:

当make搜索一个目标的隐含规则时,一个特性是,如果这个目标是“a(m)”形式的,其会把目标变成“(m)”。于是,如果成员是“%.o”的模式定义,并且如果使用make foo.a(bar.o)的形式调用makefile文件,隐含规则会去找bar.o的规则;如果没有定义bar.o的规则,内建隐含规则生效,make会去找bar.c文件来生成bar.o。如果找得到,make执行的命令大致如下:

还有一个变量要注意的是“$%”,这是专属函数库文件的自动化变量。

可以使用后缀规则和隐含规则来生成函数库打包文件,如:   

在生成函数库打包文件时,请小心使用make的并行机制(-j参数)。如果多个ar命令在同一时间运行在同一个函数库打包文件上,就很有可能损坏这个函数库文件。所以,在make未来的版本中,应该提供一种机制来避免并行操作发生在函数打包文件上。但就目前而言,还是尽量不要使用-j参数。

make的makefile文件的所有细节了。无论什么样的make,都是以文件的依赖性为基础的,其基本都是遵循一个标准的。对于前述所有的make的细节,不但可以利用make这个工具来编译程序,还可以利用make来完成其他的工作。因为规则中的命令可以是任何Shell之下的命令,所以,在Linux下,不一定只使用程序语言的编译器,还可以在makefile文件中书写其他的命令,如tar、awk、mail、sed、cvs、compress、ls、rm、yacc、rpm、ftp等,来完成诸如程序打包、程序备份、制作程序安装包、提交代码、使用程序模板、合并文件等诸多功能,如文件操作、文件管理、编程开发设计,或是其他一些异想天开的东西

}

内容简介:Linux 字符设备驱动程序编写基本流程Linux device driver 的概念   系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作。设备驱动程序是内核的一部分,它完成以下的功能: 1、对设备初始化和释放; 2、把数据从内核传送到硬件和从硬件读取数据; 3、读取应用程序传送给设备文件的数据和回送应用程序请求的数据; 4、检测和处理设备出现的错误。   在 Linux 操作系统下有三类主要的设备文件类型,一是字符...

资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!

}

我要回帖

更多关于 linux字符设备和块设备 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信