Linux编译方法.docx
- 文档编号:6667959
- 上传时间:2023-01-08
- 格式:DOCX
- 页数:33
- 大小:134.02KB
Linux编译方法.docx
《Linux编译方法.docx》由会员分享,可在线阅读,更多相关《Linux编译方法.docx(33页珍藏版)》请在冰豆网上搜索。
Linux编译方法
Linux
编译方法
目录
概述1
1GNUgcc1
1.1GNUgcc简介1
1.2为什么要用gcc1
1.3gcc支持的文件格式1
1.4gcc组成2
1.5gcc起步2
1.6可执行程序的构造3
1.7hello编译过程分析3
1.8用gcc构造程序4
1.8.1单个文件源代码编译4
1.8.2多个源文件的编译4
1.8.3包含其它目录中的源文件5
1.8.4gcc构造复杂程序6
1.9gcc选项6
1.9.1gcc完整使用格式6
1.9.2总体选项6
1.9.3其它重要选项7
2跟我一起写Makefile9
2.1Makefile概述9
2.2Makefile介绍10
2.2.1Makefile的规则10
2.2.2一个示例11
2.2.3make是如何工作的12
2.2.4makefile中使用变量13
2.2.5让make自动推导14
2.2.6另类风格的makefile14
2.2.7清空目标文件的规则15
2.3Makefile总述15
2.3.1Makefile里有什么?
15
2.3.2Makefile的文件名16
2.3.3引用其它的Makefile16
2.3.4环境变量MAKEFILES17
2.3.5make的工作方式17
2.4Makefile书写规则18
2.4.1规则举例18
2.4.2规则的语法18
2.4.3在规则中使用通配符19
2.4.4文件搜寻19
2.4.5伪目标20
2.4.6多目标22
2.4.7自动生成依赖性23
2.5Makefile书写命令25
2.5.1显示命令25
2.5.2命令执行25
2.5.3命令出错26
2.5.4嵌套执行make27
2.5.5定义命令包28
概述
本文简要介绍如何在Linux操作系统下对C/C++语言源代码执行编译的一般方法。
在Linux操作系统下编译源代码需要掌握两部分基础知识,即编译器的使用方法和利用Makefile编译较复杂文件结构代码的方法,这两部分内容将在第一、二章阐述。
1GNUgcc
1.1GNUgcc简介
Ø目前Linux下最常用的C语言编译器是GCC(GNUCompilerCollection),它是GNU项目中符合ANSIC标准的编译系统.
Ø是Linux的基石,操作系统内核和大部分程序都是gcc编译的,是Linux下最重要开发工具之一
Øgcc早期是C的编译器,后来发展能支持c,c++和objectC,它可以通过不同的前端模块来支持各种语言,如Java、Fortran、Pascal、Modula-3和Ada等。
Øgcc是一个交叉平台的编译器,目前支持几乎所有主流CPU的处理器平台。
1.2为什么要用gcc
Ø随着Linux的GUI改进,也出现了越来越多的IDE开发环境,很多IDE基本上是基于gcc编译。
Ø而且大部分项目,包括嵌入式开发,都提供gcc命令行开发模式。
gcc是免费的。
Ø大家都用gcc,易于发现问题。
Ø用gcc开发是Linux和嵌入式开发的必须使用的工具,也是基本功之一。
1.3gcc支持的文件格式
Ø.cC源程序;
Ø.C,.cc,.cxx,.cppC++源程序;
Ø.mObjective-C源程序;
Ø.i预处理后的C文件;
Ø.ii预处理后的C++文件;
Ø.s汇编语言源程序;
Ø.S汇编语言源程序;
Ø.h预处理器文件;
Ø.o目标文件(Objectfile)
注:
gcc编译时是对输入文件扩展名是敏感的,这一点跟大部分Linux程序
不一样。
1.4gcc组成
gcc是一组编译工具的总称,包含如下工作
ØC编译器cc,cc1,cc1plus,gcc
Ø–C++编译器c++,cc1plus,g++
Ø–源码预处理程序cpp,cpp0
Ø–库文件:
libgcc.a,libgcc_eh.a,libgcc_s.so,ibiberty.a,libstdc++,lib
supc++.a
1.5gcc起步
生成一个hello,world程序
–gcchello.c-ohello#把hello.c编译成一个可执行程序hello
–gcchello.c#不指定输出名,生成一个a.out
#include
#defineMY_NUMBER5
intmain(void)
{
printf("Hello%d,theWorld!
\n",MY_NUMBER);
return0;
}
1.6可执行程序的构造
任何一个可执行程序从源代码到可执行的二进制程序之中都要经过固定的几步
Ø预处理(Pre-Processing)
•这一步完成对代码的预处理
Ø编译(Compiling)
•将源代码编译成汇编代码
Ø汇编(Assembling)
•将汇编代码汇编成目标文件
Ø链接(Linking)
•将目标代码和所需要库的链成一个完整的应用程序
集成开发环境(IDE)自动协助开发完成这几步,如VC++
在Linux下,如果使用命令行开发工具(gcc,ld,ar)等,需要用户手工调用这一些命令来完成这几步骤
1.7hello编译过程分析
预处理(Pre-Processing)
#gcc-Ehello.c-ohello.ior#cpphello.c-ohello.i
•编译(Compiling)
#gcc-Shello.i-ohello.sor#cc1hello.i-ohello.s
•汇编(Assembling)
#gcc-chello.s-ohello.oor#ashello.s-ohello.o
•链接(Linking)
#gcchello.o-ohelloor#ldhello.o-ohello
注意:
gcc的结果输出是后缀名不相关的.只与输出参数相关.这跟一
般Linux程序是一样gcchello.c-ohello.o#虽然后缀名是.o,但实际
是一个应用程序。
gcc各个编译步骤
1.8用gcc构造程序
1.8.1单个文件源代码编译
Ø正确的做法
gcchello.c-ohello
•表示将hello.c一次做完四步,构造出可执行程序hello
Ø不建议的做法
gcchello.c
•将hello.c构造一个可执行程序,有缺省名a.out,但不建议这样做
Ø错误的做法
gcc-chello.c-ohello
•这一步骤是初学者常犯错误.以为等于在一次性构造应用程序hello
•但实际上这只是在编译c并生成一个目标文件hello,即便是没有.o的后缀.这个用file命令可以很容易查看,这个hello是无法执行
1.8.2多个源文件的编译
使用多个源码的项目,如项目中包含2个以上的源代码,一般要先将源代码编译成目标代码.最后一次链接成可执行程序
以链表测试程序为例.整个项目由三个c代码(foo1.c、foo2.c和main.c)和一个头文件(foo.h)组成.
Ø头文件是包含在源代码里,由预处理程序处理,不需要编译
Ø首先各自己编译成目标文件
•gcc-cfoo1.c#将foo1.c编译成foo1.o
•gcc–cfoo2.c#将foo2.c编译成foo2.o
•gcc-cmain.c#将main.c编译成main.o
Ø然后将各个目标文件链接成一个文件
•gccfoo1.ofoo2.omain.o-omultisrc
•#生成可执行文件multisrc
Ø也可以直接把两个文件在一句里编译,但强烈建议不要这样做
•gccfoo1.cfoo2.cmain.c-omultisrc
编译multicsrc实例
1.8.3包含其它目录中的源文件
对于有头文件在多个目录时,需要在编译时多次使用用-I参数加入头文件所在目录.
例如上例中main.c需要用到./heads/foo.h文件,则如下编译
gcc–I./heads-cmain.c
编译实例如下图
1.8.4gcc构造复杂程序
一个大型项目,一个可执行程序可能拥有多个位于不同目录的头文件,多个源码文件,还可能链接一些静态库或动态库,这一些都需要用到gcc的一些扩展选项。
gcc的参数参见下一节。
可能调用gcc很多次,如果完全手工编写,将是一个浩大的工程,这种情况需要写一个类似Shell脚本的Makefile来调用gcc构造。
Makefile的使用方法参见下一章。
1.9gcc选项
1.9.1gcc完整使用格式
Øgcc使用格式:
•gcc[option|filename]
其中option为gcc使用时的选项(后面会再详),而filename为欲以gcc处理的文件
Ø总体选项(OverallOption)
•-c-S-E-o
1.9.2总体选项
-c
Ø编译或汇编源文件,但是不作连接.编译器输出对应于源文件的目标文件
Ø缺省情况下,GCC通过用`.o'替换源文件名后缀`.c',`.i',`.s',等等,产生目标文件名.可以使用-o选项选择其他名字。
ØGCC忽略-c选项后面任何无法识别的输入文件(他们不需要编译或汇编)
Øgcc–chello.c
-S
Ø对于每个输入的非汇编语言文件,输出文件是汇编语言文件.缺省情况下,GCC通过用`.s'替换源文件名后缀`.c',`.i',等等,产生目标文件名.可以使用-o选项选择其他名字。
GCC忽略任何不需要编译的输入文件。
Ø相当于编译源码,只生汇编代码
Øgcc–Shello.c–ohello.s
-E
Ø生成预处理后的文件
–gcc–Ehello.c–ohello.i
-v
Ø显示编译器驱动程序,预处理器,编译器的版本号.
–gcc-v
1.9.3其它重要选项
-ofile
Ø指定输出文件为file.该选项不在乎GCC产生什么输出,无论是可执行文件,目标文件,汇编文件还是预处理后的C代码.
Ø由编译阶段决定,输入的格式
•gcc-Ehello.c-ohello.i
•gcc-chello.i-ohello.o
•gcchello.c–ohello
Ø只能输出一个文件
-Dmacro
Ø-Dmacro
•定义宏macro,宏的内容定义为printf.
•gcctest_m.c–DPRINTF=printf–otest_m
Ø-Dmacro=defn
•定义宏DBG_NUM的内容为10
•gcctest_m.c–DDBG_NUM=10–otest_m
例如如下程序:
#include
intmain(intargc,char*argv[])
{
#ifdefDEBUG
printf("Hello,thisisaDEBUGversion\n");
#elifdefinedRELEASE
printf("Hello,thisisaRELEASEversion\n");
#else
printf("Hello,NeitherDEBUTnorRELEASEisdefined\n");
#endif
}
测试过程:
-W
Ø-Wall
•打开所有编译警告
•gcc-Wallillcode.c-oillcode
Ø-Werror
•视警告为错误;出现任何警告即放弃编译.
•gcc-Wall-Werrorillcode.c-oillcode
Ø-w
•禁止输出警告信息
-g
•产生调试信息.
•GDB能够使用这些调试信息,是进行gdb调试必备条件
•和大多数C编译器不同,GNUCC允许结合使用`-g‘和`-O’选项,但一般不建议一起使用
•所有调试选项会使用最终输出文件尺寸急剧增加,在最后发布,需要使用strip命令把调试信息去掉
striphello
2跟我一起写Makefile
2.1Makefile概述
什么是makefile?
或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和专业的程序员,makefile还是要懂。
这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。
特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。
因为,makefile关系到了整个工程的编译规则。
一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:
Delphi的make,VisualC++的nmake,Linux下GNU的make。
可见,makefile都成为了一种在工程方面的编译方法。
当然,不同产商的make各不相同,也有不同的语法,但其本质都是在“文件依赖性”上做文章,这里,我仅对GNU的make进行讲述,它是最遵循于IEEE1003.2-1992标准的(POSIX.2)。
在这篇文档中,将以C/C++的源码作为我们基础,所以必然涉及一些关于C/C++的编译的知识,相关于这方面的内容,请参看第一章内容。
在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++,首先要把源文件编译成中间代码文件,在Windows下也就是.obj文件,Linux下是.o文件,即ObjectFile,这个动作叫做编译(compile)。
然后再把大量的ObjectFile合成执行文件,这个动作叫作链接(link)。
编译时,编译器需要的是语法的正确,函数与变量的声明的正确。
对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。
一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件)。
链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。
链接器并不管函数所在的源文件,只管函数的中间目标文件(ObjectFile),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(LibraryFile),也就是.lib文件,在UNIX下,是ArchiveFile,也就是.a文件。
总结一下,源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。
在编译时,编译器只检测程序语法,和函数、变量是否被声明。
如果函数未被声明,编译器会给出一个警告,但可以生成ObjectFile。
而在链接程序时,链接器会在所有的ObjectFile中找寻函数的实现,如果找不到,那到就会报链接错误码(LinkerError),在VC下,这种错误一般是:
Link2001错误,意思说是说,链接器未能找到函数的实现。
你需要指定函数的ObjectFile.
好,言归正传,GNU的make有许多的内容,闲言少叙,还是让我们开始吧。
2.2Makefile介绍
make命令执行时,需要一个Makefile文件,以告诉make命令需要怎么样的去编译和链接程序。
首先,我们用一个示例来说明Makefile的书写规则。
以便给大家一个感兴认识。
这个示例来源于GNU的make使用手册,在这个示例中,我们的工程有8个C文件,和3个头文件,我们要写一个Makefile来告诉make命令如何编译和链接这几个文件。
我们的规则是:
1、如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
2、如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
3、如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。
只要我们的Makefile写得够好,所有的这一切,我们只用一个make命令就可以完成,make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序。
2.2.1Makefile的规则
在讲述这个Makefile之前,还是让我们先来粗略地看一看Makefile的规则。
target...:
prerequisites...
command
...
...
target也就是一个目标文件,可以是ObjectFile,也可以是执行文件。
还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。
prerequisites就是,要生成那个target所需要的文件或是目标。
command也就是make需要执行的命令。
(任意的Shell命令)
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。
说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。
这就是Makefile的规则。
也就是Makefile中最核心的内容。
说到底,Makefile的东西就是这样一点,这是Makefile的主线和核心,但要写好一个Makefile还不够,下面的章节会一一详细介绍。
2.2.2一个示例
正如前面所说的,如果一个工程有3个头文件,和8个C文件,我们为了完成前面所述的那三个规则,我们的Makefile应该是下面的这个样子的。
edit:
main.okbd.ocommand.odisplay.o\
insert.osearch.ofiles.outils.o
cc-oeditmain.okbd.ocommand.odisplay.o\
insert.osearch.ofiles.outils.o
main.o:
main.cdefs.h
cc-cmain.c
kbd.o:
kbd.cdefs.hcommand.h
cc-ckbd.c
command.o:
command.cdefs.hcommand.h
cc-ccommand.c
display.o:
display.cdefs.hbuffer.h
cc-cdisplay.c
insert.o:
insert.cdefs.hbuffer.h
cc-cinsert.c
search.o:
search.cdefs.hbuffer.h
cc-csearch.c
files.o:
files.cdefs.hbuffer.hcommand.h
cc-cfiles.c
utils.o:
utils.cdefs.h
cc-cutils.c
clean:
rmeditmain.okbd.ocommand.odisplay.o\
insert.osearch.ofiles.outils.o
反斜杠(\)是换行符的意思。
这样比较便于Makefile的易读。
我们可以把这个内容保存在文件为“Makefile”或“makefile”的文件中,然后在该目录下直接输入命令“make”就可以生成执行文件edit。
如果要删除执行文件和所有的中间目标文件,那么,只要简单地执行一下“makeclean”就可以了。
在这个makefile中,目标文件(target)包含:
执行文件edit和中间目标文件(*.o),依赖文件(prerequisites)就是冒号后面的那些.c文件和.h文件。
每一个.o文件都有一组依赖文件,而这些.o文件又是执行文件edit的依赖文件。
依赖关系的实质上就是说明了目标文件是由哪些文件生成的,换言之,目标文件是哪些文件更新的。
在定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个Tab键作为开头。
记住,make并不管命令是怎么工作的,他只管执行所定义的命令。
make会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比targets文件的日期要新,或者target不存在的话,那么,make就会执行后续定义的命令。
这里要说明一点的是,clean不是一个文件,它只不过是一个动作名字,有点像C语言中的lable一样,其冒号后什么也没有,那么,make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的命令。
要执行其后的命令,就要在make命令后明显得指出这个lable的名字。
这样的方法非常有用,我们可以在一个makefile中定义不用的编译或是和编译无关的命令,比如程序的打包,程序的备份,等等。
2.2.3make是如何工作的
在默认的方式下,也就是我们只输入make命令。
那么,
1make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
2如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“edit”这个文件,并把这个文件作为最终的目标文件。
3如果edit文件不存在,或是edit所依赖的后面的.o文件的文件修改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成edit这个文件。
4如果edit所依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。
(这有点像一个堆栈的过程)
5如果你的C文件和H文件是存在的,于是make会生成.o文件,然后再用.o文件生命make的终极任务,也就是执行文件edit了。
这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
在找寻的过程中,如果出现错误,比如
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux 编译 方法