linux下gcc/g++的命令和使用详解

[介绍] 
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 `a 
ssembler-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 inl 
ine 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<filename> 
  例子用法: 
  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<file>,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<file>造成的依赖关系。 
   
-MD 
  和-M相同,但是输出将导入到.d的文件里面 
   
-MMD 
  和-MM相同,但是输出将导入到.d的文件里面 
   
-Wa,option 
  此选项传递option给汇编程序;如果option中间有逗号,就将option分成多个选项,然 
后传递给会汇编程序 
   
-Wl.option 
  此选项传递option给连接程序;如果option中间有逗号,就将option分成多个选项,然 
后传递给会连接程序. 
   
-llibrary 
  制定编译的时候使用的库 
  例子用法 
  gcc -lcurses hello.c 
  使用ncurses库编译程序 
   
-Ldir 
  制定编译的时候,搜索库的路径。比如你自己的库,可以用它制定目录,不然 
  编译器将只在标准库的目录找。这个dir就是目录的名称。 
   
-O0 
-O1 
-O2 
-O3 
  编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高  
     
-g 
  只是编译器,在编译的时候,产生调试信息。 
   
-gstabs 
  此选项以stabs格式声称调试信息,但是不包括gdb调试信息. 
   
-gstabs+ 
  此选项以stabs格式声称调试信息,并且包含仅供gdb使用的额外调试信息. 
   
-ggdb 
  此选项将尽可能的生成gdb的可以使用的调试信息. 
-static 
  此选项将禁止使用动态库,所以,编译出来的东西,一般都很大,也不需要什么 
动态连接库,就可以运行. 
-share 
  此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库. 
-traditional 
  试图让编译器支持传统的C语言特性 
[参考资料] 
-Linux/UNIX高级编程 
  中科红旗软件技术有限公司编著.清华大学出版社出版 
-Gcc man page 
   
[ChangeLog] 
-2002-08-10 
  ver 0.1 发布最初的文档 
-2002-08-11 
  ver 0.11 修改文档格式 
-2002-08-12 
  ver 0.12 加入了对静态库,动态库的参数 
-2002-08-16 
  ver 0.16 增加了gcc编译的4个阶段的命令 
运行 gcc/egcs 
********************************************运行 gcc/egcs**************************************************** 
  GCC 是 GNU 的 C 和 C++ 编译器。实际上,GCC 能够编译三种语言:C、C++ 和 O 
bject C(C 语言的一种面向对象扩展)。利用 gcc 命令可同时编译并连接 C 和 C++ 
源程序。 
  如果你有两个或少数几个 C 源文件,也可以方便地利用 GCC 编译、连接并生成可 
执行文件。例如,假设你有两个源文件 main.c 和 factorial.c 两个源文件,现在要编 
译生成一个计算阶乘的程序。 
代码: 
------------------------------------------------------------------------------ 
清单 factorial.c 
------------------------------------------------------------------------------ 
int factorial (int n) 

  if (n <= 1) 
   return 1; 
  else 
   return factorial (n - 1) * n; 

----------------------------------------------------------------------------- 
清单 main.c 
----------------------------------------------------------------------------- 
#include <stdio.h> 
#include <unistd.h> 
int factorial (int n); 
int main (int argc, char **argv) 

  int n; 
  if (argc < 2) 
  { 
    printf ("Usage: %s n\n", argv [0]); 
    return -1; 
  } 
  else 
  { 
   n = atoi (argv[1]); 
   printf ("Factorial of %d is %d.\n", n, factorial (n)); 
   } 
  return 0; 

----------------------------------------------------------------------------- 
利用如下的命令可编译生成可执行文件,并执行程序: 
$ gcc -o factorial main.c factorial.c 
$ ./factorial 5 
Factorial of 5 is 120. 
  GCC 可同时用来编译 C 程序和 C++ 程序。一般来说,C 编译器通过源文件的后缀 
名来判断是 C 程序还是 C++ 程序。在 Linux 中,C 源文件的后缀名为 .c,而 C++ 源 
文件的后缀名为 .C 或 .cpp。但是,gcc 命令只能编译 C++ 源文件,而不能自动和 C 
++ 程序使用的库连接。因此,通常使用 g++ 命令来完成 C++ 程序的编译和连接,该程 
序会自动调用 gcc 实现编译。假设我们有一个如下的 C++ 源文件(hello.C): 
#include <iostream> 
void main (void) 

  cout << "Hello, world!" << endl; 

则可以如下调用 g++ 命令编译、连接并生成可执行文件: 
$ g++ -o hello hello.C 
$ ./hello 
Hello, world! 
********************************************gcc/egcs 的主要选项********************************************** 
gcc 命令的常用选项 
选项 解释 
-ansi 只支持 ANSI 标准的 C 语法。这一选项将禁止 GNU C 的某些特色, 
例如 asm 或 typeof 关键词。 
-c 只编译并生成目标文件。 
-DMACRO 以字符串“1”定义 MACRO 宏。 
-DMACRO=DEFN 以字符串“DEFN”定义 MACRO 宏。 
-E 只运行 C 预编译器。 
-g 生成调试信息。GNU 调试器可利用该信息。 
-IDIRECTORY 指定额外的头文件搜索路径DIRECTORY。 
-LDIRECTORY 指定额外的函数库搜索路径DIRECTORY。 
-lLIBRARY 连接时搜索指定的函数库LIBRARY。 
-m486 针对 486 进行代码优化。 
-o FILE 生成指定的输出文件。用在生成可执行文件时。 
-O0 不进行优化处理。 
-O 或 -O1 优化生成代码。 
-O2 进一步优化。 
-O3 比 -O2 更进一步优化,包括 inline 函数。 
-shared 生成共享目标文件。通常用在建立共享库时。 
-static 禁止使用共享连接。 
-UMACRO 取消对 MACRO 宏的定义。 
-w 不生成任何警告信息。 
-Wall 生成所有警告信息。 

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

C++中的一些文件后缀
.a    静态库 (archive)
.C
.c
.cc
.cp
.cpp
.cxx    C++源代码(需要编译预处理)
.h    C或者C++源代码头文件
.ii    C++源代码(不需编译预处理)
.o    对象文件
.s    汇编语言代码
.so    动态库
<none>    标准C++系统头文件
===========================================================================================================

linux的实际的搜索路径是比较烦人的,下面是摘自here的一段介绍。

注意事项
64位的linux机器上的默共享库的查找路径为:/lib64 /usr/lib64。实测发现不会搜索/lib /usr/lib。而且以上的两个目录没有什么so文件。/usr/local/lib64、/usr/local/lib 这两个目录也不会搜索的。
动态库的搜索路径搜索的先后顺序是: //注释:居然没有当前路径** 
  1.编译目标代码时指定的动态库搜索路径; //LDIRNAME 
  2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径; 
  3.配置文件/etc/ld.so.conf中指定的动态库搜索路径;//只需在在该文件中追加一行库所在的完整路径如”/root/test/conf/lib"即可,然后ldconfig是修改生效。(实际上是根据缓存文件/etc/ld.so.cache来确定路径) 
  4.默认的动态库搜索路径/lib;(64位机器为/lib64) 
  5.默认的动态库搜索路径/usr/lib。(64位机器为/usr/lib64)
关于ldconfig 
a) ldconfig主要的作用是根据/etc/ld.so.conf 的内容,查找内容中所包含目录下实际的动态库文件,生成搜索共享库的缓存文件/etc/ld.so.cache 。 
b) 缓存必须与实际路径的文件相一致。机器比较傻,只认缓存,然后按照缓存的路径去实际路径查找文件。增加或删除了实际的共享库路径下的文件,而没有更新缓存,执行被其依赖的可执行文件时会出错。 
c) 查看共享库的缓存内容。ldconfig -p。
/lib 或 /usr/lib(64位系统下为/lib64 /usr/lib64)路径下的共享库比较特殊。 
a) 它是默认的共享库的搜索路径。 
b) 它没有放到/etc/ld.so.conf 文件中。但是在/etc/ld.so.cache 的缓存中有它。 
c) 其路径下的共享库的变动即时生效,不用执行ldconfig。就算缓存ldconfig -p 中没有,新加入的动态库也可以执行。
linux中搜索动态库的顺序
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 变量,尤其是作为全局变量

ldd 的作用
ldd 命令的作用是 打印共享库的依赖关系

首先ldd不是一个可执行程序,而只是一个shell脚本
ldd能够显示可执行模块的dependency,其原理是通过设置一系列的环境变量,如下:LD_TRACE_LOADED_OBJECTS、LD_WARN、LD_BIND_NOW、LD_LIBRARY_VERSION、 LD_VERBOSE等。当LD_TRACE_LOADED_OBJECTS环境变量不为空时,任何可执行程序在运行时,它都会只显示模块的 dependency,而程序并不真正执行。要不你可以在shell终端测试一下,如下: 
  (1) export LD_TRACE_LOADED_OBJECTS=1 
  (2) 再执行任何的程序,如ls等,看看程序的运行结果
ldd显示可执行模块的dependency的工作原理,其实质是通过ld-linux.so(elf动态库的装载 
  器)来实现的。我们知道,ld-linux.so模块会先于executable模块程序工作,并获得控制权,因此当上述的那些环境变量被设置时,ld-linux.so选择了显示可执行模块的dependency。
实际上可以直接执行ld-linux.so模块,如:/lib/ld-linux.so.2 –list program(这相当于ldd program)
ldconfig 工具的作用
ldconfig是一个动态链接库管理命令。其目的是为了让动态链接库为系统所共享。 
ldconfig命令的用途 
主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态链接库(格式如lib.so),进而创建出动态装入程序(ld.so)所需的连接和缓存文件。 
缓存文件默认为/etc/ld.so.cache,此文件保存已排好序的动态链接库名字列表。 
ldconfig命令的使用时机 
ldconfig通常在系统启动时运行,而当用户安装了一个新的动态链接库时,就需要手工运行这个命令。

===========================================================================================================
关于gcc的静态库和动态库介绍:


静态编译的写法:  

                 gcc -o test -static test.c

库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀。 例如:libtest.so libtest.a。为了在同一系统中使用不同版本的库,可以在库文件名后加上版本号为后缀,但由于程序连接默认以.so为文件后缀名。所以为了使用这些库,通常使用建立符号连接的方式。如:

  ln -s libtest.so.1.0 hello.so.1

  ln -s libtest.so.1 hello.so 下面对比一下两者:

  静态链接库:当要使用时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。

  动态库而言:某个程序在运行中要调用某个动态链接库函数的时候,操作系统首先会查看所有正在运行的程序,看在内存里是否已有此库函数的拷贝了。如果有,则让其共享那一个拷贝;只有没有才链接载入。在程序运行的时候,被调用的动态链接库函数被安置在内存的某个地方,所有调用它的程序将指向这个代码段。因此,这些代码必须使用相对地址,而不是绝对地址。在编译的时候,我们需要告诉编译器,这些对象文件是用来做动态链接库的,所以要用地址不无关代码(Position Independent Code (PIC))。注意:linux下进行连接的缺省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。

在Linux上,静态程序库会有类似libname.a 这样的名称;而共享程序库则称为libname.so .x.y.z , 此处的x.y.z 是指版本序号的样式 
静态库文件(.a)

  比如静态数学库libm.a、静态C++库libstdc++.a等,编译静态程序时会连接它们。 

动态库文件(.so、.s0[0-9]*)

  比如动态数学库lim.so、动态C++库libstdc++.so等。编译动态程序时会用到这些文件,但是不会连接它们,运行时才连接。

你可以用ldd (List Dynamic Dependencies)来查出某支程序需要哪些共享程序库。

$ ldd /usr/bin/lynx

     libncurses.so.1 => /usr/lib/libncurses.so.1.9.6
     libc.so.5 => /lib/libc.so.5.2.18 

编译时默认搜索库文件的路径是

就a.out而言,以-lfoo 参数来连结,会驱使ld去寻找libfoo.so (shared stubs);如果没有成功,就会换成寻找libfoo.a (static)。 

就ELF而言,先找libfoo.so ,然后是libfoo.a 。libfoo.so 通常是一个连结符号,连结至libfoo.so.x 。

ld可能不会自动加载 libfoo.so.x,需要使用 libfoo.so的链接来指定。   


Linux 系统上有两类根本不同的 Linux 可执行程序。
第一类是静态链接的可执行程序。静态可执行程序包含执行所需的所有函数 — 换句话说,它们是“完整的”。因为这一原因,静态可执行程序不依赖任何外部库就可以运行。

第二类是动态链接的可执行程序。静态可执行程序与动态可执行程序比较

我们可以用 ldd 命令来确定某一特定可执行程序是否为静态链接的:

        //这一前提只适用于用gcc编译的情况吧
  # ldd /sbin/sln
  not a dynamic executable
  “not a dynamic executable”是 ldd 说明 sln 是静态链接的一种方式。现在,让我们比较 sln 与其非静态同类 ln 的大小:
  # ls -l /bin/ln /sbin/sln
  -rwxr-xr-x    1 root     root        23000 Jan 14 00:36 /bin/ln
  -rwxr-xr-x    1 root     root       381072 Jan 14 00:31 /sbin/sln
  sln 的大小超过 ln 十倍。ln 比 sln 小这么多是因为它是动态可执行程序。动态可执行程序是不完整的程序,它依靠外部共享库来提供运行所需的许多函数。

  动态链接相关性

  要查看 ln 依赖的所有共享库的列表,可以使用 ldd 命令://前提是因为ln为动态链接的可执行程序
  # ldd /bin/ln
  libc.so.6 => /lib/libc.so.6 (0x40021000)
  /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

  ln 依赖外部共享库 libc.so.6 和 ld-linux.so.2。通常,动态链接的程序比其静态链接的等价程序小得多。不过,静态链接的程序可以在某些低级维护任务中发挥作用。例如,sln 是修改位于 /lib 中的不同库符号链接的极佳工具。但通常您会发现几乎所有 Linux 系统上的可执行程序都是某种动态链接的变体。

  动态装入器

  那么,如果动态可执行程序不包含运行所需的所有函数,Linux 的哪部分负责将这些程序和所有必需的共享库一起装入,以使它们能正确执行呢?答案是动态装入器(dynamic loader),它实际上是您在 ln 的 ldd 清单中看到的作为共享库相关性列出的ld-linux.so.2 库。动态装入器负责装入动态链接的可执行程序运行所需的共享库。现在,让我们迅速查看一下动态装入器如何在系统上找到适当的共享库。

  ld.so.conf

  动态装入器找到共享库要依靠两个文件 — /etc/ld.so.conf 和 /etc/ld.so.cache。如果您对 /etc/ld.so.conf 文件进行 cat 操作,您可能会看到一个与下面类似的清单:

  $ cat /etc/ld.so.conf

  /usr/X11R6/lib

  /usr/lib/gcc-lib/i686-pc-linux-gnu/2.95.3

  /usr/lib/mozilla

  /usr/lib/qt-x11-2.3.1/lib

  /usr/local/lib

  ld.so.conf 文件包含一个所有目录(/lib 和 /usr/lib 除外,它们会自动包含在其中)的清单,动态装入器将在其中查找共享库。

  ld.so.cache

  但是在动态装入器能“看到”这一信息之前,必须将它转换到 ld.so.cache 文件中。可以通过运行 ldconfig 命令做到这一点:

  # ldconfig

  当 ldconfig 操作结束时,您会有一个最新的 /etc/ld.so.cache 文件,它反映您对 /etc/ld.so.conf 所做的更改。从这一刻起,动态装入器在寻找共享库时会查看您在 /etc/ld.so.conf 中指定的所有新目录。 

  ldconfig 技巧

  要查看 ldconfig 可以“看到”的所有共享库,请输入: 

  # ldconfig -p | less

  还有另一个方便的技巧可以用来配置共享库路径。有时候您希望告诉动态装入器在尝试任何 /etc/ld.so.conf 路径以前先尝试使用特定目录中的共享库。在您运行的较旧的应用程序不能与当前安装的库版本一起工作的情况下,这会比较方便。

  LD_LIBRARY_PATH

  要指示动态装入器首先检查某个目录,请将 LD_LIBRARY_PATH 变量设置成您希望搜索的目录。多个路径之间用逗号分隔;例如:

  # export LD_LIBRARY_PATH="/usr/lib/old:/opt/lib"

  导出 LD_LIBRARY_PATH 后,如有可能,所有从当前 shell 启动的可执行程序都将使用 /usr/lib/old 或 /opt/lib 中的库,如果仍不能满足一些共享库相关性要求,则转回到 /etc/ld.so.conf 中指定的库。

gcc创建和使用静态库、动态库

        下面以工程libtest为例说明gcc创建和使用静态库、动态库的过程,libtest目录结构和内容如图1所示,其中三个文件hello.h,hello.c和main.c的内容如下。

libtest/include/hello.h

#ifdef _HELLO_H_
#define _HELLO_H_
 
void hello();
 
#endif
libtest/lib/hello.c

#include "hello.h"
#include <stdio.h>
void hello()
{
    printf("hello world!\n");
}
libtest/src/main.c

#include "hello.h"
int main()
{
    hello();
}
 静态库过程如下:

(1)进入libtest/lib目录,执行命令:

       gcc -c -I../include hello.c

       该命令生成目标文件hello.o,注意:参数-I添加头文件搜索目录,这里因为hello.c中有#include “hello.h”,hello.h在libtest/include目录中,这里需要指定该目录通知gcc,否则出现错误提示“找不到头文件hello.h”。

       这一步将在libtest/lib目录中生成一个hello.o文件。

(2)在libtest/lib目录,执行命令:

       ar rc libhello.ahello.o

       该命令将hello.o添加到静态库文件libhello.a,ar命令就是用来创建、修改库的,也可以从库中提出单个模块,参数r表示在库中插入或者替换模块,c表示创建一个库,关于ar命令的详细使用规则可以参考文章http://blog.csdn.net/xuhongning/article/details/6365200。

这一步将在libtest/lib目录中生成一个libhello.a文件。

(3)进入libtest/src目录,执行命令:

       gcc main.c-I../include -L../lib -lhello -o main

       该命令将编译main.c并链接静态库文件libhello.a生成可执行文件main,注意:参数-L添加库文件搜索目录,因为libhello.a在libtest/lib目录中,这里需要指定该目录通知gcc,参数-l指定链接的库文件名称,名称不用写全名libhello.a,只用写hello即可。

       这一步将在libtest/src目录中生成可执行文件main。

动态库过程如下:

(1)      进入libtest/lib目录,执行命令:

       gcc hello.c-I../include -fPIC -shared -o libhello.so

       这一步将在当前目录生成动态库文件libhello.so,参数-fPIC -shared固定格式,不用纠结他们什么意思。

(2)      进入libtest/src目录,执行命令:

       gcc main.c-I../include -L../lib -lhello -o main

       此时在当前目录中已经生成了可执行文件main,执行./main时却提示错误:

       ./main: error while loading shared libraries: libhello.so: cannotopen shared object file: No such file or directory

也就是找不到动态库文件libhello.so,在网上找了答案说如果遇到这样的问题需要设置环境变量LD_LIBRARY_PATH,如下:

       export LD_LIBRARY_PATH=”../lib”

       gcc main.c -I../include -L../lib -lhello -o main

       然后再执行./main就没有错误了。

【补充】

       环境变量LD_LIBRARY_PATH指示动态连接器可以装载动态库的路径,在链接动态库文件前设置该变量为库文件所在路径,注意:用export LD_LIBRARY_PATH=”…”方式只是临时生效的,如果要永久有效可以写入~/.bashrc文件中,跟修改PATH类似,exportLD_LIBRARY_PATH=$LD_LIBRARY_PATH:”…”。

       当然如果有root权限的话,也可以修改/etc/ld.so.conf文件,将要添加的动态库搜索路径写入该文件中,然后调用/sbin/ldconfig来达到同样的目的。
 

猜你喜欢

转载自blog.csdn.net/zxh2075/article/details/86679140