嵌入式系统原理与应用 课件 第9章 Linux下程序设计工具_第1页
嵌入式系统原理与应用 课件 第9章 Linux下程序设计工具_第2页
嵌入式系统原理与应用 课件 第9章 Linux下程序设计工具_第3页
嵌入式系统原理与应用 课件 第9章 Linux下程序设计工具_第4页
嵌入式系统原理与应用 课件 第9章 Linux下程序设计工具_第5页
已阅读5页,还剩70页未读 继续免费阅读

下载本文档

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

文档简介

嵌入式系统原理与设计第9章Linux下程序设计工具第XX章0102030405Vi编辑器GCC编译器GDB调试Make项目管理器Makefile编程/01Vi编辑器Vi编辑器图形界面编辑器的代表是gedit文本界面编辑器的代表是Vi,它没有采用图形界面,因而运行效率很高,缺点在于需要记住众多的命令。Linux下的编辑器可以分为图形界面编辑器和文本界面编辑器。Vi的启动与退出启动:在Linux终端命令提示符下输入vi(或vi文件名),即可启动vi编辑器。#vifilename退出:要退出Vi,必须先按“Esc”键回到命令行模式,然后输入“:”,此时光标会停留在最下面一行(底行模式),再输入“q”,最后按“Enter”键即可退出。Vi工作模式Vi工作模式命令行模式:也叫做“普通模式”,它是启动Vi编辑器后的初始模式。在该模式下主要是使用隐式命令(命令不显示)来实现光标的移动、复制、粘贴、删除等操作。在该模式下,编辑器并不接受用户从键盘输入的任何字符作为文档的编辑内容。插入模式:在该模式下,用户输入的任何字符都被认为是编辑到文件中的内容,并直接显示在Vi的文本编辑区。底行模式:在该模式下,用户输入的任何字符都会在Vi的最下面一行显示,按“Enter”键后便会执行该命令(当然前提是输入的命令正确)。Vi使用实例练习参考教材中三种模式的常用命令,编辑源代码并将其命名为vi_test.c/*vi_test.c*/#include<stdio.h>intmax(inta,intb);main(){inta,b;printf("Enterab:");scanf("%d%d",&a,&b);printf("max=%d\n",max(a,b));}intmax(inta,intb){intp;p=a>b?a:b;return(p);}Vi使用实例练习在编辑完vi_test.c后完成以下操作:(1)为了方便查看代码,在Vi编辑器中显示行号(2)将第5-8行的内容复制到第8行行首(3)删除此时光标所在行(4)将源代码每行的第一个字符“i”替换成字符“n”。(5)撤销上一步操作/02GCC编译器GCC编译器GCC全称是GNUCCompiler,它是GNU组织推出的符合ANSIC标准的功能强大、性能优越的多平台编译器。经过几十年的发展,GCC已经成为Linux下最重要的免费软件开发工具,它不仅支持C语言,还支持C++语言、Java语言、Objective语言、Ada语言、Pascal语言、COBOL语言等。因此,GCC也被成为GNU编译器集合。此外,GCC还是一个交叉平台编译器GCC编译器交叉编译器:在一个CPU平台上编译另一个CPU平台的程序,这两个CPU平台的指令体系结构不一样GCC目前支持所有主流CPU平台,可以完成从C、C++、Java等源文件向运行在特定CPU硬件平台上的目标代码的转换。GCC编译器所能支持的部分源程序的格式后缀名所对应语言后缀名所对应语言.cC语言源程序.s/.S汇编语言源程序.C/.cc/.cxxC++源程序.h预处理文件(头文件).mObjective-C源程序.o目标文件.i已经经过预处理的C程序.a/.so编译后的文件.ii已经经过预处理的C++程序

