首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C语言 >

全面温习linux C语言系列-第二讲-GCC编译器

2012-12-21 
全面复习linux C语言系列--第二讲--GCC编译器???1.编译过程简述:?? 1.1 预编译????? 1.1.1 宏定义指令????

全面复习linux C语言系列--第二讲--GCC编译器

?

?

?

1.编译过程简述:

?

? 1.1 预编译

?

???? 1.1.1 宏定义指令

?

??????? #define #undef

?

???? 1.1.2 条件编译指令


例子: debug? , debug.c 内容如下

?

#include <stdio.h>main(){        #ifdef DEBUG        fprintf(stderr,"debug infomation \n");        #endif}

?

?

在测试环境上 我们使用下面的命令编译:

?

cc debug.c -DDEBUG -o debug

?

他的执行结果:

?

[root@xhu-vm 5]# ./debug
debug infomation
[root@xhu-vm 5]#

?

我们看到了debug 信息

?

上了生产环境,这样编译:

?

[root@xhu-vm 5]# cc debug.c -o debug

?

执行结果:

[root@xhu-vm 5]# ./debug
[root@xhu-vm 5]#

没有输出debug信息

?

? 1.2 编译

?

? 1.3 优化和汇编

?

?

2.链接过程

?

? 2.1 在debug的例子上在加上一句 打印的测试代码,使用 编译-链接-执行 来完成这个例子

?

#include <stdio.h>main(){        #ifdef DEBUG        fprintf(stderr,"debug infomation \n");        #endif        fprintf(stderr,"just a test!\n");}
?

?

?

a. 使用 [root@xhu-vm 5]# gcc -c debug.c?? 生成.o 目标文件 debug.o

?

b. 使用 [root@xhu-vm 5]# gcc debug.o -o debug 将目标文件链接成可执行文件

?

c. 查看结果

[root@xhu-vm 5]# ./debug
just a test!
[root@xhu-vm 5]#

?

d.使用dumpobj 反编译.o 目标文件

?

?

[root@xhu-vm 5]# objdump -d debug.odebug.o:     file format elf32-i386Disassembly of section .text:00000000 <main>:   0:   55                      push   %ebp   1:   89 e5                   mov    %esp,%ebp   3:   83 ec 08                sub    $0x8,%esp   6:   83 e4 f0                and    $0xfffffff0,%esp   9:   b8 00 00 00 00          mov    $0x0,%eax   e:   83 c0 0f                add    $0xf,%eax  11:   83 c0 0f                add    $0xf,%eax  14:   c1 e8 04                shr    $0x4,%eax  17:   c1 e0 04                shl    $0x4,%eax  1a:   29 c4                   sub    %eax,%esp  1c:   83 ec 08                sub    $0x8,%esp  1f:   68 00 00 00 00          push   $0x0  24:   ff 35 00 00 00 00       pushl  0x0  2a:   e8 fc ff ff ff          call   2b <main+0x2b>  2f:   83 c4 10                add    $0x10,%esp  32:   c9                      leave    33:   c3                      ret    [root@xhu-vm 5]# 
?

2.2?? 动态链接和静态链接

?

静态链接:[root@xhu-vm 5]# gcc debug.o -o debug

动态链接:[root@xhu-vm 5]# gcc -s debug.c -o debug.s

运行:

[root@xhu-vm 5]# ./debug.s
just a test!
[root@xhu-vm 5]#

?

我们可以看到 静态链接 产生的文件体积要小

?

[root@xhu-vm 5]# lltotal 20-rwxr-xr-x  1 root root 4818 Jun  7 06:41 debug-rw-r--r--  1 root root  127 Jun  7 06:37 debug.c-rw-r--r--  1 root root  920 Jun  7 06:37 debug.o-rwxr-xr-x  1 root root 3000 Jun  7 07:04 debug.s[root@xhu-vm 5]#
?

2.3? 用GCC 生成可执行文件

?

例子目的: 按照c 项目的目录结构,建立inc,src,lib等目录,建立.h, .c,.lib文件 ,完成调用自己lib中的加法功能,其他程序可以静态链接这个.a 库文件 ,并使用其中的方法

?

a. 目录结构

?

?

[root@xhu-vm pro1]# pwd/root/c_project/source code/5/pro1[root@xhu-vm pro1]# lltotal 12drwxr-xr-x  2 root root 4096 Jun  7 08:13 incdrwxr-xr-x  2 root root 4096 Jun  7 08:13 libdrwxr-xr-x  2 root root 4096 Jun  7 08:18 src

b. 在src 目录下写 tool.c ,并使用 gcc 将其编译成.o的目标文件

?

?

[root@xhu-vm src]# more tool.c #include <stdio.h>int add(int x ,int y){        return x+y;}[root@xhu-vm src]# 

?

