gcc 编译选项

转自往上一篇博文:http://apps.hi.baidu.com/share/detail/14973380

 

GNU编译器集(其前身为GNU C 编译器)诞生于1987年。当时Richard Stallman(GNU项目的创办人)想要创建一个编译器,它可以满足他定义的“自由软件”概念,并可用来编译 GNU 项目发布的其他软件。GNU C编译器迅速在自由软件社区中流行开来,而且以其健壮性和可移植性而闻名。它已成为许多集成开发工具的基础,被世界各地的发行商应用在 Linux和其他操作系统之上。

 

GCC 已不再是主要针对GNU项目自身的软件的小型 C语言编译器了。如今,它已支持了许多不同的语言,包括 C、C++、Ada、Fortran、Objective C,甚至还有Java。事实上,现代Linux 系统除了可以自豪地炫耀那些由 GNU 工具直接支持的语言以外,它还支持大量其他语言。日益流行的脚本语言 Perl、Python 和Ruby,以及正在不断发展的mono 可移植C#实现的确有助于冲淡人们对 Linux 编程的传统看法,但这完全是另外一个问题了。

Linux 内核和许多其他自由软件以及开放源码应用程序都是用 C 语言编写并使用 GCC 编译的。

1. 编译单个源文件

为了进行测试,你可以创建“Hello World”程序:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
printf(”Hello world!\n”);
exit(0);
}

使用如下命令编译并测试这个代码:
# gcc -o hello hello.c
# ./hello
Hello wordl!

在默认情况下产生的可执行程序名为a.out,但你通常可以通过 gcc 的“-o”选项来指定自己的可执行程序名称。

2. 编译多个源文件

源文件message.c包含一个简单的消息打印函数:

#include <stdio.h>

void goodbye_world(void)
{
printf(”Goodbye, world!\n”);
}

使用gcc的“-c”标记来编译支持库代码:
# gcc -c message.c

这一过程的输出结果是一个名为message.o的文件,它包含适合连接到一个较大程序的已编译目标代码。

创建一个简单的示例程序,它包含一个调用goodbye_world的main函数

#include <stdlib.h>

void goodbye_world(void):

int main(int argc, char **argv)
{
goodbye_world();
exit(0);
}

使用GCC编译这个程序:
# gcc -c main.c

现在有了两个目标文件: message.o 和 main.o 。它们包含能够被 Linux 执行的目标代码。要从这个目标代码创建Linux可执行程序,需要再一次调用 GCC 来执行连接阶段的工作:
# gcc -o goodbye message.o main.o

运行编译结果:
# ./goodbye
Goodbye, world!

前面这些单独的步骤也可以简化为一个命令,这是因为 GCC 对如何将多个源文件编译为一个可执行程序有内置的规则。
# gcc -o goodbye message.c main.c
# ./goodbye
Goodbye, world!

3. 使用外部函数库

GCC 常常与包含标准例程的外部软件库结合使用,几乎每一个 Linux 应用程序都依赖于由 GNU C 函数库 GLIBC。
应用外部函数库的例子:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define MAX_INPUT 25

int main(int agrc, char **argv)
{
char input[MAX_INPUT];
double angle;

printf(”Give me an angle (in radians) ==>”);
if(!fgets(input, MAX_INPUT, stdin)){
perror(”an error occurred.\n”);
}
angle = strtod(input, NULL);

printf(”sin(%e) = %e\n”, angle, sin(angle));

return 0;
}

编译命令:
# gcc -o trig -lm trig.c

GCC 的”-lm”选项,它告诉 GCC查看系统提供的数学库(libm)。因为Linux和UNIX的系统函数库通常以”lib”为前缀,所以我们假设它存在。真正的函数库位置随系统的不同而不同,但它一般会位于目录/lib或/usr/lib中,在这些目录中还有数以百计的其他必需的系统函数库。

4. 共享函数库与静态函数库

Linux系统上的函数库分为两种不同的类型:共享的和静态的

