Linux 环境开发--gcc 编译以及动态连接

    • 简介
    • 一些基础概念
    • 常用编译选项
    • 静态库和共享库
    • 实例
    • 总结


简介

GNU编译器套装(英语:GNU Compiler Collection,缩写为GCC),一套编程语言编译器,以GPL及LGPL许可证所发布的自由软件,也是GNU项目的关键部分,也是GNU工具链的主要组成部份之一。GCC(特别是其中的C语言编译器)也常被认为是跨平台编译器的事实标准。1985年由理查德·马修·斯托曼开始发展,现在由自由软件基金会负责维护工作。

原名为GNU C语言编译器(GNU C Compiler),因为它原本只能处理C语言。GCC很快地扩展,变得可处理C++。之后也变得可处理Fortran、Pascal、Objective-C、Java、Ada,以及Go与其他语言。

许多操作系统,包括许多类Unix系统,如Linux及BSD家族都采用GCC作为标准编译器。苹果电脑Mac OS X 操作系统也采用这个编译器。

原本用C开发,后来因为LLVM、Clang的崛起,令GCC更快将开发语言转换为C++。许多C的爱好者在对C++一知半解的情况下主观认定C++的性能一定会输给C,但是Taylor给出了不同的意见,并表明C++不但性能不输给C,而且能设计出更好,更容易维护的程序(GCC’s move to C++)。
ps: 摘自 wiki http://zh.wikipedia.org/zh-cn/GCC

一些基础概念

一些文件:

后缀名 含义 后缀名 含义
.o c 代码文件 .s/.S 汇编语言原始程序
.c/.cc/.cxx C++ 代码文件 .h 预处理文件(头文件)
.m Objective-C 代码文件 .o 可重定向文件
.i 经过预处理的 C 代码文件 .a/.so 编译后的库文件
.ii 经过预处理的 C++ 代码文件

gcc的编译流程分为了四个步骤:

预处理(Pre-Processing—->编译(Compiling)—–>汇编(Assembling)—–>链接(Linking)

常用编译选项

gcc有超过100个的可用选项,主要包括总体选项、告警和出错选项、优化选项和体系结构相关选项。这里列一些常用选项

选项 含义
-c 生成目标文件“.o”
-S 生成汇编代码
-E 只进行预编译
-g 在可执行程序中包含标准调试信息
-o 输出文件
-v 打印出编译过程
-I 添加头文件搜索目录
-L 添加库搜索目录
-static 生成链接静态库
-llibrary 连接名为library的库文件(注意没有空格)
-fPIC 地址无关代码
-shared 生成共享库

关于 -fPIC 选项是使共享库能使代码可以在多个进程间共享,需要一些汇编知识和代码运行堆栈机制知识,其实我还没怎么搞懂,给个博文地址研究研究吧
http://www.cnblogs.com/catch/p/3857964.html

静态库和共享库*

  • 静态库: 在linux中一般以 libxxx.a命名.静态库中包含了所有代码和数据,在编译时会把代码和数据拷贝合并到可执行文件当中.因此,静态库是编译时需要的,不是执行时需要的.
  • 共享库:在linux中一般以libxxx.M.N.so命名,MN为主副版本号,so文件当中有自己的代码和函数,当可执行文件运行并调用动态库中的文件时需要借助连接程序 ld 把控制全交给动态库中执行.

Linux系统中动态链接库的配置文件一般在/etc/ld.so.conf文件内,它里面存放的内容是可以被Linux共享的动态联库所在的目录的名字. /etc/ld.so.cache 是 /lib/ /usr/lib/ 目录下 /etc/ld.so.conf 中的记录 /etc/ld.so.conf.d/ 目录下所有文件的记录的缓存.动态加载时系ld 加载器会从这个缓存中找共享库的位值(这里要注意和windows不同,linux不会从可执行文件所在的目录搜索共享库,如果是临时使用可以使用命令ldconfig `pwd`)

实例

下面举个实例说明:
cat.c

#include 
void cat_say(){
    printf("I am cat\n");
}

mouse.c

#include 
void mouse_say(){
    printf("I am cat\n");
}

animal.h

#ifndef __ANIMAL_H__
void cat_say();
void mouse_say();
#endif

main.c

#include 
#include "animal.h"
int main(){
    cat_say();
    exit(0);
}
[aquarius@localhost libtest]$ ll
-rw-rw-r--: 1 aquarius aquarius 65 Mar  1 15:16 animal.h
-rw-rw-r--: 1 aquarius aquarius 63 Mar  1 17:05 cat.c
-rw-rw-r--: 1 aquarius aquarius 78 Mar  1 15:20 main.c
-rw-rw-r--: 1 aquarius aquarius 67 Mar  1 15:21 mouse.c
  • 直接生成可执行文件
[aquarius@localhost libtest]$ gcc -o main main.c cat.c 
[aquarius@localhost libtest]$ ./main 
I am cat
  • 使用静态库
[aquarius@localhost libtest]$ gcc -c cat.c mouse.c
[aquarius@localhost libtest]$ ll *.o
-rw-rw-r--. 1 aquarius aquarius 1488 Mar  8 22:09 cat.o
-rw-rw-r--. 1 aquarius aquarius 1488 Mar  8 22:09 mouse.o
[aquarius@localhost libtest]$ ar -crv libanimal.a cat.o mouse.o
a - cat.o
a - mouse.o
[aquarius@localhost libtest]$ gcc -o main main.c -L. -lanimal
[aquarius@localhost libtest]$ ./main
I am cat

-L. 选项: 库搜索目录列表添加当前目录(注意后面有个点,没有空格)
-lanimal 选项: 连接名位libanimal.a后者libanimal.M.N.so的库文件,M为主版本号N为副版本号(注意 l 后面没有空格)

  • 使用共享库
[aquarius@localhost libtest]$ gcc -fPIC -shared -o libanimal.so cat.c mouse.c
[aquarius@localhost libtest]$ gcc -o main main.c -L. -lanimal.1.0
[aquarius@localhost libtest]$ ./main 
./main: error while loading shared libraries: libanimal.1.0.so: cannot open shared object file: No such file or directory

出错了,为什么呢, 用 ldd 命令看一下依赖关系

[aquarius@localhost libtest]$ ldd ./main
        linux-vdso.so.1 =>  (0x00007fff921f8000)
        libanimal.1.0.so => not found
        libc.so.6 => /lib64/libc.so.6 (0x00007fd5d0fd7000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fd5d13bc000)
[aquarius@localhost libtest]$ sudo ldconfig `pwd`  

找不到动态库,为什么呢,上面说了,没有配置 ld 加载缓存

[aquarius@localhost libtest]$ ldd ./main
        linux-vdso.so.1 =>  (0x00007fff477fb000)
        libanimal.1.0.so => /home/aquarius/libtest/libanimal.1.0.so (0x00007f45cb476000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f45cb0b8000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f45cb69f000)
[aquarius@localhost libtest]$ ./main 
I am cat

总结

好了,这就是linux下用gcc编译程序的过程和一些总结,但是在实际生成环境中真的是这样编译代码的吗?
当然不是的,这个过程只是为了学习一下gcc的编译过程以及静态库和共享库的一些知识,在实际生产环境中是使用 make 工具进行管理工程和编译的以及安装卸载的,make 工具需要 Makefile 文件,那么这个 Makefile 文件是手动编写的吗?
当然可以手动编写,但生产环境一般是用 automake 工具进行自动生成 Makefile 文件的(就是你编译安装软件是用的 ./configure)这个工具的使用篇幅也不小,有空在写吧…
小弟正在学习当中,有错误请大神指出,赐教^_^—-Aquarius_Coder

你可能感兴趣的:(Linux)