Linux程序设计基础-C环境(gcc-gdb-makefile)课件_第1页
Linux程序设计基础-C环境(gcc-gdb-makefile)课件_第2页
Linux程序设计基础-C环境(gcc-gdb-makefile)课件_第3页
Linux程序设计基础-C环境(gcc-gdb-makefile)课件_第4页
Linux程序设计基础-C环境(gcc-gdb-makefile)课件_第5页
已阅读5页,还剩173页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Linux开发基础原仓周专业.....Linux开发基础原仓周专业..第二章Linux程序设计基础—C环境Linux编程概述文本编辑器viLinux下函数库GCC及其使用调试工具gdbGNUmake和makefile专业.....第二章Linux程序设计基础—C环境Linux编程概述专业Linux编程概述

Linux软件开发一直在Internet环境下讲行。这个环境是全球性的,编程人员来自世界各地。只要能够访问Web站点,就可以启动一个以Linux为基础的软件项目。Linux开发工作经常是在Linux用户决定共同完成一个项目时开始的。当开发工作完成后,该软件就被放到Internet站点上,任何用户都可以访问和下载它。由于这个活跃的开发环境,新的以Linux为基础的软件功能日益强大,而且呈现爆炸式的增长态势。大多数Linux软件是经过自由软件基金会(FreeSoftwareFoundation)提供的GNU(GNU即GNU’snotUNIX)公开认证授权的,因而通常被称作GNU软件。GNU软件免费提供给用户使用,并被证明是非常可靠和高效的。许多流行的Linux实用程序如C编译器、shell和编辑器都是GNU软件应用程序。专业.....Linux编程概述Linux软件开发一直在Internet

Linux程序需要首先转化为低级机器语言即所谓的二进制代码以后,才能被操作系统执行。例如编程时,先用普通的编程语言生成一系列指令,这些指令可被翻译为适当的可执行应用程序的二进制代码。这个翻译过程可由解释器一步步来完成,或者也可以立即由编译器明确地完成。shell编程语言如BASH、TCSH、GAWK、Perl、Tcl和Tk都利用自己的解释器。用这些语言编制的程序尽管是应用程序文件,但可以直接运行。编译器则不同,它将生成一个独立的二进制代码文件然后才可以运行。专业.....Linux程序需要首先转化为低级机器语言即所谓的二进制代码Linux编程风格GNU风格Linux内核编程风格专业.....Linux编程风格GNU风格专业..GNU风格(1/2)函数返回类型说明和函数名分两行放置,函数起始字符和函数开头左花括号放到最左边。尽量不要让两个不同优先级的操作符出现在相同的对齐方式中,应该附加额外的括号使得代码缩进可以表示出嵌套。按照如下方式排版do-while语句:do{}while()每个程序都应该以一段简短的说明其功能的注释开头。请为每个函数书写注释,说明函数是做什么的,需要哪些入口参数,参数可能值的含义和用途。如果用了非常见的、非标准的东西,或者可能导致函数不能工作的任何可能的值,应该进行特殊说明。如果存在重要的返回值,也需要说明。不要声明多个变量时跨行,每一行都以一个新的声明开头。专业.....GNU风格(1/2)函数返回类型说明和函数名分两行放置,函GNU风格(2/2)当一个if中嵌套了另一个if-else时,应用花括号把if-else括起来。要在同一个声明中同时说明结构标识和变量或者结构标识和类型定义(typedef)。先定义变量,再使用。尽量避免在if的条件中进行赋值。请在名字中使用下划线以分割单词,尽量使用小写;把大写字母留给宏和枚举常量,以及根据统一惯例使用的前缀。例如,应该使用类似ignore_space_change_flag的名字;不要使用类似iCantReadThis的名字。用于表明一个命令行选项是否给出的变量应该在选项含义的说明之后,而不是选项字符之后被命名。专业.....GNU风格(2/2)当一个if中嵌套了另一个if-elseLinux内核编程风格Linux内核缩进风格是8个字符。Linux内核风格采用K&R标准,将开始的大括号放在一行的最后,而将结束的大括号放在一行的第一位。命名尽量简洁。不应该使用诸如ThisVariableIsATemporaryCounter之类的名字。应该命名为tmp,这样容易书写,也不难理解。命名全局变量,应该用描述性命名方式,例如应该命名“count_active_users()”,而不是“cntusr()”。本地变量应该避免过长。函数最好短小精悍,一般来说不要让函数的参数多于10个,否则应该尝试分解这个过于复杂的函数。通常情况,注释说明代码的功能,而不是其实现原理。避免把注释插到函数体内,而写到函数前面,说明其功能,如果这个函数的确很复杂,其中需要有部分注释,可以写些简短的注释来说明那些重要的部分,但是不能过多。专业.....Linux内核编程风格Linux内核缩进风格是8个字符。文本编辑器vivi的模式vi的进入命令模式插入模式末行模式专业.....文本编辑器vivi的模式专业..vi的模式CommandMode(命令模式)这是执行vi后的缺省模式此时键盘输入当作命令命令有大小写之区分InputMode(插入模式)使用a、i、o、c、r、s

进入插入模式用户输入的任何字符都被vi当做文件内容保存起来,并将其显示在屏幕上按下ESC键即可回到CommandMode专业.....vi的模式CommandMode(命令模式)专业..vi的模式LastMode(末行模式)在

