博客访问: 155082
博文数量: 39
博客积分: 2713
博客等级: 少校
技术积分: 420
用 户 组: 普通用户
注册时间: 2010-09-25 00:05
分类: LINUX
2010-11-07 12:32:47
我懒的以后再到处找,以下为原文(原出处未知):
1。gcc包含的c/c++编译器
gcc,cc,c++,g++,gcc和cc是一样的,c++和g++是一样的,(没有看太明白前面这半句是什么意思:))一般c程序就用gcc编译,c++程序就用g++编译
2。gcc的基本用法
gcc test.c这样将编译出一个名为a.out的程序
gcc test.c -o test这样将编译出一个名为test的程序,-o参数用来指定生成程序的名字
3。为什么会出现undefined reference to 'xxxxx'错误?
首先这是链接错误,不是编译错误,也就是说如果只有这个错误,说明你的程序源码本身没有问题,是你用编译器编译时参数用得不对,你没有指定链接程序要用到得库,比如你的程序里用到了一些数学函数,那么你就要在编译参数里指定程序要链接数学库,方法是在编译命令行里
加入-lm。
4。-l参数和-L参数
-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢?
就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的头lib和尾.so去掉就是库名了。
好了现在我们知道怎么得到库名了,比如我们自已要用到一个第三方提供的库名字叫libtest.so,那么我们只要把libtest.so拷贝到
/usr/lib里,编译时加上-ltest参数,我们就能用上libtest.so库了(当然要用libtest.so库里的函数,我们还需要与
libtest.so配套的头文件)。
放在/lib和/usr/lib和/usr/local/lib里的库直接用-l参数就能链接了,但如果库文件没放在这三个目录里,而是放在其他目
录里,这时我们只用-l参数的话,链接还是会出错,出错信息大概是:“/usr/bin/ld:
cannot find
-lxxx”,也就是链接程序ld在那3个目录里找不到libxxx.so,这时另外一个参数-L就派上用场了,比如常用的X11的库,它放在/usr
/X11R6/lib目录下,我们编译时就要用-L/usr/X11R6/lib
-
lX11参数,-L参数跟着的是库文件所在的目录名。再比如我们把libtest.so放在/aaa/bbb/ccc目录下,那链接参数就是-L/aaa
/bbb/ccc
-ltest。另外,大部分libxxxx.so只是一个链接,以RH9为例,比如libm.so它链接到/lib/libm.so.x,/lib
/libm.so.6又链接到/lib/libm-2.3.2.so,如果没有这样的链接,还是会出错,因为ld只会找libxxxx.so,所以如果你
要用到xxxx库,而只有libxxxx.so.x或者libxxxx-x.x.x.so,做一个链接就可以了ln
-s libxxxx-x.x.x.so libxxxx.so
手工来写链接参数总是很麻烦的,还好很多库开发包提供了生成链接参数的程序,名字一般叫xxxx-config,一般放在/usr/bin目录下,比如gtk1.2的链接参数生成程序是gtk-config,执行gtk-config
--libs就能得到以下输出"-L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic
-lgmodule -lglib -ldl -lXi -lXext -lX11
-lm",这就是编译一个gtk1.2程序所需的gtk链接参数,xxx-config除了--libs参数外还有一个参数是--cflags用来生成头文
件包含目录的,也就是-I参数,在下面我们将会讲到。你可以试试执行gtk-config --libs
--cflags,看看输出结果。
现在的问题就是怎样用这些输出结果了,最笨的方法就是复制粘贴或者照抄,聪明的办法是在编译命令行里加入这个`xxxx-config
--libs -- cflags`,比如编译一个gtk程序:gcc gtktest.c `gtk-config --libs
--cflags`这样就差不多了。注意`不是单引号,而是1键左边那个键。
除了xxx-config以外,现在新的开发包一般都用pkg-config来生成链接参数,使用方法跟xxx-config类似,但xxx-config是针对特定的开发包,但pkg-config包含很多开发包的链接参数的生成,用pkg-config
--list-all命令可以列出所支持的所有开发包,pkg-config的用法就是pkg-config pagName --libs
--cflags,其中pagName是包名,是pkg-config--list-all里列出名单中的一个,比如gtk1.2的名字就是gtk+,pkg-config
gtk+ --libs --cflags的作用跟gtk-config --libs --cflags是一样的。比如:gcc
gtktest.c `pkg-config gtk+ --libs --cflags` 。
5。-include和-I参数
-include用来包含头文件,但一般情况下包含头文件都在源码里用#include
xxxxxx实现,-include参数很少用。-I参数是用来指定头文件目录,/usr/include目录一般是不用指定的,gcc知道去那里找,但
是如果头文件不在/usr/include里我们就要用-I参数指定了,比如头文件放在/myinclude目录里,那编译命令行就要加上-I
/myinclude参数了,如果不加你会得到一个"xxxx.h:
No such file or
directory"的错误。-I参数可以用相对路径,比如头文件在当前目录,可以用-I.来指定。上面我们提到的--cflags参数就是用来生成-I
参数的。
6。-O参数
这是一个程序优化参数,一般用-O2就是,用来优化程序用的,比如gcc test.c
-O2,优化得到的程序比没优化的要小,执行速度可能也有所提高(我没有测试过)。
7。-shared参数
编译动态库时要用到,比如gcc -shared test.c -o libtest.so
8。几个相关的环境变量
PKG_CONFIG_PATH:用来指定pkg-config用到的pc文件的路径,默认是/usr/lib/pkgconfig,pc文件是文本文件,扩展名是.pc,里面定义开发包的安装路径,Libs参数和Cflags参数等等。
CC:用来指定c编译器。
CXX:用来指定cxx编译器。
LIBS:跟上面的--libs作用差不多。
CFLAGS:跟上面的--cflags作用差不多。
CC,CXX,LIBS,CFLAGS手动编译时一般用不上,在做configure时有时用到,一般情况下不用管。
环境变量设定方法:export ENV_NAME=xxxxxxxxxxxxxxxxx
9。关于交叉编译
交叉编译通俗地讲就是在一种平台上编译出能运行在体系结构不同的另一种平台上,比如在我们地PC平台(X86
CPU)上编译出能运行在sparc CPU平台上的程序,编译得到的程序在X86 CPU平台上是不能运行的,必须放到sparc
CPU平台上才能运行。当然两个平台用的都是linux。这种方法在异平台移植和嵌入式开发时用得非常普遍。
相对与交叉编译,我们平常做的编译就叫本地编译,也就是在当前平台编译,编译得到的程序也是在本地执行。
用来编译这种程序的编译器就叫交叉编译器,相对来说,用来做本地编译的就叫本地编译器,一般用的都是gcc,但这种gcc跟本地的gcc编译器是不一样的,需要在编译gcc时用特定的configure参数才能得到支持交叉编译的gcc。
为了不跟本地编译器混淆,交叉编译器的名字一般都有前缀,比如sparc-xxxx-linux-gnu-gcc,sparc-xxxx-linux-gnu-g++
等等
10。交叉编译器的使用方法
使用方法跟本地的gcc差不多,但有一点特殊的是:必须用-L和-I参数指定编译器用sparc系统的库和头文件,不能用本地(X86)
的库(头文件有时可以用本地的)。
例子:
sparc-xxxx-linux-gnu-gcc test.c -L/path/to/sparcLib
-I/path/to/sparcInclude
______________________________________________________________________________
编译器gcc的简单用法说明:
用法: gcc [OPTION] file ...
用--help可以得到更多帮助。
常用选项:
1)
-o 指定输出的文件,如果是一个文件的C程序不指定-o选项,则输出的文件
是一个a.out的可执行文件,运行./a.out可以运行,注意LINUX下当前目录默认不在
搜索路径下,所以运行当前目录的程序也必须加./ 。
2) -c
只编译不连接,这样生成的程序如果不指定-o是file.o形式的文件,基本名字和
C 程序的相同。有些程序可能包括很多个文件,需要将每个文件先编译成.o的文件
,然后再连接在一起。
3) -I
指定include搜索的路径。如-I/home/lxq/include即指定include搜索路径中加
上/home/lxq/include。
4) -L
指定库的搜索路径。如-L/home/lxq/libs即指定库的搜索路径中加上/home/lxq/
libs。
5) -l
指定所用到的库。Linux下的库文件一般是这种格式:静态库libxxxx.a,动态库
libxxx.so,这样如果用到了某个库只需在编译的时候加上-lxxx即可。比如-lm,即
包含数学库。
6) -g
加入调试信息。加了这个选项之后生成的程序可以进行调试,但是可能程序的执
行速度会受到影响。可能用-gdb3来代替,-gdb3加入的调试信息最多。
7) -On
优化生成的目标代码。n是一个具体的数,如3。这样生成的程序没有调试信息
加入不能进行调试,但是程序的效率比较高,对有些程序的执行速度可能会影响很
大。
例子:
共有main.c func.c func.h
三个文件的程序其中main.c中有#i nclude
gcc -c main.c -o
main.o
gcc -c func.c -o
func.o
gcc main.o func.o -o
main
这样就生成了main的可执行程序,当然这些工作用make来做便不用每次都敲这些命令
3. make及Makefile的用法:
make是用来管理工程文件的,系统自动检测变化的部分,并为这种变化采取适当的
动作。make工作要有一个Makefile文件,下面介绍Makefile的文件格式及写法。
当在一个目录下运行make命令时,系统自动找Makefile或makefile,如果两者都没
有,也可以用-f来指定。Makefile的基本规则是这样的:
目标:依赖程序
执行命令1
执行命令2
.
.
.
比如上面的例子可以写成Makefile如下:
main:main.o func.o
gcc main.o
func.o -o main
main.o:main.c
gcc -c main.c
-o main.o
func.o:func.c func.h
gcc -c
func.c -o func.o
注意此处必须是TAB键而不能是空格。
可以在Makefile里定义变量,变量的引用用$()来表示,如下例,可参考相关书籍介绍
###########################################################################
gcc and g++分别是gnu的c & c++编译器
gcc/g++在执行编译工作的时候,总共需要4步
1.预处理,生成.i的文件[预处理器cpp]
2.将预处理后的文件不转换成汇编语言,生成文件.s[编译器egcs]
3.有汇编变为目标代码(机器代码)生成.o的文件[汇编器as]
4.连接目标代码,生成可执行程序[链接器ld]
[参数详解]
-x language filename
设定文件所使用的语言,使后缀名无效,对以后的多个有效.也就是根据约定C语言的后缀名称是.c的,而C++的后缀名是.C或者.cpp,如果你很个性,决定你的C代码文件的后缀名是.pig
哈哈,那你就要用这个参数,这个参数对他后面的文件名都起作用,除非到了下一个参数的使用。
可以使用的参数吗有下面的这些
`c', `objective-c', `c-header', `c++', `cpp-output', `assembler',
and `assembler-with-cpp'.
看到英文,应该可以理解的。
例子用法:
gcc -x c hello.pig
-x none filename
关掉上一个选项,也就是让gcc根据文件名后缀,自动识别文件类型
例子用法:
gcc -x c hello.pig -x none
hello2.c
-c
只激活预处理,编译,和汇编,也就是他只把程序做成obj文件
例子用法:
gcc -c hello.c
他将生成.o的obj文件
-S
只激活预处理和编译,就是指把文件编译成为汇编代码。
例子用法
gcc -S hello.c
他将生成.s的汇编代码,你可以用文本编辑器察看
-E
只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面.
例子用法:
gcc -E hello.c >;
pianoapan.txt
gcc -E hello.c | more
慢慢看吧,一个hello word
也要与处理成800行的代码
-o
制定目标名称,缺省的时候,gcc
编译出来的文件是a.out,很难听,如果你和我有同感,改掉它,哈哈
例子用法
gcc -o hello.exe hello.c
(哦,windows用习惯了)
gcc -o hello.asm -S
hello.c
-pipe
使用管道代替编译中临时文件,在使用非gnu汇编工具的时候,可能有些问题
gcc -pipe -o hello.exe
hello.c
-ansi
关闭gnu c中与ansi c不兼容的特性,激活ansi c的专有特性(包括禁止一些asm inline
typeof关键字,以及UNIX,vax等预处理宏,
-fno-asm
此选项实现ansi选项的功能的一部分,它禁止将asm,inline和typeof用作关键字。
-fno-strict-prototype
只对g++起作用,使用这个选项,g++将对不带参数的函数,都认为是没有显式的对参数的个数和类型说明,而不是没有参数.
而gcc无论是否使用这个参数,都将对没有带参数的函数,认为城没有显式说明的类型
-fthis-is-varialble
就是向传统c++看齐,可以使用this当一般变量使用.
-fcond-mismatch
允许条件表达式的第二和第三参数类型不匹配,表达式的值将为void类型
-funsigned-char
-fno-signed-char
-fsigned-char
-fno-unsigned-char
这四个参数是对char类型进行设置,决定将char类型设置成unsigned char(前两个参数)或者 signed
char(后两个参数)
-include file
包含某个代码,简单来说,就是便以某个文件,需要另一个文件的时候,就可以用它设定,功能就相当于在代码中使用#include;
例子用法:
gcc hello.c -include
/root/pianopan.h
-imacros file
将file文件的宏,扩展到gcc/g++的输入文件,宏定义本身并不出现在输入文件中
-Dmacro
相当于C语言中的#define macro
-Dmacro=defn
相当于C语言中的#define
macro=defn
-Umacro
相当于C语言中的#undef macro
-undef
取消对任何非标准宏的定义
-Idir
在你是用#include"file"的时候,gcc/g++会先在当前目录查找你所制定的头文件,如果没有找到,他回到缺省的头文件目录找,如果使用-I制定了目录,他
回先在你所制定的目录查找,然后再按常规的顺序去找.
对于#include;,gcc/g++会到-I制定的目录查找,查找不到,然后将到系统的缺省的头文件目录查找
-I-
就是取消前一个参数的功能,所以一般在-Idir之后使用
-idirafter dir
在-I的目录里面查找失败,讲到这个目录里面查找.
-iprefix prefix
-iwithprefix dir
一般一起使用,当-I的目录查找失败,会到prefix+dir下查找
-nostdinc
使编译器不再系统缺省的头文件目录里面找头文件,一般和-I联合使用,明确限定头文件的位置
-nostdin C++
规定不在g++指定的标准路经中搜索,但仍在其他路径中搜索,.此选项在创libg++库使用
-C
在预处理的时候,不删除注释信息,一般和-E使用,有时候分析程序,用这个很方便的
-M
生成文件关联的信息。包含目标文件所依赖的所有源代码你可以用gcc -M
hello.c来测试一下,很简单。
-MM
和上面的那个一样,但是它将忽略由#include;造成的依赖关系。
-MD
和-M相同,但是输出将导入到.d的文件里面
-MMD
和-MM相同,但是输出将导入到.d的文件里面
-Wa,option
此选项传递option给汇编程序;如果option中间有逗号,就将option分成多个选项,然后传递给会汇编程序
-Wl.option
此选项传递option给连接程序;如果option中间有逗号,就将option分成多个选项,然后传递给会连接程序.