GCC编译流程预处理(Pre-Processing)编译(Compiling)汇编(Assembling)链接(Linking)GCC编译流程下面以一个简单的“Hello,World”实例程序来说明,/*hello.c*/#include<stdio.h>intmain(){printf("Hello!Thisisourembeddedworld!\n");return0;}return(p);}预处理阶段预处理阶段主要完成3个功能:1)将源文件中以“#include”格式包含的文件复制到编译的源文件中;2)用实际值替换用“#define”定义的字符串;3)根据“#if”后面的条件确定实际需要编译的源代码。注:实例代码中仅需将stdio.h复制到源文件预处理阶段GCC中,“-E”选项用来指示仅做预处理,预处理结束后停止编译过程。[root@localhostgcc]#gcc–Ehello.c–ohello.i在上面命令中,选项“-o”用来指定输出的目标文件名称,“hello.i”为已经过预处理的C源程序typedefint(*__gconv_trans_fct)(struct__gconv_step*,struct__gconv_step_data*,void*,__constunsignedchar*,__constunsignedchar**,__constunsignedchar*,unsignedchar**,size_t*);…#2"hello.c"2intmain(){printf("Hello!Thisisourembeddedworld!n");return0;}编译阶段在编译阶段,GCC首先要检查经过预处理后的源代码的规范性(是否有语法错误等),检查无误后再把源代码翻译成目标CPU平台的汇编语言。[root@localhostgcc]#gcc–Shello.i–ohello.sGCC中,“-S”选项用来指示仅做编译、生成汇编代码,汇编代码生成后结束编译过程。编译阶段.file"hello.c".section.rodata.align4.LC0:.string"Hello!Thisisourembeddedworld!".text.globlmain.typemain,@functionmain:push1%ebpmovl%esp,%ebpsubl$8,%espandl$-16,%espmovl$0,%eaxaddl$15,%eaxaddl$15,%eaxshrl$4,%eaxsall$4,%eaxsubl%eax,%espsubl$12,%esppushl$.LC0callputsaddl$16,%espmovl$0,%eaxleaveret.sizemain,.-main.ident"GCC:(GNU)4.0.020050519(RedHat4.0.0-8)".section.note.GNU-stack,"",@progbits汇编阶段汇编阶段是把编译阶段生成的“.s”文件转成目标文件。GCC中,可以使用选项“-c”将汇编代码转化为以“.o”结尾的二进制目标代码。[root@localhostgcc#gcc–chello.s–ohello.o注:由于hello.o为二进制文件,不能用文本编辑器打开;如果用文本编辑器强制打开,显示为一堆乱码。链接阶段上面生成的hello.o并没有定义“printf”函数的实现,而预编译中包含进的“stdio.h”中也只有该函数的声明,无该函数的实现。那么,是在哪里实现“printf”函数的呢?通俗的讲,链接就是找到函数的实现处,也就是函数库。而函数库按时间、空间需求可分为静态库与动态库链接阶段静态库:指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件,其后缀名一般为“.a”。(“以空间换时间”)动态库:在链接时并没有把库文件的代码加入到可执行文件中,因而生成的文件比较小,但在程序执行时需要动态加载库文件的代码,其后缀名一般为“.so”。(“以时间换空间”)链接阶段在GCC中,“printf”函数实现被放到名为“libc.so.6”的库文件中,它是一个动态库。在没有特别指定时,GCC会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到libc.so.6库函数中去,这样就能实现函数“printf”,而这也就是链接的作用。GCC编译实际源程序编译过程中,不需要分步运行上述命令来生成可执行文件,可以利用下面命令一步到位,生成可执行文件hello。[root@localhostgcc]#gcc–Shello.i–ohello.s运行生成的可执行文件hello,得到运行结果:[root@localhostgcc]#./helloHello!Thisisourembeddedworld!常用的GCC编译选项选项含义-E只进行预编译,不做其他处理-c只编译不链接,生成目标文件“.o”-S只编译不汇编,生成汇编代码-ofile指定输出文件名称为file-g在可执行程序中包含标准调试信息-v打印出编译器内部编译各过程的命令行信息和编译器的版本-Idir在头文件的搜索路径列表中添加dir目录-Ldir在库文件的搜索路径列表中添加dir目录-static链接静态库-llibrary链接名为library的库文件告警和出错辅助选项选项含义-ansi支持符合ANSI标准的C程序-pedantic允许发出ANSIC标准所列的全部警告信息-pedantic-error允许发出ANSIC标准所列的全部错误信息-w关闭所有告警-Wall允许发出GCC提供的所有有用的报警信息-werror把所有的告警信息转化为错误信息,并在告警发生时终止编译过程/03Gdb调试器Gdb调试Linux下C程序开发主要用到的调试工具是Gdb调试器。Gdb是一款由GNU开发并发布的自由软件,是UNIX/Linux下的功能强大的程序调试工具。虽然,它没有图形化的友好界面,但是它强大的功能也足以与微软的VC工具等媲美。一般来说,Gdb主要提供以下功能:(1)设置断点(可以是条件表达式),使程序在指定的代码上暂停执行。(2)单步执行程序,便于调试。(3)查看程序中变量值的变化。(4)动态改变程序执行环境。(5)分析崩溃产生的core文件。Gdb的调用Gdb的使用非常简单,只要在Linux的命令提示符下输入gdb,系统便会启动Gdb,并打印出Gdb的相关信息。也可以在gdb后面给出文件名,直接指定想要测试的程序,Gdb就会自动调用这个可执行文件进行调试,命令格式如下:注:为了使Gdb正常工作,程序在编译的时候必须包含调试信息,这需要在GCC编译时加上-g或者-ggdb选项。[root@localhostGdb]#gdbGNUgdb(Ubuntu7.11.1-0ubuntu1~16.5)7.11.1Copyright(C)2016FreeSoftwareFoundation,Inc.LicenseGPLv3+:GNUGPLversion3orlater<http:gnu="gnu">Thisisfreesoftware:youarefreetochangeandredistributeit.ThereisNOWARRANTY,totheextentpermittedbylaw.Type"showcopying"and"showwarranty"fordetails.ThisGDBwasconfiguredas"x86_64-linux-gnu".Type"showconfiguration"forconfigurationdetails.Forbugreportinginstructions,pleasesee:<http:///software/gdb/bugs/>.FindtheGDBmanualandotherdocumentationresourcesonlineat:<http:///software/gdb/documentation/>.Forhelp,type"help".Type"aproposword"tosearchforcommandsrelatedto"word".(gdb)·[root@localhostGdb]#gdbfilenameGdb的常用命令命令含义file装入想要调试的可执行文件run执行当前被调试的程序kill终止正在调试的程序step执行下一行源代码并且进入函数内部next执行下一行内容但不进入函数内部break在代码里设置断点,这将是程序执行到这里被挂起print打印表达式或者变量的值,或打印内存中某个变量开始的一段连续区域的值,还可以用来对变量进行赋值display设置自动显示表达式或变量,当程序停住或在单步跟踪时,这些变量将会自动显示其当前值list列出产生执行文件的源代码的一部分quit退出Gdbwatch监视一个变量的值而不论它何时改变backtrace回溯跟踪framen定位到发生错误的代码段,n为backtrace命令输出结果中的行号examine查看内存地址中的值jump使程序跳转执行signal产生信号量return强制函数返回call强制调用函数make使用户不退出Gdb就可以重新产生可执行文件shell使用户不离开Gdb就执行Linux的shell命令Gdb简单调试实例以一个简单的例子来介绍Gdb调试器的使用,其源代码如下:/*simple_gdb.c*/#include<stdio.h>intmain(void){intinput=0;printf("输入一个整数:");