CommandLine按下:即可进入该模式用来进行保存文件、打开文档或环境的设定命令有大小写之分专业.....vi的模式LastMode(末行模式)专业..专业.....专业..vi的进入和内容输入进入:

vi文件名输入文件内容(进入插入模式)新增(append)

a从光标所在位置后面开始新增内容

A从光标所在行最后面的地方开始新增内容。插入(insert)

i从光标所在位置前面开始插入内容

I从光标所在行的第一个非空白字符前面开始插入资料。开始(open)

o在光标所在行下新增一行并进入输入模式。

O在光标所在行上新增一行并进入输入模式。(命令模式)专业.....vi的进入和内容输入进入:(命令模式)专业..命令模式1、光标的移动

h左移一个字符l右移一个字符

j下移一行k上移一行

w,W跳至后一个字的开头(W忽略标点)

b,B跳至前一个字的开头(B忽略标点)

e移动到后一个字的末尾

^至本行第一个非空字符

$至行尾0至行首

H移动到当前窗口的第一列

M移动到当前窗口的中间列

L移动到视窗的最后一列

)光标所在位置到下个句子的第一个字母

(光标所在位置到该句子的第一个字母}光标所在位置到该段落的最后一个字母

{光标所在位置到该段落的第一个字母专业.....命令模式1、光标的移动专业..命令模式1、光标的移动(续)nH将光标移到屏幕的第n行nL将光标移到屏幕的倒数第n行CTRL-d向下半页CTRL-f向下一页CTRL-u向上半页CTRL-b向上一页n-减号移动到上一行的第一个非空白字符,前面加上数字可以指定移动到以上n行n+加号移动到下一行的第一个非空白字符,前面加上数字可以指定移动到以下n行专业.....命令模式1、光标的移动(续)专业..命令模式2、删除

x删除光标所在字符

X删除光标前面的字符

s删除光标所在字符,并进入输入模式

S删除光标所在的行,并进入输入模式

dd删除光标所在的行

D从光标位置开始删除到行尾

d与光标移动命令的组合专业.....命令模式2、删除专业..命令模式3、修改

r修改光标所在字符,r后接着要修改的字符。如,rc可以用字符“c”替换光标所指向的当前字符

R进入替换状态,新增内容会覆盖原先内容,直到按[ESC]回到命令模式下为止

cc修改光标所在行

C修改从光标位置到该行末尾的内容

c与光标移动命令的组合专业.....命令模式3、修改专业..命令模式4、复制和移动yy复制当前行到内存缓冲区nyy复制n行内容到内存缓冲区

y与光标移动的组合p将缓冲区的内容粘贴到光标的后面P将缓冲区的内容粘贴到光标的前面另:在末行模式下实现移动:n1,n2mn3:把n1到n2行内容搬到第n3行后专业.....命令模式4、复制和移动专业..5、搜索字符串/pattern移至下一个包含pattern的行?pattern移至上一个包含pattern的行/往下重复查找?往上重复查找n在同一方向重复查找N在相反方向重复查找/pattern/+n移至下一个pattern所在行后的第n行?pattern?-n移至上一个Pattern所在行前的第n行

6、其他

u撤销前一条命令的结果*.$^[]{}\/包含在查找字符串中,要用转义字符(\)命令模式专业.....5、搜索字符串*.$^[]{}\/命令模式专末行模式1、文件的保存和退出:w保存:q退出:w!强制保存:q!强制退出:wq保存退出:wq!强制保存退出专业.....末行模式1、文件的保存和退出专业..末行模式2、字符串的替换

:s/str1/str2/用字符串str2替换行中首次出现的字符串str1:s/str1/str2/g用字符串str2替换行中所有出现的字符串str1:.,$s/str1/str2/g用字符串str2替换正文当前行到末尾所有出现的字符串str1:1,$s/str1/str2/g用字符串str2替换正文中所有出现的字符串str1:g/str1/s//str2/g功能同上专业.....末行模式2、字符串的替换专业..末行模式其他::n将光标移到第n行编辑多个文件vifile1file2…:n编辑下一个文件:efilename编辑指定文件专业.....末行模式其他:专业..Linux下函数库(1/3)一个“程序函数库”就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用。程序函数库可以使整个程序更加模块化,更容易重新编译,而且更方便升级。可分为两种类型:静态函数库(staticlibraries):是一个普通的目标文件的集合,一般用“.a”作为文件的后缀。静态函数库和共享函数库相比有很多的缺点,占用内存空间多。但使用ELF格式的静态库函数生成的代码可以比使用共享函数库的程序运行速度上快一些。可以用ar这个程序来创建一个静态函数库文件,或者往一个已经存在地静态函数库文件添加新的目标代码。例如,把file1.o和file2.o加入到my_library.a这个函数库文件:

arrcsmy_library.afile1.ofile2.o

然后运行ranlib,以给库加入一些索引信息专业.....Linux下函数库(1/3)一个“程序函数库”就是一个文件包Linux下函数库(2/3)共享函数库(sharedlibraries):当一个可执行程序在启动的时候被加载的函数。每个共享函数库都有个特殊的名字,称作“soname”。soname名字命名必须以“lib”作为前缀,然后是函数库的名字,然后是“.so”,最后是版本号信息。优点:多进程使用同一函数库;修改函数库不需重新连编。安装一个新版本的函数库的时候,要先将这些函数库文件拷贝到一些特定的目录中,运行ldconfig就可以。ldconfig检查已经存在的库文件,然后创建soname的符号链接到真正的函数库,同时设置/etc/ld.so.cache这个缓冲文件。

例如,创建两个目标文件(a.o和b.o),然后创建一个包含a.o和b.o的共享函数库。gcc-fPIC-g-c-Walla.cgcc-fPIC-g-c-Wallb.cgcc-shared-Wl,-soname,liblusterstuff.so.1-oliblusterstuff.so.1.0.1a.ob.o–lc注:”-fPIC”是位置无关参数,”-g”和“-Wall”参数不是必须的。专业.....Linux下函数库(2/3)共享函数库(sharedlibLinux下函数库(3/3)函数库和头文件的保存位置a.函数库/lib:系统必备共享函数库/usr/lib:标准共享函数库和静态函数库/usr/i486-linux-libc5/lib:libc5兼容性函数库/usr/X11R6/lib:X11R6的函数库/usr/local/lib:本地函数库b.头文件/usr/include:系统头文件/usr/local/include:本地头文件c.

共享函数库的相关配置和命令/etc/ld.so.conf:包含共享库的搜索位置ldconfig:共享库管理工具,一般在更新了共享库之后要运行该命令ldd:可查看可执行文件所使用的共享函数库专业.....Linux下函数库(3/3)函数库和头文件的保存位置专业.使用GNUcc开发应用程序gcc的简介可执行文件的格式gcc的使用专业.....使用GNUcc开发应用程序gcc的简介专业..gcc的简介gcc是GNU的C和C++编译器。实际上,gcc能够编译多种语言:C、C++和ObjectC等。利用gcc命令可同时编译并连接C和C++源程序。也可以对几个C源文件利用gcc编译、连接并生成可执行文件。gcc可以使程序员灵活地控制编译过程。编译过程一般可以分为下面四个阶段,每个阶段分别调用不同的工具进行处理预处理链接编译组译源程序(*.c)可执行文件预处理器编译器组译器连接器专业.....gcc的简介gcc是GNU的C和C++编译器gcc的四个阶段命令gcc首先调用cpp进行预处理,在预处理过程中,对源代码文件中的文件包含(include)、预编译语句(如宏定义define等)进行分析。接着调用cc1进行编译,这个阶段根据输入文件生成以.o为后缀的目标文件。汇编过程是针对汇编语言的步骤,调用as进行工作,一般来讲,.S或.s为后缀的汇编语言源代码文件汇编之后都生成以.o为后缀的目标文件。当所有的目标文件都生成之后,gcc就调用ld来完成最后的关键性工作,这个阶段就是连接。在连接阶段,所有的目标文件被安排在可执行程序中的恰当的位置,同时,该程序所调用到的库函数也从各自所在的函数库中连到合适的地方。专业.....gcc的四个阶段命令gcc首先调用cpp进行预处理,在预处理可执行文件格式

Linux系统中可执行文件有两种格式。第一种格式是a.out格式,这种格式用于早期的Linux系统以及Unix系统的原始格式。a.out来自于UnixC编译程序默认的可执行文件名。当使用共享库时,a.out格式就会发生问题。把a.out格式调整为共享库是一种非常复杂的操作。因此,一种新的文件格式被引入Unix系统5的第四版本和Solaris系统中。它被称为可执行和连接的格式(ELF)。这种格式很容易实现共享库。ELF格式已经被Linux系统作为标准的格式采用。gcc编译程序产生的所有的二进制文件都是ELF格式的文件(即使可执行文件的默认名仍然是a.out)。较旧的a.out格式的程序仍然可以运行在支持ELF格式的系统上。专业.....可执行文件格式Linux系统中可执行文件有两种格式。专业GNUC的使用基本语法

gcc[options][filenames]说明:在gcc后面可以有多个编译选项,同时进行多个编译操作。很多的gcc选项包括一个以上的字符。因此你必须为每个选项指定各自的连字符。例如,下面的两个命令是不同的:

gcc-p-gtest1.cgcc-pgtest1.c当你不用任何选项编译一个程序时,GCC将会建立(假定编译成功)一个名为a.out的可执行文件。专业.....GNUC的使用基本语法专业..gcc选项-o选项你能用-o编译选项来为将产生的可执行文件指定一个文件名来代替a.out。 例:gcc–ocountcount.c-c选项:告诉GCC仅把源代码编译为目标代码而跳过汇编和连接的步骤。这个选项使用的非常频繁,因为它使得编译多个C程序时速度更快并且更易于管理。缺省时GCC建立的目标代码文件有一个.o的扩展名。 例:gcc–ctest2.c-E只运行C预编译器。-S编译选项告诉gcc在为C代码产生了汇编语言文件后停止编译。-shared生成共享目标文件。通常用在建立共享库时。-static禁止使用共享连接。专业.....gcc选项-o选项专业..警告选项在gcc中用开关-Wall控制警告信息,使用示例命令如下:

gcc–Wall-otest3_1test3_1.c-w不生成任何警告信息。专业.....警告选项在gcc中用开关-Wall控制警告信息,使用示例命令查找选项gcc一般使用默认路径查找头文件和库文件。如果文件所用的头文件或库文件不在缺省目录下,则编译时要指定它们的查找路径。-I选项:指定头文件的搜索目录 例:

gcc–I/export/home/st–otest1test1.c-L选项:指定库文件的搜索目录 例:

gcc–L/usr/X11/R6/lib–otest1test1.c专业.....查找选项gcc一般使用默认路径查找头文件和库文件。如果文件所多个源文件生成一个可执行文件问题:有多个源文件时,如何生成一个可执行文件?方法1:gcc–Wall–omytesttest1.ctest2.ctest3.c方法2:gcc-Wall-ctest1.cgcc-Wall–ctest2.cgcc-Wall–ctest3.cgcc–omytesttest1.otest2.otest3.o专业.....多个源文件生成一个可执行文件问题:有多个源文件时,如何生成优化选项优化选项可以使GCC在耗费更多编译时间和牺牲易调试性的基础上产生更小更快的可执行文件。这些选项中最典型的是-O和-O2选项。-O0不进行优化处理。-O选项:告诉GCC对源代码进行基本优化。这些优化在大多数情况下都会使程序执行的更快。-O2选项:告诉GCC产生尽可能小和尽可能快的代码。-O2选项将使编译的速度比使用-O时慢。但通常产生的代码执行速度会更快。-O3选项:比-O2更进一步优化,包括inline函数。专业.....优化选项优化选项可以使GCC在耗费更多编译时间和牺牲易调试版本选项-v选项用户将会得到自己目前正在使用的gcc的版本及与版本相关的一些信息。

gcc-v将得到如下结果:

Readingspecsfrom/usr/lib/gcc-lib/i486-box-linux/2.7.2/specsgccversion2.7.2-V选项如果安装了多个版本的gcc,并且想强制执行其中的某个版本,可以用命令通知系统用户要使用的版本。

gcc-V2.6.3-v专业.....版本选项-v选项专业..宏定义选项-DMACRO以字符串“1”定义MACRO宏。-DMACRO=DEFN以字符串“DEFN”定义MACRO宏。-UMACRO取消对MACRO宏的定义。专业.....宏定义选项-DMACRO以字符串“1”定义MACRO调试和剖析选项使用调试选项后,gcc在进行编译的时候,在目标文件(.o)和创建的可执行文件中插入额外信息,这些额外信息使gdb能够判断编译过的代码和源代码之间的关系。-g选项:告诉GCC产生能被GNU调试器使用的调试信息以便调试你的程序。 例:gcc–g–otest3test3.c-pg选项:告诉GCC在你的程序里加入额外的代码,执行时,产生gprof用的剖析信息以显示你的程序的耗时情况。使用gdb调试工具,命令行如下: 例:gcc–ggdb3–otest3test3.c专业.....调试和剖析选项使用调试选项后,gcc在进行编译的时候,在目调试工具gdbGDB调试器简介gdb的常用命令gdb应用实例专业.....调试工具gdbGDB调试器简介专业..gdb简介Linux系统中包含了GNU调试程序gdb,它是一个用来调试C和C++程序的调试器。可以使程序开发者在程序运行时观察程序的内部结构和内存的使用情况。gdb所提供的一些功能如下所示:运行程序,设置所有的能影响程序运行的参数和环境;控制程序在指定的条件下停止运行;当程序停止时,可以检查程序的状态;修改程序的错误,并重新运行程序;动态监视程序中变量的值;可以单步逐行执行代码,观察程序的运行状态。分析崩溃程序的产生的core文件专业.....gdb简介Linux系统中包含了GNU调试程序gdb,它gdb的特点gdb的功能非常强大到目前为止,gdb已能够支持Moduls-2、Chill、Pascal和FORTRAN程序的调试,但是调试这些语言的源程序时有一些功能还不能使用。例如调试FORTRAN程序时还不支持表达式的输入、输出变量或类FORTRAN的词法。gdb程序调试的对象是可执行文件,而不是程序的源代码文件。然而,并不是所有的可执行文件都可以用gdb调试。如果要让产生的可执行文件可以用来调试,需在执行gcc指令编译程序时,加上-g参数,指定程序在编译时包含调试信息。调试信息包含程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。gdb利用这些信息使源代码和机器码相关联。gdb是一个用来调试C和C++程序的常用调试工具之一。

专业.....gdb的特点gdb的功能非常强大专业..gdb的启动在命令行上输入gdb并按回车键就可以运行gdb了,如果一切正常的话,将启动gdbgdb[filename]出现(gdb)在这里,可以输入调试命令在可以使用gdb调试程序之前,必须使用-g选项编译源文件。可在makefile中如下定义CFLAGS变量:CFLAGS=-g运行专业.....gdb的启动在命令行上输入gdb并按回车键就可以运行gdb了获取帮助信息启动gdb后,可以在命令行上指定很多的选项。输入:help可以获得gdb的帮助信息。如果想要了解某个具体命令(比如break)的帮助信息,在gdb提示符下输入下面的命令:break屏幕上会显示关于break的帮助信息。从返回的信息可知,break是用于设置断点的命令。另一个获得gdb帮助的方法是浏览gdb的手册页。在LinuxShell提示符输入:mangdb可以看到man的手册页专业.....获取帮助信息启动gdb后,可以在命令行上指定很多的选项。输入gdb命令的分类在gdb提示符处键入help,将列出命令的分类,主要的分类有:aliases:命令别名breakpoints:断点定义;data:数据查看;files:指定并查看文件;internals:维护命令;running:程序执行;stack:调用栈查看;statu:状态查看;tracepoints:跟踪程序执行。后跟命令的分类名,可获得该类命令的详细清单专业.....gdb命令的分类在gdb提示符处键入help,将列出命基本gdb命令(1/2)file命令:装入想要调试的可执行文件。cd命令:改变工作目录。pwd命令:返回当前工作目录。run命令:执行当前被调试的程序。kill命令:停止正在调试的应用程序。list命令:列出正在调试的应用程序的源代码。break命令:设置断点。watch命令:设置监视点,监视表达式的变化。awatch命令:设置读写监视点。当要监视的表达式被读或写时将应用程序挂起。它的语法与watch命令相同。rwatch命令:设置读监视点,当监视表达式被读时将程序挂起,等侍调试。此命令的语法与watch相同。next命令:执行下一条源代码,但是不进入函数内部。也就是说,将一条函数调用作为一条语句执行。执行这个命令的前提是已经run,开始了代码的执行。专业.....基本gdb命令(1/2)file命令:装入想要调试的可执行文基本gdb命令(2/2)step命令:执行下一条源代码,进入函数内部。如果调用了某个函数,会跳到函数所在的代码中等候一步步执行。执行这个命令的前提是已经用run开始执行代码。display命令:在应用程序每次停止运行时显示表达式的值。infobreak命令:显示当前断点列表,包括每个断点到达的次数16)infofiles命令:显示调试文件的信息。17)infofunc命令:显示所有的函数名。18)infolocal命令:显示当前函数的所有局部变量的信息。19)infoprog命令:显示调试程序的执行状态。20)print命令;显示表达式的值。21)delete命令:删除断点。指定一个断点号码,则删除指定断点。不指定参数则删除所有的断点。22)Shell命令:执行LinuxShell命令。23)make命令:不退出gdb而重新编译生成可执行文件。24)Quit命令:退出gdb。专业.....基本gdb命令(2/2)step命令:执行下一条源代码,进入gdb使用实例(1/2)/*一个有错误的C源程序*/#include<stdio.h>#include<stdlib.h>staticcharbuff[256];staticchar*string;intmain(){printf("Pleaseinputastring:");gets(string);printf("\nYourstringis:%s\n",string);}上面这个程序非常简单,其目的是接受用户的输入,然后将用户的输入打印出来。该程序使用了一个未经过初始化的字符串地址string,因此,编译并运行之后,将出现SegmentFault错误:$gcc-otest-gtest.c$./testPleaseinputastring:asfdSegmentationfault(coredumped)专业.....gdb使用实例(1/2)/*一个有错误的C源程序*gdb使用实例(2/2)为了查找该程序中出现的问题,我们利用gdb,并按如下的步骤进行:1.运行gdbbugging命令,装入bugging可执行文件;2.执行装入的bugging命令;3.使用where命令查看程序出错的地方;4.利用list命令查看调用gets函数附近的代码;5.唯一能够导致gets函数出错的因素就是变量string。用print命令查看string的值;6.在gdb中,我们可以直接修改变量的值,只要将string取一个合法的指针值就可以了,为此,我们在第11行处设置断点;7.程序重新运行到第11行处停止,这时,我们可以用setvariable命令修改string的取值;8.然后继续运行,将看到正确的程序运行结果。专业.....gdb使用实例(2/2)为了查找该程序中出现的问题,我们利GNUmake和makefileGNUmake概述Makefile的基本结构Makefile中的变量GNUmake的主要预定义变量Makefile的隐含规则make命令行选项使用automake和autoconf产生Makefile专业.....GNUmake和makefileGNUmake概述专业GNUmake概述在大型的开发项目中,人们通常利用make工具来自动完成编译工作。这些工作包括:如果仅修改了某几个源文件,则只重新编译这几个源文件;如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。利用这种自动编译可大大简化开发工作,避免不必要的重新编译。实际上,make工具通过一个称为makefile的文件来完成并自动维护编译工作。makefile需要按照某种语法进行编写,其中说明了如何编译各个源文件并连接生成可执行文件,并定义了源文件之间的依赖关系。当修改了其中某个源文件时,如果其他源文件依赖于该文件,则也要重新编译所有依赖该文件的源文件。默认情况下,GNUmake工具在当前工作目录按如下顺序搜索makefile:

GNUmakefilemakefileMakefile专业.....GNUmake概述在大型的开发项目中,人们通常利用makmakefile举例在UNIX中,习惯使用makefile作为makfile文件。Linux程序员使用第三种文件名Makefile。因为第一个字母是大写,通常被列在一个目录的文件列表的最前面。如果要使用其他文件作为makefile,则可利用类似下面的make命令选项指定makefile文件:

$make-fMakefile.debug例1:一个简单的makefile

prog:prog1.oprog2.o

gccprog1.oprog2.o-oprog

prog1.o:prog1.clib.h

gcc-c-I.-oprog1.oprog1.c

prog2.o:prog2.c

gcc-cprog2.c专业.....makefile举例在UNIX中,习惯使用makefileMakefile的基本结构(1/2)Makefile是一个文本形式的数据库文件,其中包含一些规则来告诉make处理哪些文件以及如何处理这些文件。规则主要是描述哪些文件(称为target目标文件,不要和编译时产生的目标文件相混淆)是从哪些别的文件(称为dependency依赖文件)中产生的,以及用什么命令(command)来执行这个过程。依靠这些信息,make会对磁盘上的文件进行检查,如果目标文件的生成或被改动时的时间(称为该文件时间戳)至少比它的一个依赖文件还旧的话,make就执行相应的命令,以更新目标文件。目标文件不一定是最后的可执行文件,可以是任何一个中间文件并可以作为其他目标文件的依赖文件。专业.....Makefile的基本结构(1/2)Makefile是一个Makefile的基本结构(2/2)Makefile规则的一般形式如下:

target:dependencydependency (tab)<command>一个Makefile文件主要含有一系列的规则,每条规则包含以下内容。一个目标(target),即make最终需要创建的文件,如可执行文件和目标文件;目标也可以是要执行的动作,如“clean”。一个或多个依赖文件(dependency)列表,通常是编译目标文件所需要的其他文件。一系列命今(command),是make执行的动作,通常是把指定的相关文件编译成目标文件的编译命令,每个命令占一行,且每个命令行的起始字符必须为TAB字符。除非特别指定,否则make的工作目录就是当前目录。target是需要创建的二进制文件或目标文件,dependency是在创建target时需要用到的一个或多个文件的列表,命令序列是创建target文件所需要执行的步骤,比如编译命令。专业.....Makefile的基本结构(2/2)Makefile规则的Makefile实例(1/3)#以#开头的为注释行test:prog.ocode.o gcc–otestprog.ocode.o

prog.o:prog.cprog.hcode.h gcc–cprog.c–oprog.o

code.o:code.ccode.h gcc–ccode.c–ocode.o

clean:

rm–f*.o上面的Makefile文件中共定义了四个目标:test、prog.o、code.o和clean。目标从每行的最左边开始写,后面跟一个冒号(:),如果有与这个目标有依赖性的其他目标或文件,把它们列在冒号后面,并以空格隔开。然后另起一行开始写实现这个目标的一组命令。在Makefile中,可使用续行号(\)将一个单独的命令行延续成几行。但要注意在续行号(\)后面不能跟任何字符(包括空格和键)专业.....Makefile实例(1/3)#以#开头的为注释行专业.Makefile实例(2/3)一般情况下,调用make命令可输入:#maketargettarget是Makefile文件中定义的目标之一,如果省略target,make就将生成Makefile文件中定义的第一个目标。对于上面Makefile的例子,单独的一个“make”命令等价于:#maketest因为test是Makefile文件中定义的第一个目标,make首先将其读入,然后从第一行开始执行,把第一个目标test作为它的最终目标,所有后面的目标的更新都会影响到test的更新。第一条规则说明只要文件test的时间戳比文件prog.o或code.o中的任何一个旧,下一行的编译命令将会被执行。专业.....Makefile实例(2/3)一般情况下,调用make命令可Makefile实例(3/3)但是,在检查文件prog.o和code.o的时间戳之前,make会在下面的行中寻找以prog.o和code.o为目标的规则,在第三行中找到了关于prog.o的规则,该文件的依赖文件是prog.c、prog.h和code.h。同样,make会在后面的规则行中继续查找这些依赖文件的规则,如果找不到,则开始检查这些依赖文件的时间戳,如果这些文件中任何一个的时间戳比prog.o的新,make将执行“gcc–cprog.c–oprog.o”命令,更新prog.o文件。以同样的方法,接下来对文件code.o做类似的检查,依赖文件是code.c和code.h。当make执行完所有这些套嵌的规则后,make将处理最顶层的test规则。如果关于prog.o和code.o的两个规则中的任何一个被执行,至少其中一个.o目标文件就会比test新,那么就要执行test规则中的命令,因此make去执行gcc命令将prog.o和code.o连接成目标文件test。在上面Makefile的例子中,还定义了一个目标clean,它是Makefile中常用的一种专用目标,即删除所有的目标模块专业.....Makefile实例(3/3)但是,在检查文件prog.o和make的工作过程现在来看一下make做的工作:首先make按顺序读取makefile中的规则,然后检查该规则中的依赖文件与目标文件的时间戳哪个更新如果目标文件的时问戳比依赖文件还早,就按规则中定义的命令更新目标文件。如果该规则中的依赖文件又是其他规则中的目标文件,那么依照规则链不断执行这个过程,直到Makefile文件的结束,至少可以找到一个不是规则生成的最终依赖文件,获得此文件的时间戳然后从下到上依照规则链执行目标文件的时间戳比此文件时间戳旧的规则,直到最顶层的规则通过以上的分析过程,可以看到make的优点,因为.o目标文件依赖.c源文件,源码文件里一个简单改变都会造成那个文件被重新编译,并根据规则链依次由下到上执行编译过程,直到最终的可执行文件被重新连接。例如,当改变一个头文件的时候,由于所有的依赖关系都在Makefile里,因此不再需要记住依赖此头文件的所有源码文件,make可以自动的重新编译所有那些因依赖这个头文件而改变了的源码文件,如果需要,再进行重新连接专业.....make的工作过程现在来看一下make做的工作:专业..Makefile中的变量Makefile里的变量就像一个环境变量。事实上,环境变量在make中也被解释成make的变量。这些变量对大小写敏感,一般使用大写宇母。几乎可以从任何地方引用定义的变量,变量的主要作用如下:保存文件名列表。在前面的例子里,作为依赖文件的一些目标文件名出现在可执行文件的规则中,而在这个规则的命令行里同样包含这些文件并传递给gcc做为命令参数。如果使用一个变量来保存所有的目标文件名,则可以方便地加入新的目标文件而且不易出错。保存可执行命令名,如编译器。在不同的Linux系统中存在着很多相似的编译器系统,这些系统在某些地方会有细微的差别,如果项目被用在一个非gcc的系统里,则必须将所有出现编译器名的地方改成用新的编译器名。但是如果使用一个变量来代替编译器名,那么只需要改变该变量的值。其他所有地方的命令名就都改变了。保存编译器的参数。在很多源代码编译时,gcc需要很长的参数选项,在很多情况下,所有的编译命令使用一组相同的选项,如果把这组选项使用一个变量代表,那么可以把这个变量放在所有引用编译器的地方。当要改变选项的时候,只需改变一次这个变量的内容即可。专业.....Makefile中的变量Makefile里的变量就像一个环境变量的定义和使用Makefile中的变量是用一个文本串在Makefile中定义的,这个文本串就是变量的值。只要在一行的开始写下这个变量的名字,后面跟一个“=”号,以及要设定这个变量的值即可定义变量,下面是定义变量的语法:

VARNAME=string使用时,把变量用括号括起来,并在前面加上$符号,就可以引用变量的值:

${VARNAME}make解释规则时,VARNAME在等式右端展开为定义它的字符串。变量一般都在Makefile的头部定义。按照惯例,所有的Makefile变量都应该是大写。如果变量的值发生变化,就只需要在一个地方修改,从而简化了Makefile的维护。专业.....变量的定义和使用Makefile中的变量是用一个文本串在MaMakefile变量举例现在利用变量把前面的Makefile重写一遍:OBJS=prog.ocode.oCC=gcc

test:${OBJS} ${CC}–otest${OBJS}

prog.o:prog.cprog.hcode.h ${CC}–cprog.c–oprog.o

code.o:code.ccode.h ${CC}–ccode.c–ocode.o

clean:

rm–f*.o专业.....Makefile变量举例现在利用变量把前面的Makefile变量的类型除用户自定义的变量外,make还允许使用环境变量使用环境变量的方法很简单,在make启动时,make读取系统当前已定义的环境变量,并且创建与之同名同值的变量,因此用户可以像在shell中一样在Makefile中方便的引用环境变量。需要注意的是,如果用户在Makefile中定义了同名的变量,用户自定义变量将覆盖同名的环境变量自动变量预定义变量专业.....变量的类型除用户自定义的变量外,make还允许使用专业..GNUmake的主要预定义变量(1/2)$*不包含扩展名的目标文件名称。$+所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件。$<第一个依赖文件的名称。$?所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚。$@目标的完整名称。$^所有的依赖文件,以空格分开,不包含重复的依赖文件。$%如果目标是归档成员,则该变量表示目标的归档成员名称。例如,如果目标名称为mytarget.so(image.o),则$@为mytarget.so,而$%为image.o。AR归档维护程序的名称,默认值为ar。ARFLAGS归档维护程序的选项。AS汇编程序的名称,默认值为as。ASFLAGS汇编程序的选项。专业.....GNUmake的主要预定义变量(1/2)$*GNUmake的主要预定义变量(2/2)CCC编译器的名称,默认值为cc。CFLAGSC编译器的选项。CPPC预编译器的名称,默认值为$(CC)-E。CPPFLAGSC预编译的选项。CXXC++编译器的名称,默认值为g++。CXXFLAGSC++编译器的选项。FCFORTRAN编译器的名称,默认值为f77。FFLAGSFORTRAN编译器的选项。专业.....GNUmake的主要预定义变量(2/2)CCCMakefile的隐含规则在上面的例子中,几个产生目标文件的命令都是从“.c”的C语言源文件和相关文件通过编译产生“.o”目标文件,这也是一般的步骤。实际上,make可以使工作更加自动化,也就是说,make知道一些默认的动作,它有一些称作隐含规则的内置的规则,这些规则告诉make当用户没有完整地给出某些命令的时候,应该怎样执行。例如,把生成prog.o和code.o的命令从规则中删除,make将会查找隐含规则,然后会找到并执行一个适当的命令。由于这些命令会使用一些变量,因此可以通过改变这些变量来定制make。象在前面的例子中所定义的那样,make使用变量CC来定义编译器,并且传递变量CFLAGS(编译器参数)、CPPFLAGS(C语言预处理器参数)、TARGET_ARCH(目标机器的结构定义)给编译器,然后加上参数-c,后面跟变量$<(第一个依赖文件名),然后是参数-o加变量$@(目标文件名)。综上所述,一个C编译的具体命令将会是:

${CC}${CFLAGS}${CPPFLAGS}${TARGET_ARCH}–c$<-o$@专业.....Makefile的隐含规则在上面的例子中,几个产生目标文隐含规则举例在上面的例子中,利用隐含规则,可以简化为:OBJS=prog.ocode.oCC=gcctest:${OBJS} ${CC}–o$@$^

prog.o:prog.cprog.hcode.hcode.o:code.ccode.h

clean:

rm–f*.o专业.....隐含规则举例在上面的例子中,利用隐含规则,可以简化为:专业make命令行选项直接在make命令的后面键入目标名可建立指定的目标,如果直接运行make,则建立第一个目标。还可以用make-fmymakefile这样的命令指定make使用特定的makefile,而不是默认的GNUmakefile、makefile或Makefile。GNUmake命令还有一些其他选项,下面是GNUmake命令的常用命令行选项命令行选项含义:-CDIR在读取makefile之前改变到指定的目录DIR。-fFILE以指定的FILE文件作为makefile。-h显示所有的make选项。-i忽略所有的命令执行错误。-IDIR当包含其他makefile文件时,可利用该选项指定搜索目录。-n只打印要执行的命令,但不执行这些命令。-p显示make变量数据库和隐含规则。-s在执行命令时不显示命令。-w在处理makefile之前和之后,显示工作目录。-WFILE假定文件FILE已经被修改。专业.....make命令行选项直接在make命令的后面键入目标名可使用automake和autoconf产生Makefile在开始使用Automake和autoconf之前,请先确认系统已经安装以下的软件:GNUAutomakeGNUAutoconfGNUm4PerlGNULibtool(如果你需要产生sharedlibrary)Automake所产生的Makefile除了可以做到程序的编译和连接,也已经把如何产生程序文件的操作,以及把安装程序都考虑进去了,所以源程序所存放的目录架构最好符合GNU的标准惯例,下面用hello.c来作为例子进行说明。专业.....使用automake和autoconf产生Makefile生成一个源程序在工作目录下建立一个新的子目录devel,再在devel下建立一个hello的子目录,这个目录将作为存放hello这个程序及其相关文件的地方:用编辑器写个hello.c文件:#include<stdio.h>intmain(intargc,char**argv){printf("Hello,GNU!\n");return0;}专业.....生成一个源程序在工作目录下建立一个新的子目录devel,再在使用Autoconf及Automake来产生Makefile文件的步骤autoscan产生一个configure.in的模板,执行autoscan后会产生一个configure.scan的文件,可以用它做为configure.in文件的模板:编辑configure.scan文件,如下所示,并且把文件名改成configure.in执行aclocal和autoconf,分别会产生aclocal.m4及configure两个文件:编辑Makefile.am文件,内容如下:执行automake--add-missing,Automake会根据Makefile.am产生一些文件,包含最重要的Makefile.in:最后执行./configure专业.....使用Autoconf及Automake来产生Make使用RCS/CVS来管理源代码RCS的使用CVS的使用专业.....使用RCS/CVS来管理源代码RCS的使用专业..RCS的使用RCS(RevisionControlSystem)即程序改版控制系统,主要功能是用来管理文件的版本,可以节省空间和时间。这样就不需要在每个程序开发到某一个阶段就将数据拷贝到其他的地方备份起来了。RCS提供了如下几个最重要的指令的:ci指令:将文件放入RCS目录下的控制系统co指令:从RCS目录下将文件取出rcs指令:用来对RCS文件进行参数的设置专业.....RCS的使用RCS(RevisionControlSy基本操作方式一般而言,RCS所产生出来的文件会放在RCS目录中。所以第一步必须要在当前的目录下制作一个文件:

[root@wyhlinux]#mkdirRCS接下来只要使用ci指令。就可以把文件备份到RCS改版控制系统中:

[root@wyhlinux]#citest.c若要将文件取出,可以使用下列指令:

[root@wyhlinux]#cotest.c取出来的文件是只读文件,若要取出可以写入的工作文件,可以加上-l参数来锁定它:

[root@wyhlinux]#co-ltest.c此外将文件放入RCS控制系统时,可以使用-l参数锁定文件,那么目录下的文件依然存在:

[root@wyhlinux]#ci-ltest.c

若要比较当前的文件和RCS中最新版本的文件,可以使用下列指令:

[root@wyhlinux]#rcsdifftest.c专业.....基本操作方式一般而言,RCS所产生出来的文件会放在RCS目指定版本若不指定版本编号时,co会从RCS取得最新的版本。如果要以特定的版本号码写入RCS或读出,可以使用-r参数选项。[root@wyhlinux]#ci-l-r3.25test.c<--以3.25作为版本编号[root@wyhlinux]#co-l-r1.2test.c <--将RCS中1.2版的test.c读出此外,rcsdiff也可以用来指定任何一个版本和当前程序代码进行比较。[root@wyhlinux]#rcsdiff-r3.25test.c <--取出3.25版与test.c进行比较专业.....指定版本若不指定版本编号时,co会从RCS取得最新的版本。关键词的使用在RCS中可以将关键词变量放入程序代码中。这些变量经过RCS会变成版本的注解。用户可以将这些关键词说明当作

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论