静态函数库:每次当应用程序和静态连接的函数库一起编译时,任何引用的库函数中的代码都会被直接包含进最终的二进制程序。

共享函数库:包含每个库函数的单一全局版本,它在所有应用程序之间共享。这一过程背后所涉及的机制相当复杂,但主要依靠的是现代计算机的虚拟内存能力,它允许包含库函数的物理内存安全地在多个独立用户程序之间共享。

使用共享函数库不仅减少了文件的容量和 Linux应用程序在内存中覆盖的区域,而且它还提高了系统的安全性。一个被许多不同程序同时调用的共享函数库很可能会驻留在内存中,以在需要使用它时被立即使用,而不是位于磁盘的交换分区中。这有助于进一步减少一些大型 Linux 应用程序的装载时间。

将上面的 message.c 作为共享库函数使用的例子:

# gcc -fPIC -c message.c
“PIC”命令行标记告诉 GCC产生的代码不要包含对函数和变量具体内存位置的引用,这是因为现在还无法知道使用该消息代码的应用程序会将它连接到哪一段内存地址空间。这样编译输出的文件 message.o 可以被用于建立共享函数库,我们只需使用gcc的“-shared”标记即可:
# gcc -shared -o libmessage.so message.o

将上面的mian.c使用共享库函数ligmessage.so编译:
# gcc -o goodbye -lmessage -L. message.o
“-lmessage”标记来告诉 GCC 在连接阶段引用共享函数库 libmessage.so 。“-L.”标记告诉 GCC 函数库可能位于当前目录中,否则 GNU 的连接器会查找标准系统函数库目录,在本例的情况下,就找不到可用的函数库了。

此时运行编译好的goodbye会提示找不到共享函数库:
#./goodbye
./goodbye: error while loading shared libraries: libmessage.so: cannot open shared object file: No such file or directory

可以使用命令 ldd 来发现一个特定应用程序需要使用的函数库。ldd搜索标准系统函数库路径并显示一个特定程序使用的函数库版本。

#ldd goodbye
linux-gate.so.1 => (0×00493000)
libmessage.so => not found
libc.so.6 => /lib/libc.so.6 (0×0097c000)
/lib/ld-linux.so.2 (0×0095a000)

库文件 libmessage.so 不能在任何一个标准搜索路径中找到,而且系统提供的配置文件 /etc/ld.so.conf 也没有包含一个额外的条目来指定包含该库文件的目录。

需要设置一个环境变量LD_LIBRARY_PATH来制定额外的共享函数库搜索路径,
# export LD_LIBRARY_PATH=`pwd`
# ldd goodbye
linux-gate.so.1 => (0x002ce000)
libmessage.so => /tmp/cpro/libmessage.so (0x00b0f000)
libc.so.6 => /lib/libc.so.6 (0x0097c000)
/lib/ld-linux.so.2 (0x0095a000)

运行程序
# ./goodbye
Goodbye, world!