scanf("%d",input);/*这里出现了错误*/printf("输入的整数是:%d\n",input);return0;}Gdb简单调试实例首先使用GCC对simple_gdb.c进行编译,注意一定要加上“-g”或“-ggdb”调试选项,这样编译出的可执行代码中才包含调试信息,否则之后Gdb无法载入该可执行文件。[root@localhostGdb]#gcc-ggdb3simple_gdb.c-osimple_gdb注:-g3包含一些额外信息,例如包含宏定义信息。当需要调试宏定义时,请使用-g3。Gdb简单调试实例先运行生存的文件simple_gdb,发现发生了段错误,信息如下:[root@localhostGdb]#./simple_gdb输入一个整数:1024段错误(核心已转储)为了更快发现错误所在,现在使用Gdb进行跟踪测试,命令如下:[root@localhostGdb]#gdb./simple_gdbGNUgdb(Ubuntu7.11.1-0ubuntu1~16.5)7.11.1……(gdb)当提示符(gdb)出现的时候,表明调试器已经做好准备进行调试了,现在可以通过run命令让程序在Gdb监控下运行:Gdb简单调试实例(gdb)runStartingprogram:/home/user/simple_gdb输入一个整数:1024ProgramreceivedsignalSIGSEGV,Segmentationfault.0x00007ffff7a6cde5in_IO_vfscanf_internal(s=<optimizedout="out">,format=<optimizedout="out">,argptr=argptr@entry=0x7fffffffddc8,errp=errp@entry=0x0)atvfscanf.c:19021902 vfscanf.c:没有那个文件或目录.程序是由于段错误而导致异常终止的,说明内存操作出了问题,具体发生问题的地方是在调用_IO_vfscanf_internal(…)的时候。Gdb简单调试实例为了得到更有价值的信息,可以使用Gdb提供的问题回溯跟踪命令backtrace,执行结果如下:(gdb)backtrace#00x00007ffff7a6cde5in_IO_vfscanf_internal(s=<optimizedout="out">,format=<optimizedout="out">,argptr=argptr@entry=0x7fffffffddc8,errp=errp@entry=0x0)atvfscanf.c:1902#10x00007ffff7a785dfin__isoc99_scanf(format=<optimizedout="out">)atisoc99_scanf.c:37#20x00000000004005c8inmain()atsimple_gdb.c:7可以明显在输出结果#2后发现,Gdb已经将错误定位到simple_gdb.c中的第7行了。Gdb简单调试实例使用Gdb的frame命令可以定位到发生错误的代码段,该命令后面跟着的数值可以在backtrace命令输出结果中的行首找到。(gdb)frame2#20x00000000004005c8inmain()atsimple_gdb.c:77 scanf("%d",input); /*这里出现了错误*/现在已经发现错误所在了,很明显,应该将scanf("%d",input)改为scanf("%d",&input),这样就完成了程序的调试,然后可以退出Gdb:(gdb)quit断点使用命令含义break<function>在进入指定函数时停住break<linenum>在指定行号停住break+offset在当前行号前面的offset行停住,offset为自然数break-offset在当前行号后面的offset行停住,offset为自然数breakfilename:function在源文件filename的function函数入口停住breakfilename:linenum在源文件filename的linenum行停住break*address在程序运行的地址处停住。地址,可以是函数、变量的地址,此地址可以通过infoadd命令得到break该命令没有参数时,表示在下一条指令停住break…if<condition>condition表示条件,在条件成立时停住。例:breakifi=100,表示当i为100时停住程序查看源代码命令含义list<function>显示名为function的函数的源程序list<linenum>显示名第linenum行周围的源程序list显示当前行后面的程序list-显示当前行前面的源程序setlistsize<count>设置一次显示代码的行数showlistsize查看当前listsize的设置list<first>,<last>显示从first行到last行之间的代码list,<last>显示当前行到last行之间的代码list+向后显示代码/04Make项目管理器Make概述在Linux下进行程序开发,一般不具有集成开发环境(IDE)。因此,当需要大量编译工程文件时,就需要用自己的方法来管理。当GCC在编译一个包含许多源文件的工程时,GCC需要将其中每个源文件都编译一遍,然后再全部链接起来。这样做显然非常浪费时间,尤其是当用户只修改了其中某一个文件,完全没有必要将每个文件都编译一遍Linux下,通过Make工程管理器和Makefile脚本文件,提供了一种非常简单有效的工程管理方式。这种管理方式的核心是用Make工具按Makefile脚本文件所描述的方式进行程序编译和目标代码生成。这里面,Makefile是一个决定怎样编译工程的脚本文件,有自己的编程规则,需要程序员自己开发。Make简单实例下面通过一个简单的例子来向读者说明Make的工作机制:/****************************main.c****************************/#include<stdio.h>intmain(void){charc;charstr[20];enter_string(str);/*调用字符串输入函数*/printf("Thedeletestringis:");scanf("%c",&c);delete_string(str,c);/*调用字符删除函数*/print_string(str);/*打印处理后的字符串*/return0;}/**************************enter_string.c************************/#include<stdio.h>intenter_string(charstr[20]){printf("Inputthestrings:");gets(str);return0;}/**************************delete_string.c***********************/#include<stdio.h>intdelete_string(charstr[],charch){inti,j;for(i=j=0;str[i]!='\0';i++)if(str[i]!=ch)str[j++]=str[i];str[j]='\0';return0;}/**************************print_string.c************************/#include<stdio.h>intprint_string(charstr[]){printf("Result:%s\n",str);return0;}Make简单实例为了演示Make工具编译多个源程序文件的使用方法,可将上述程序分成4个C源文件,分别为main.c、enter_string.c、delete_string.c、print_string.c。不同的C文件负责完成不同的功能模块:main.c:主函数,主要是对各个模块的调用;enter_string.c:实现字符串的输入;delete_string.c:负责删除字符串中某些特殊字符;print_string.c:输出处理后的字符串。Make简单实例为了使用Make工具管理这些源文件,实现自动编译,需要对应的Makefile文件:Myprog:main.oenter_string.odelete_string.oprint_string.o gccmain.oenter_string.odelete_string.oprint_string.o-oMyprogmain.o:main.c gcc-cmain.c-omain.oenter_string.o:enter_string.c gcc-center_string.c–oenter_string.odelete_string.o:delete_string.c gcc-cdelete_string.c–odelete_string.oprint_string.o:print_string.c gcc-cprint_string.c–oprint_string.oclean: rmMyprog*.oMake简单实例#makegcc-cmain.c-omain.ogcc-center_string.c-oenter_string.ogcc-cdelete_string.c-odelete_string.ogcc-cprint_string.c-oprint_string.ogccmain.oenter_string.odelete_string.oprint_string.o-oMyprogMake自动执行了Makefile中的编译命令,并生成了最终可执行文件Myprog。运行该文件,得到如下结果:#./MyprogInputthestrings:abcdcjdscseThedeletestringis:cResult:abdjdsseMake与Makefile的关系Make是一个Linux下的二进制程序,用来处理Makefile脚本文件。在Linux的Shell命令行键入make命令后,启动Make程序。Make程序自动寻找当前目录下名称为“Makefile”或“makefile”的脚本文件。具体来说,Make工具的使用格式为:make{options}{target}…options为Make工具的参数选项,target为Makefile中指定的目标,缺省时执行Makefile中的第一个目标。Make工具参数选项选项含义-ffilename显式地指定文件作为Makefile-Cdirname指定Make在开始运行后的工作目录为dirname-e不允许在Makefile中个替换环境变量的赋值-k执行命令出错时,放弃当前目标,继续维护其他目标-n只打印要执行的命令,但不执行这些命令-p显示Makefile中所有的变量和内部规则-r忽略内部原则-s执行但不显示命令,常用来检查Makefile的正确性-S如果执行命令出错就退出-t修改每个目标文件的创建日期-I忽略运行Make-V显示Make版本号/05Makefile编程Makefile编程规则基本规则Target:dependencies commandTarget:目标名,可以是可执行文件名、目标文件名或者标签。图9.3中的简单Makefile文件中Myprog是一个可执行文件名,main.o是一个目标文件名,clean是一个标签。dependencies:依赖文件,即生成目标所需要的文件或目标,如果有多个目标或文件,中间以空格分开。当然,也可以没有此项,如图9.3中的clean目标,它就无依赖文件。command:make需要执行的命令,可以为任意的shell命令,command必须以“Tab”键开头。同样,command也不是必须要有的,可以用后面讲的隐含规则由make自动推导出。Makefile编程规则以上述简单Makefile为例Myprog:main.oenter_string.odelete_string.oprint_string.o gccmain.oenter_string.odelete_string.oprint_string.o-oMyprog这两行就构成了一个基本规则,Myprog是目标名,它实质是一个可执行文件名,其依赖于main.o、enter_string.o、delete_string.o和print_string.o这四个目标文件,而第二行的命令则给出了Myprog的生成方法。Makefile编程规则基本规则中的特例(伪目标)clean: rmMyprog*.o这两行也构成一个基本规则,clean仅是一个标签,它不需要Make生成一个clean文件;此外,clean后面也没有依赖文件,所以Make无法根据依赖关系决定其后的命令是否需要执行。Makefile编程规则伪目标Make工具遇到伪目标后一般都会执行其后的命令。为避免伪目标与真实的文件名发生冲突,比如当前Makefile文件所在目录下有一个clean文件,可以在Makefile中使用一个特殊的标记“.PHONY”来显式地指明一个目标为伪目标,即不管是否有这个文件,这个目标都是伪目标。.PHONY:cleanclean: rm-fMyprog*.oMakefile常用伪目标伪目标用途all这个伪目标是所有目标的目标,其功能一般是编译所有的目标。clean删除所有被make创建的文件。install安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目标中去。print输出改变过的源文件。tar把源程序打包备份,生成一个tar文件。dist创建一个压缩文件,一般是把tar文件压成Z文件或是gz文件。TAGS更新所有的目标,以备完整地重编译使用。check/test这两个伪目标一般用来测试makefile的流程Makefile编程规则模式规则<targets...>:<target-pattern>:<dependency-pattern...><command>Makefile脚本中另外一种常用的规则是模式规则。模式规则与一般的规则类似,只是在模式规则中的目标模式定义中需要用到“%”字符。“%”字符代表对文件名的匹配,表示任意长度的非空字符串。在依赖目标中同样要使用“%”,但依赖目标中“%”的取值取决于目标。targets定义了一系列的目标,可以有通配符,是目标的集合;target-pattern是指明了目标集合的模式。dependency-pattern是目标集合的依赖模式,它对target-pattern形成的模式再进行一次依赖目标的定义。Makefile编程规则仍以上述简单Makefile中第2-5个规则为例,采用模式规则后可简化为第1行代码定义了一个用户变量objects,其值为“main.oenter_string.odelete_string.oprint_string.o”。第2、3行代码定义了一个模式规则。第2行代码的$(objects)给出目标集合,“%.o:%.c”给出所有以“.o”结尾的目标文件依赖对应的以“.c”结尾的文件,如main.o依赖于main.c。第3行代码给出生成命令,命令中的“$<”和“$@”是自动化变量,“$<”表示所有的依赖目标集(main.center_string.cdelete_string.cprint_string.c),“$@”表示目标集(main.oenter_string.odelete_string.oprint_string.o)。objects=main.oenter_string.odelete_string.oprint_string.o$(objects):%.o:%.c gcc-c$<-o$@Makefile编程规则隐式规则objects=main.oenter_string.odelete_string.oprint_string.oMyprog:$(objects) gcc$(objects)-oMyprogclean: rmMyprog*.oMake工具具有自动推导功能,一些约定俗成的规则就不需要显示指定,这些规则就称为隐式规则。采用隐式规则后,可以简化Makefile文件。以上述Makefile为例,可等价为:www.islide.cc55CC=gccRM=rm-rf##debugflagDBG_ENABLE=0##sourcefilepathSRC_PATH:=.##targetexecfilenameTARGET:=Myprog##getallsourcefilesSRCS+=$(wildcard*.c)##all.obasedonall.cOBJS:=$(SRCS:.c=.o)##usedheadersfilepathINCLUDE_PATH:=.##debugfordebuginfo,whenusegdbtodebugifeq(1,${DBG_ENABLE}) CFLAGS=-gelse CFLAGS=-O3endif$(TARGET):$(OBJS) $(CC)$(CFLAGS)$(OBJS)-o$(TARGET)clean: $(RM)$(OBJS)$(TARGET)all:cleanbuild一个比较通用的MakefileMakefile变量变量命名变量的命名可以包含字符、数字、下划线(可以是数字开头),但不能含有“:”、“#”、“=”或者空字符(如空格、回车等)。变量大小写敏感,如“foo”、“FOO”、和“Foo”代表不同的变量。推荐在Makefile使用大小写字母搭配作为变量名,预留大写字母作为控制隐含规则参数或用户重载命令选项参数的变量名。变量在声明时需要给予初值,而在使用时,需要在变量名前加上“$”符号,但最好用“()”或者是“{}”把变量引起来。如果需要使用真实的“$”字符,那么需要用“$$”来表示。Makefile变量变量赋值最基本的变量赋值方式就是使用“=”直接给变量赋值,同时,Makefile还支持变量的嵌套定义。例如:foo=$(bar)bar=$(ugh)ugh=Huh?all: echo$(foo)foo的值是$(bar),$(bar)的值是$(ugh),$(ugh)的值是“Huh?”,故执行“makeall”后会输出$(foo)的值“Huh?”Makefile变量变量赋值上述示例中,第一次定义foo这个变量时,bar这个变量还未定义,即变量可以使用后面的变量来定义。这种形式的变量定义的优点在于方便,弊端在于可能会造成递归定义,如下面的变量定义:A=$(B)B=$(A)Makefile变量变量赋值当然,Make有能力检测出这样的定义,并会报错。但是为了避免上面这种问题,Make定义了“:=”这种变量赋值方法,使用“:=”赋值符,可以使得前面的变量不能使用后面的变量,例如:x:=fooy:=$(x)barx:=later其等价于:y:=foobarx:=laterMakefile变量变量赋值还有一个很有用的变量赋值操作符是“?=”,其含义是,如果变量FOO没有被定义时,那么变量FOO的值就是“bar”,但是FOO先前被定义过,那么这条语句将什么也不做。一种赋值操作符是“+=”,它实质是对变量追加值,如:于是objects值变为“main.oenter_string.odelete_string.oprint_string.o”。objects=main.oenter_string.odelete_string.oobjects+=print_string.oMakefile变量自动化变量自动化变量是一类特殊的变量,其值是Make工具根据上下文自动推理得到,一般出现在规则的命令语句中,它属于局部变量,在不同的规则中有不同的取值。变量含义$@表示规则中的目标文件。在模式规则中如果有多个目标,“$@”就是匹配于目标模式定义的集合。$%仅当目标是库函数文件时,表示规则中的目标的成员名。例如,如果一个目标是“foo.a(bar.o)”,那么,“$%”就是“bar.o”,“$@”就是“foo.a”。如果目标不是函数库文件,那么,“$%”值为空。$<表示规则中的第一个依赖目标,如果依赖目标是以模式(即“%”)定义的,则“$<”是符合模式的一系列的目标文件集合。$?所有比目标新的依赖目标的集合,以空格分开。$^所有依赖目标的集合,以空格分隔。如果在依赖目标有多个重复的,则自动去除重复的依赖目标。$+同“$^”,只是不清除重复的依赖文件。$*目标模式中“%”及其之前的部分Makefile变量自动化变量分析下面Makefile脚本中的自动化变量的值main.o:main.cmain.h gcc$<-o$@enter_string.o:enter_string.cstdio.h gcc$<-o$@第一个规则里面,“$<”和“$@”分别代表main.c和main.o;在第二个规则里面,“$<”和“$@”分别代表enter_string.c和enter_string.o。Makefile高级编程使用各种关键字关键字用法@该关键字用于命令前,使用@可以避免显示出命令本身override如果一个变量的值需要在编译选项中指定或由系统传入,那么makefile中可以使用override关键字来设置,使这个变量的赋值被忽略define使用define关键字可以定义多行变量,结束有对应关键字endefwildcard让通配符(主要是“*”)在变量或函数中展开,通常用于提取指定目录的某一类型文件。export将变量导出,以便于所有的子makefile都可以使用include和C语言的#include一样,将后面的文件展开到当前位置Makefile高级编程灵活使用伪目标前面说过,伪目标在Makefile里面是一类特殊的目标,它不是一个

温馨提示

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

最新文档

评论

0/150

提交评论