[root@xhu-vm src]# cc -c tool.c [root@xhu-vm src]# lltotal 8-rw-r--r--  1 root root  58 Jun  7 08:18 tool.c-rw-r--r--  1 root root 684 Jun  7 08:21 tool.o[root@xhu-vm src]# 

?

c. 将 tool.o形成 库文件,方便其他程序调用add方法,其中 libtools.a? 的命名必须规范,以lib开头,以.a结尾

[root@xhu-vm src]# ar rv libtools.a tool.oar: creating libtools.aa - tool.o[root@xhu-vm src]# 
?

d. 编写tool1.c 实现减法操作

?

[root@xhu-vm src]# vi tool1.c#include <stdio.h>int sub(int x,int y){        return x-y;}

?编译成.o 文件

?

[root@xhu-vm src]# lltotal 20-rw-r--r--  1 root root 824 Jun  7 08:28 libtools.a-rw-r--r--  1 root root  57 Jun  7 08:31 tool1.c-rw-r--r--  1 root root 689 Jun  7 08:31 tool1.o-rw-r--r--  1 root root  58 Jun  7 08:18 tool.c-rw-r--r--  1 root root 684 Jun  7 08:21 tool.o[root@xhu-vm src]# 

?

?

将tool1.o放到libtools.a库文件中

?

[root@xhu-vm src]# ar rv libtools.a tool1.oa - tool1.o
?

查看 libtools.a包含哪些目标文件,可见加法和减法的目标文件都 已经放到库文件中去了

?

[root@xhu-vm src]# ar tv libtools.arw-r--r-- 0/0    684 Jun  7 08:21 2011 tool.orw-r--r-- 0/0    689 Jun  7 08:31 2011 tool1.o[root@xhu-vm src]# 

?

将库文件 移动到lib下

?

[root@xhu-vm src]# mv libtools.a ../lib/

?

?

e.在inc下 编写 .h 头文件

?

[root@xhu-vm inc]# vi my.h#define VALUE 100

?f. 编写a.c

?

[root@xhu-vm src]# vi a.c#include <stdio.h>#include "my.h"main(){        fprintf(stderr,"VALUE + 10=%d\n",add(VALUE,10));}
?

g. 编译 a.c 生成a.o , -I 指定头文件路径

?

[root@xhu-vm src]# gcc -c -I../inc a.c [root@xhu-vm src]# lltotal 24-rw-r--r--  1 root root  96 Jun  7 08:44 a.c-rw-r--r--  1 root root 964 Jun  7 08:46 a.o-rw-r--r--  1 root root  57 Jun  7 08:31 tool1.c-rw-r--r--  1 root root 689 Jun  7 08:31 tool1.o-rw-r--r--  1 root root  58 Jun  7 08:18 tool.c-rw-r--r--  1 root
?

?

h. 链接并执行,查看结果 ,-L 指定库文件路径 -l 指定库文件名称

?

[root@xhu-vm src]# gcc a.o -L../lib -ltools -o a[root@xhu-vm src]# ./a VALUE + 10=110[root@xhu-vm src]# 
?

?

2.4 用GCC 生成 动态链接库

?

?例子目的: 使用gcc生成一个.so的动态链接库

?

a. 建立 pro2目录,在下面建立一个 包含加法 运算的 a.c文件

?

[root@xhu-vm pro2]# vi a.c{main()#include <stdio.h>int add(int x,int y){        return x+y;}

?

b. 使用 -fPIC 编译源文件,生成可以重定位的目标代码,对于需要被动态链接的函数库,这点尤其重要。

?

[root@xhu-vm pro2]# gcc -fPIC -c a.c [root@xhu-vm pro2]# lltotal 8-rw-r--r--  1 root root  57 Jun  8 13:14 a.c-rw-r--r--  1 root root 681 Jun  8 13:15 a.o[root@xhu-vm pro2]# 

?c.? 使用gcc -shared -o libabc.so xxx.o 生成动态链接库 ,其中 libabc.so 的命名必须规范,以lib开头,以.so结尾

?

[root@xhu-vm pro2]# gcc -shared -o libabc.so a.o[root@xhu-vm pro2]# lltotal 16-rw-r--r--  1 root root   57 Jun  8 13:14 a.c-rw-r--r--  1 root root  681 Jun  8 13:15 a.o-rwxr-xr-x  1 root root 4152 Jun  8 13:22 libabc.so

?d. 使用动态链接库

???? 2种方式:

?