gcc在命令行上经常使用的几个选项是:
-c   只预处理、编译和汇编源程序,不进行连接。编译器对每一个源程序产生一个目标文件。
-o file 确定输出文件为file。如果没有用-o选项,缺省的可执行文件的输出是 a.out,目标文件和汇编文件的输出对source.suffix分别是source.o和source.s,预处理的C源程序的输出是标准输出stdout。
-Dmacro或-Dmacro=defn   其作用类似于源程序里的#define。例如:% gcc -c -DHAVE_GDBM-DHELP_FILE=\”help\” cdict.c其中第一个-D选项定义宏HAVE_GDBM,在程序里可以用#ifdef去检查它是否被设置。第二个-D选项将宏HELP_FILE定义为字符串“help”(由于反斜线的作用,引号实际上已成为该宏定义的一部分),这对于控制程序打开哪个文件是很有用的。
-Umacro   某些宏是被编译程序自动定义的。这些宏通常可以指定在其中进行编译的计算机系统类型的符号,用户可以在编译某程序时加上-v选项以查看gcc缺省定义了哪些宏。如果用户想取消其中某个宏定义,用-Umacro选项,这相当于把#undefmacro放在要编译的源文件的开头。
-Idir   将dir目录加到搜寻头文件的目录列表中去,并优先于在gcc缺省的搜索目录。在有多个-I选项的情况下,按命令行上-I选项的前后顺序搜索。dir可使用相对路径,如-I../inc等。
-O   对程序编译进行优化,编译程序试图减少被编译程序的长度和执行时间,但其编译速度比不做优化慢,而且要求较多的内存。
-O2   允许比-O更好的优化,编译速度较慢,但结果程序的执行速度较快。
-g   产生一张用于调试和排错的扩展符号表。-g选项使程序可以用GNU的调试程序GDB进行调试。优化和调试通常不兼容,同时使用-g和-O(-O2)选项经常会使程序产生奇怪的运行结果。所以不要同时使用-g和-O(-O2)选项。
-fpic或-fPIC   产生位置无关的目标代码,可用于构造共享函数库。
以上是gcc的编译选项。gcc的命令行上还可以使用连接选项。事实上,gcc将所有不能识别的选项传递给连接程序ld。连接程序ld将几个目标文件和库程序组合成一个可执行文件,它要解决对外部变量、外部过程、库程序等的引用。但我们永远不必要显式地调用ld。利用gcc命令去连接各个文件是很简单的,即使在命令行里没有列出库程序,gcc也能保证某些库程序以正确的次序出现。
gcc的常用连接选项有下列几个:
-Ldir   将dir目录加到搜寻-l选项指定的函数库文件的目录列表中去,并优先于gcc缺省的搜索目录。在有多个-L选项的情况下,按命令行上-L选项的前后顺序搜索。dir可使用相对路径。如-L../lib等。
-lname   在连接时使用函数库libname.a,连接程序在-Ldir选项指定的目录下和/lib,/usr/lib目录下寻找该库文件。在没有使用-static选项时,如果发现共享函数库libname.so,则使用libname.so进行动态连接。
-static   禁止与共享函数库连接。
-shared   尽量与共享函数库连接。
这是Linux上连接程序的缺省选项。下面是一个使用gcc进行连接的例子:
% gcc -o prog main.o subr.o -L../lib -lany -lm

转载者记:

在编译Myseelite的tracker时,编译不通过,提示:

/usr/lib/gcc/i586-suse-linux/4.6/../../../../i586-suse-linux/bin/ld: cannot find -lm
/usr/lib/gcc/i586-suse-linux/4.6/../../../../i586-suse-linux/bin/ld: cannot find -lc

试着去掉了Makefile中的 -static 编译选项,编译通过,生成了可执行文件。


检查动态链接库的相关配置:

linux-u55j:/home/nana/Myseelite/myseelite.sf/src/server/tracker # ldd tsnew.120718
        linux-gate.so.1 =>  (0xffffe000)
        libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7619000)
        libm.so.6 => /lib/libm.so.6 (0xb75ee000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb75d0000)
        libpthread.so.0 => /lib/libpthread.so.0 (0xb75b5000)
        libc.so.6 => /lib/libc.so.6 (0xb7448000)
        /lib/ld-linux.so.2 (0xb771e000)
