在Linux下如何使用GCC编译程序、简单生成静态库及动态库。

本文介绍如何在Linux环境下使用GCC编译程序、生成静态库及动态库。涵盖编译过程详解、静态库与动态库的创建及应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Linux下如何使用GCC编译程序、简单生成 静态库及动态库。   本文适用于Linux下开发初学者。本文初步讲解在Linux下如何使用GCC编译程序、简单生成静态库及动态库。

一、关于安装。一般系统默认是安装好编译器的,并且网络上有大量资料介绍不同发行版本下的安装问题,本文不再描述。

二、C编程中的文件后缀名介绍
    .a 静态库(打包文件)
    .c 未经过预处理的C源码
    .h C头文件   
    .i 经过预处理的C源码
    .o 编译之后产生的目标文件
    .s 生成的汇编语言代码
    .so 动态库(动态链接库)
    解释:*.a是我们在编译过后用ar打包生成的静态库;*.c一般使我们自己编辑的代码,使我们劳动的结晶;*.h一般是 我们手工生成的接口文件,如果愿意,也可在*.c完成后用GCC的选项-aux-info帮我们生成;*.i是经过预处理后的源码,是由GCC在选项-E编译下自动生成 的文件;*.o是编 译后产生的目标文件;*.s是GCC在选项-S编译下生成的汇编语言代码,对于性能要求很高的程序可以先生成汇编语言文件并对汇编做优化,然后用优 化后的汇编生成目标文件并链接;*.so是动态库,通过GCC的-fpic -shared选项生成。

三、hello.c的编译过程

    本小节的演示都针对文件 hello.c 进行

  1. /*

  2.  * hello.c

  3.  */


  4.   #include <stdio.h>

  5.   int  main()

  6.   {

  7.     printf("hello, world!/n");

  8.     return 0;

  9.   }

1. 直接生成可执行程序

  1. $ gcc -o hello hello.c

  2. $ ./hello

  3. hello, world!


  4. 如 下编译方式 结果相同:

  5. $ gcc hello.c -o hello

  6. $ ./hello

  7. hello, world!


  8. 如 下编译方式 有别于以上编译方 案(具体查找ELF和a.out文件格式差别的网络资料,对于此处结果是无任何区别的):

  9. $ gcc hello.c 

  10. $ ./a.out 

  11. hello, world!


2. 生成预处理后的文件 hello.i

  1. $ gcc -E hello.c -o hello.i

  2. $ ls

  3. a.out  hello  hello.c  hello.i

  4. hello.i 就 是新生成的文件


  5. 如下语句结果相同:

  6. $ gcc -E -o hello.i hello.c 


  7. 如 果不设定输出文件,则打印到标准终端,此时我们可以用 less 查看:

  8. $ gcc -E hello.c | less

  9. # 1 "hello.c"

  10. # 1 "<built-in>"

  11. # 1 "<command line>"

  12. # 1 "hello.c"

  13. # 1 "/usr/include/stdio.h" 1 3 4

  14. # 28 "/usr/include/stdio.h" 3 4

  15. # 1 "/usr/include/features.h" 1 3 4

  16. # 329 "/usr/include/features.h" 3 4

  17. ..............................


  18. 或 者执行:

  19. $ gcc -E hello.c -o hello.i

  20. $ vi hello.i

  21.   1 # 1 "hello.c"

  22.   2 # 1 "<built-in>"

  23.   3 # 1 "<command line>"

  24.   4 # 1 "hello.c"

  25.   5 # 1 "/usr/include/stdio.h" 1 3 4

  26.   6 # 28 "/usr/include/stdio.h" 3 4

  27.   7 # 1 "/usr/include/features.h" 1 3 4

  28.   8 # 329 "/usr/include/features.h" 3 4


  29. .......... < 中间部分略> ..................


  30. 929 # 844 "/usr/include/stdio.h" 3 4

  31. 930 

  32. 931 # 2 "hello.c" 2

  33. 932 

  34. 933 int main()

  35. 934 {

  36. 935         printf("hello, world!/n");

  37. 936 

  38. 937         return 0;

  39. 938 }


  40. 可 见,将近1000行的代码,我们的只占了最末8行。


3.生成汇编语言文件 hello.s

  1. $ gcc -S hello.c -o hello.s

  2. $ ls

  3. a.out  hello  hello.c  hello.i  hello.s

  4. hello.s 就是新生成的文件


  5. 如下语句结果相同:

  6. $ gcc -S -o hello.s hello.c


  7. 如 下语句结果相同:

  8. $ gcc -S hello.c


  9. 也 可以采用前一步骤产生的中间文件生成汇编文件:

  10. $ gcc -S hello.i -o hello.s

  11. $ gcc -S -o hello.s hello.i

  12. $ gcc -S hello.i



  13. 生 成的汇编部分代码如下:

  14. $ vi hello.s 

  15.   1         .file   "hello.c"

  16.   2         .section        .rodata

  17.   3 .LC0:

  18.   4         .string "hello, world!"

  19.   5         .text

  20.   6 .globl main

  21.   7         .type   main, @function

  22.   8 main:

  23.   9         leal    4(%esp), %ecx

  24.  10         andl    $-16, %esp

  25.  11         pushl   -4(%ecx)

  26.  12         pushl   %ebp

  27. // 注释:如果你熟悉,就可以对部分汇编优化以达到更好效果。