1. 一是通过设置环境变量LD——LIBRARY_PATH的方式 (这种方式比较常用

2. 二是通过dlopen系列系统调用动态打开的方式

?

使用方式1,先写b.c ,包含main

?

[root@xhu-vm pro2]# vi b.c#include <stdio.h>main(){        fprintf(stderr,"%d\n",add(1,1));}

?

e. 编译b.c 文件

?

[root@xhu-vm pro2]# gcc -c -O b.c [root@xhu-vm pro2]# lltotal 24-rw-r--r--  1 root root   57 Jun  8 13:14 a.c-rw-r--r--  1 root root  681 Jun  8 13:15 a.o-rw-r--r--  1 root root   64 Jun  8 13:33 b.c-rw-r--r--  1 root root  936 Jun  8 13:34 b.o-rwxr-xr-x  1 root root 4152 Jun  8 13:22 libabc.so
?

f. 生成可执行文件

[root@xhu-vm pro2]# gcc b.o -L./ -labc -s -o b[root@xhu-vm pro2]# lltotal 28-rw-r--r--  1 root root   57 Jun  8 13:14 a.c-rw-r--r--  1 root root  681 Jun  8 13:15 a.o-rwxr-xr-x  1 root root 3272 Jun  8 13:35 b-rw-r--r--  1 root root   64 Jun  8 13:33 b.c-rw-r--r--  1 root root  936 Jun  8 13:34 b.o-rwxr-xr-x  1 root root 4152 Jun  8 13:22 libabc.so[root@xhu-vm pro2]# 

?

-L 指定库文件所在的目录

-l? 指定库文件的名字?? ,系统会搜索 libabc.a 静态库文件 和? libabc.so 的动态库文件

-s 只搜索扩展名为.so的库文件

-o 指定输出文件名字

?

g. 运行可执行文件,报错了 找不到 共享的库文件,原因是我们没有设置环境变量

?

[root@xhu-vm pro2]# ./b ./b: error while loading shared libraries: libabc.so: cannot open shared object file: No such file or directory[root@xhu-vm pro2]# 

设置了? LD_LIBRARY_PATH 这个环境变量 指定动态库的位置 后 我们得到了 1+1=2 的结果

?

[root@xhu-vm pro2]# export LD_LIBRARY_PATH=./[root@xhu-vm pro2]# ./b 2[root@xhu-vm pro2]# 
?

?

使用方式2 : 使用了系统的dlopen系列函数 (程序启动的时候并不加载,等需要使用的时候再加载)

?

[root@xhu-vm pro2]# vi c.cint *pdata = NULL;#include <stdio.h>#include <dlfcn.h>int (*fcn)(int,int) = NULL;int load(const char *libname){    void *handle;    handle = dlopen(libname, RTLD_NOW);    if (handle == NULL)    {        fprintf(stderr,"Failed to load %s: %s\n",libname, dlerror());        return 1;    }    fcn = dlsym(handle,"add");    if (fcn == NULL)    {        fprintf(stderr,"%s\n",dlerror());        dlclose(handle);        return 1;    }    /* 加载完不能dlclose,必须等到不再使用从handle中加载出的任何东西时才能dlclose*/    return 0;}int main(){    if (load("./libabc.so"))    {        return 1;    }    int result = fcn(2,2);    printf("%d\n",result);    return 0;}
?
[root@xhu-vm pro2]# gcc -o c -ldl c.c[root@xhu-vm pro2]# ./c 4[root@xhu-vm pro2]# 

?

?

?

Note:? 使用dlsym 函数不仅可以得到 动态库中 函数的指针,也可以得到 动态库中的全局变量的指针,从而得到全局变量的值,我们产品的agent framework 就是这样的,在so加载的时候用 dlsym 方式得到 一个全局变量aa, 这个aa 代表了 所有能操的op_list 集合,然后用 得到函数指针,最后调用方法, 下面有个例子

?

a.在 so 中定义2个全局变量,一个是float,一个是char[],在 caller中得到他们的地址

?

?

a.c

#include <stdio.h>  float test=123.4;char test2[]="xhu";int add(int x,int y)  {          return x+y;  }

编译 : gcc -fPIC -c a.c? ->> 得到a.o

打包so? gcc -shared -o libabc.so a.o

?

测试程序 c.c

?

#include <stdio.h>  #include <dlfcn.h>    char* fcn=NULL;  float* ff=NULL;   int load(const char *libname)    {        void *handle;        handle = dlopen(libname, RTLD_LAZY);        if (handle == NULL)        {            fprintf(stderr,"Failed to load %s: %s\n",libname, dlerror());            return 1;        }            fcn =(char*)dlsym(handle,"test2");      ff = (float*)dlsym(handle,"test");      if (fcn == NULL)        {            fprintf(stderr,"%s\n",dlerror());            dlclose(handle);            return 1;        }            /* 加载完不能dlclose,必须等到不再使用从handle中加载出的任何东西时才能dlclose*/        return 0;    }        int main()    {        if (load("../lib/libabc.so"))        {            return 1;        }       char* result = fcn;      printf("%s\n",result);      float* result2 = ff;    printf("%f\n",*result2);    return 0;    } 
?

编译: gcc -o c -ldl c.c? >> 得到c

?

执行:

?

[root@egovmo03 src]# ./c
xhu
123.400002

?

打完收工

?

?

?

?

?

?

?

?

?

?

?

?

?

热点排行