linux-u55j:/home/nana/Myseelite/myseelite.sf/src/server/tracker # strings /etc/ld.so.conf
/usr/local/lib
/usr/local/BerkeleyDB.4.3/lib
include /etc/ld.so.conf.d/*.conf
# /lib64, /lib, /usr/lib64 and /usr/lib gets added
# automatically by ldconfig after parsing this file.
# So, they do not need to be listed.

gcc如何寻找动态链接库:

转自:http://james23dier.iteye.com/blog/763274

Linux 运行的时候,是如何管理共享库(*.so)的?在 Linux 下面,共享库的寻找和加载是由 /lib/ld.so 实现的。 ld.so 在标准路经(/lib, /usr/lib) 中寻找应用程序用到的共享库。

但是,如果需要用到的共享库在非标准路经,ld.so 怎么找到它呢?

目前,Linux 通用的做法是将非标准路经加入 /etc/ld.so.conf,然后运行 ldconfig 生成 /etc/ld.so.cache。 ld.so 加载共享库的时候,会从 ld.so.cache 查找。

传统上,Linux 的先辈 Unix 还有一个环境变量:LD_LIBRARY_PATH 来处理非标准路经的共享库。ld.so 加载共享库的时候,也会查找这个变量所设置的路经。

LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib

export LD_LIBRARY_PATH

但是,有不少声音主张要避免使用 LD_LIBRARY_PATH 变量,尤其是作为全局变量。这些声音是:

* LD_LIBRARY_PATH is not the answer - http://prefetch.net/articles/linkers.badldlibrary.html

* Why LD_LIBRARY_PATH is bad - http://xahlee.org/UnixResource_dir/_/ldpath.html 

* LD_LIBRARY_PATH - just say no - http://blogs.sun.com/rie/date/20040710

解决这一问题的另一方法是在编译的时候通过 -R<path> 选项指定 run-time path。

1. 往/lib和/usr/lib里面加东西,是不用修改/etc/ld.so.conf的,但是完了之后要调一下ldconfig,不然这个library会找不到

2. 想往上面两个目录以外加东西的时候,一定要修改/etc/ld.so.conf,然后再调用ldconfig,不然也会找不到。

比如安装了一个mysql到/usr/local/mysql,mysql有一大堆library在/usr/local/mysql/lib下面,这时就需要在/etc/ld.so.conf下面加一行/usr/local/mysql/lib,保存过后ldconfig一下,新的library才能在程序运行时被找到。

3. 如果想在这两个目录以外放lib,但是又不想在/etc/ld.so.conf中加东西(或者是没有权限加东西)。那也可以,就是export一个全局变量LD_LIBRARY_PATH,然后运行程序的时候就会去这个目录中找library。一般来讲这只是一种临时的解决方案,在没有权限或临时需要的时候使用。

4. ldconfig做的这些东西都与运行程序时有关,跟编译时一点关系都没有。编译的时候还是该加-L就得加,不要混淆了。

5. 总之,就是不管做了什么关于library的变动后,最好都ldconfig一下,不然会出现一些意想不到的结果。不会花太多的时间,但是会省很多的事。

LD_LIBRARY_PATH 这个环境变量是大家最为熟悉的,它告诉loader:在哪些目录中可以找到共享库。可以设置多个搜索目录,这些目录之间用冒号分隔开。在linux下,还提供了另外一种方式来完成同样的功能,你可以把这些目录加到/etc/ld.so.conf中,然后调用ldconfig。当然,这是系统范围内全局有效的,而环境变量只对当前shell有效。按照惯例,除非你用上述方式指明,loader是不会在当前目录下去找共享库的,正如shell不会在当前目前找可执行文件一样。

================================================================================================

转自:http://www.cnblogs.com/zackyang/archive/2010/01/17/1649823.html

1、可以用 LD_LIBRARY_PATH 环境变量指定,这个类似于 PATH 机制,比较直观,而且,可以放到 bashrc 中固化下来,也可以放到自己的 .bashrc 中只对本用户起作用;
2、如果启用了 ld.so.cache 的话,系统会在 /etc/ld.so.cache 中存储所有可引用的动态链接库。这个文件的内容可以通过 /etc/ld.so.conf 来指定;这个是比较固定的机制,对全局所有用户都有影响;不过更改设置后需要 root 调用 ldconfig 来刷新一下。
3、默认的标准库路径,这个似乎不用设置就可以。包括 /lib 和 /usr/lib。当然,如果是64位系统,还包括 /lib64 和 /usr/lib64。
4、其它情况,如果只想对某一个特定的应用程序起作用的话,可以在编译时指定搜索路径。gcc 的 -Wl 和 -rpath 参数。

========================================================

后记:

虽然修改后编译成功了,但是,原来的Makefile为什么非要用 "-static" 选项呢?

以后遇到问题,再解决吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值