4.生成目标文件 hello.o

  1. $ gcc -c hello.c -o hello.o

  2. $ ls

  3. a.out  hello  hello.c  hello.i  hello.o  hello.s

  4. hello.o 就是新生成的目标文件:


  5. 如下语句结果相同:

  6. $ gcc -c -o hello.o hello.c 


  7. 如 下语句结果相同:

  8. $ gcc -c hello.c


  9. 也 可以采用前面步骤产生的中间文件hello.i或hello.s来生成目标文件:

  10. $ gcc -c hello.i

  11. $ gcc -c hello.s


  12. 我 们可以用 objdump 查看 hello.o 的二进制码:

  13. $ objdump -s hello.o


  14. hello.o:     file format elf32-i386


  15. Contents of section .text:

  16.  0000 8d4c2404 83e4f0ff 71fc5589 e55183ec  .L$.....q.U..Q..

  17.  0010 04c70424 00000000 e8fcffff ffb80000  ...$............

  18.  0020 000083c4 04595d8d 61fcc3             .....Y].a..     

  19. Contents of section .rodata:

  20.  0000 68656c6c 6f2c2077 6f726c64 2100      hello, world!.  

  21. Contents of section .comment:

  22.  0000 00474343 3a202847 4e552920 342e312e  .GCC: (GNU) 4.1.

  23.  0010 31203230 30373031 30352028 52656420  1 20070105 (Red 

  24.  0020 48617420 342e312e 312d3532 2900      Hat 4.1.1-52).  

5. 采用中间级文件生成可执行程序

  1. $ gcc -o hello hello.i

  2. $ ./hello

  3. hello, world!


  4. $ gcc -o hello hello.s

  5. $ ./hello

  6. hello, world!


  7. $ gcc -o hello hello.o

  8. $ ./hello

  9. hello, world!

四、 静态库的生成
    linux下静态库的生成比较方便。在生成目标文件后用 ar 打包即可。在中大型项目中一个模块一般会做成一个静态库,以方便管理、提高编译、链接效率。
    本小节的展示针对 main.c、func1.c、func2.c三个文件

  1. /*

  2.  * main.c

  3.  */

  4. #include <stdio.h>


  5. extern int func1();

  6. extern int func2();


  7. int main()

  8. {

  9.         int i;


  10.         i = func1();

  11.         printf("func1 return = %d/n",i);


  12.         i = func2();

  13.         printf("func2 return = %d/n",i);


  14.         return 0;

  15. }


-----------------------------------------------------

  1. /*

  2.  * func1.c

  3.  */

  4. int func1()

  5. {

  6.         return 100;

  7. }

-----------------------------------------------------

  1. /*

  2.  * func2.c

  3.  */

  4. int func2()

  5. {

  6.         return 200;

  7. }

一 下是编译指 令:

  1. $ gcc -c func1.c

  2. $ gcc -c func2.c

  3. $ ls

  4. func1.c  func1.o  func2.c  func2.o  main.c


  5. func1.o 和 func2.o 是 我们生成的目标文件。打包指令如下:

  6. $ ar -r libfunc.a func1.o func2.o


  7. 我 们查看 libfunc.a 中的文件:

  8. $ ar -t libfunc.a 

  9. func1.o

  10. func2.o


  11. 现 在用静态库和 main.c 共同生成目标程序:

  12. $ gcc -o main main.c libfunc.a

  13. $ ./main 

  14. func1 return = 100

  15. func2 return = 200


  16. 和 我们的预期相符合。下面我们进入动态库。



五、动态库的生成
    linux下动态库的生成通过GCC选项实现。案例程序和静态库中的相同。一下是操作指令:

  1. 首 先我们生成目标文件,但是需要加编译器选项 -fpic 和链接器选项 -shared

  2. $ gcc -fpic -c func1.c

  3. $ gcc -fpic -c func2.c

  4. $ gcc -shared -o libfunc.so func1.o func2.o

  5. $ ls

  6. func1.c  func1.o  func2.c  func2.o  libfunc.so  main.c


  7. libfunc.so 就是我们生成的目标动态库。我们用动态库和 main.c 生成目标程序:

  8. $ gcc -o main main.c -L. -lfunc


  9. 注 意,我们用 -L. -lfunc 作为编译选项。-L. 表从当前目录查找需要的动态库,-lfunc 是动态库的调用规则。Linux系统下的动态库命名方 式是 lib*.so,而在链接时表示位 -l* , *是自己起的库名。下面我们运行它:


  10. $ ./main 

  11. ./main: error while loading shared libraries: libfunc.so: cannot open shared object file: No such file or directory


  12. 提 示一个错误, 指示无法找到动态库。在linux下最方便的解决方案是拷贝libfunc.so到绝对目录 /lib 下。但是只有超级用户才有这个权限。另外一个方案 是更改环境变量 LD_LIBRARY_PATH。如下:

  13. $ $ export LD_LIBRARY_PATH=`pwd`

  14. $ ./main 

  15. func1 return = 100

  16. func2 return = 200


  17. 运 行成功。现在我们更改动态库的函数而不重新链接。如下:

  18. 更改 func1.c 为:

  19. int func1()

  20. {

  21.         return 101;

  22. }

  23. 更 改 func2.c 为:

  24. int func2()

  25. {

  26.         return 202;

  27. }

  28. 重 新生成库:

  29. $ gcc -fpic -shared func1.c func2.c -o libfunc.so

  30. $ ./main 

  31. func1 return = 101

  32. func2 return = 202


  33. 可 以看出,动态库已经更新了。

六、结束语
    本文简单介绍了linux下如何使用gcc进行编译程序、以及简 单的静态、动态库的生成。静态库提供了一种打包管理方案,而动态库使程序局部更新成为了可能,更重要的是,当有多份实例存在时,动态库可减小内存的消耗 (只占用一份代码空间)。
    对本系列知识感兴趣者可继续跟踪阅读后续文章:库的版本管理、GCC的编译选项、Makefile与自动化编译


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值