个人博客首页(点击查看详情) -- https://blog.51cto.com/11495268
 
1、简介
    程序编译一般需要经预处理、编译、汇编和链接,在实际应用中,有些公共代码需要反复使用,就把这些代码编译成为 "库" 文件,本文 主要 描述 Linux 平台下 库文件的 创建 和 链接 相关操作(既然都看 这么底层的内容了,相信 也有一定的基础,所以本文 对相关命令 也不会进行详细解释)
Linux 环境下 gcc 链接库 编译、链接(概览) 以及 自动化工具Makefile的编写
    
备注:
    linux平台下,静态链接库是以 .a 的后缀文件,动态链接库是以 .so 的后缀文件
    widows平台下,静态链接库是以 .lib 的后缀文件,动态库文件是以 .dll 的后缀文件
    

2、库文件
    库是写好的 现有的、成熟的 一种可执行、可以复用代码的二进制形式(注,其本身不可执行),可以被操作系统载入内存执行;分为 静态链接库 和 动态链接库
    

2.1 静态库
2.1.1 简介
    静态链接库可以简单看成一组目标文件.o 的集合,即很多目标文件经过压缩打包后形成的一个文件
    

2.1.2 原理
    链接器将从 静态(链接)库 取得所需的代码,复制到生成的可执行文件
Linux 环境下 gcc 链接库 编译、链接(概览) 以及 自动化工具Makefile的编写
    

2.1.3 特点
    静态库对函数库的链接是放在程序编译时期完成
    程序在运行时对函数库再无瓜葛(因为所有相关的目标文件和牵涉到的函数库被链接合成一个可执行文件)
    浪费空间和资源(因为所有相关的目标文件和牵涉到的函数库被链接合成一个可执行文件)
    

2.1.4 创建流程
Linux 环境下 gcc 链接库 编译、链接(概览) 以及 自动化工具Makefile的编写
    

备注:
    linux下使用ar工具(windows下用lib.exe)将目标文件压缩到一起,并且对其进行编号和索引,以便于查找和索引
    

2.1.5 命令规则
    静态链接库的名称 和 库文件名称不同但有联系;例如,库名称为"static_library",那么起库文件名为"libstatic_library.a"
    

2.2 动态库
2.2.1 简介
    程序在开始运行后调用 动态(链接)库(Dynamic Link Library)中的函数 才被载入
    

2.2.2 原理
    程序编译是并不会被连接到目标代码中,而是在程序运行时才被载入
Linux 环境下 gcc 链接库 编译、链接(概览) 以及 自动化工具Makefile的编写
    

2.2.3 特点
    动态库把对一些库函数的链接载入推迟到程序运行时期
    进程之间的相同动态库实现共享
    

2.2.4 创建
    创建动态库与创建静态库不同,不需要打包工具,直接使用编译器创建动态库

# gcc -fPIC -shared -o libxxx.so xx1.c xx2.c xx3.c

    

2.2.5 命名规则
    动态链接库的名称 和 库文件名称不同但有联系;例如,库名称为"dynamic_library",那么起库文件名为"libdynamic_library.a"
    

3、库文件 编译、链接(实战操作)
3.1 静态库 编译、链接
3.1.1 静态库 源码

# cat gcc_lib_header.h
#ifndef __GCC_LIB_HEADER_H_ 
#define __GCC_LIB_HEADER_H_

#include <stdio.h>

void gcc_lib_one();
void gcc_lib_two();
void gcc_lib_three();

#endif

    

# cat gcc_lib_first.c 
/* 
    filename : gcc_lib_first.c 
*/
#include "gcc_lib_header.h"

void gcc_lib_one(){
    printf("call gcc_lib_one() function\n");
}

    

# cat gcc_lib_sec.c
/* 
    filename : gcc_lib_sec.c 
*/
    #include "gcc_lib_header.h"

void gcc_lib_two(){
    printf("call gcc_lib_two() function\n");
}

    

# cat gcc_lib_third.c
/* 
    filename : gcc_lib_third.c
*/
#include "gcc_lib_header.h"

void gcc_lib_three(){
    printf("call gcc_lib_three() function\n");
}

    

# cat gcc_lib_main.c
/* 
    filename : gcc_lib_main.c
*/
#include "gcc_lib_header.h"

int main(int argc, char *argv[])
{
    gcc_lib_one();
    gcc_lib_two();
    gcc_lib_three();

    return 0;
}

    

3.1.2 静态库 编译

# gcc -c gcc_lib_first.c
# gcc -c gcc_lib_sec.c
# gcc -c gcc_lib_third.c

# ar  cqs  libstatic_gcc.a  gcc_lib_first.o gcc_lib_sec.o gcc_lib_third.o

    

3.1.3 静态库 链接

## -L ./ 等同于 -L.
# gcc -o gcc_lib_main_static gcc_lib_main.c -L. -static -l static_gcc

# ./gcc_lib_main_static 
call gcc_lib_one() function
call gcc_lib_two() function
call gcc_lib_three() function

    

3.2 动态库 编译、链接
3.1.1 动态库 源码
    为了便于测试比较,使用 与 静态库编译相同的源码
    

3.1.2 动态库 编译

# gcc -fPIC -shared -o libdynamic_gcc.so  gcc_lib_first.c gcc_lib_sec.c gcc_lib_third.c

    

3.1.3 动态库 链接

# gcc -o gcc_lib_main_dynamic gcc_lib_main.c -L ./ -l dynamic_gcc

    

3.1.4 共享路径设置(不详细解释)

## 共享路径设置 :
##     1@:LD_LIBRARY_PATH 修改 这个全局变量
##     2@:修改 /etc/ld.so.conf 配置
## 本文 就 详细描述了,直接把 生成的共享库 cp 至 系统默认路径下
# cp libdynamic_gxx.so /usr/local/lib/

## 重新读取 库文件信息(需root用户执行)
# ldconfig

    

备注:
    如果 不设置 共享路径 或者 共享路径下 找不到 指定的 库文件,系统 就会 提示相关的错误信息:"./g++_lib_main_static: error while loading shared libraries: libstatic_gcc.so: cannot open shared object file: Error 40"
    

3.1.5 执行

## 查看 依赖库,没有问题 就执行
# ldd gcc_lib_main_dynamic
    linux-vdso.so.1 =>  (0x00007fff241e9000)
    libdynamic_gcc.so => /usr/local/lib/libdynamic_gcc.so (0x00007fe587990000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe5875c6000)
    /lib64/ld-linux-x86-64.so.2 (0x000055b1d62ea000)

# ./gcc_lib_main_dynamic 
call gcc_lib_one() function
call gcc_lib_two() function
call gcc_lib_three() function

    

4、自定义工具(Makefile)
4.1 安装 make

# apt-get install make

    

4.2 编写 Makefile

# cat Makef
default_target : help

help :
    @echo "usage : make [opt]"
    @echo "\topt arguement is one of \"static_gcc、dynamic_gcc\""

gcc_lib_first.o : gcc_lib_first.c gcc_lib_header.h
    gcc -c gcc_lib_first.c 

gcc_lib_sec.o : gcc_lib_sec.c gcc_lib_header.h
    gcc -c gcc_lib_sec.c

gcc_lib_third.o : gcc_lib_third.c gcc_lib_header.h
    gcc -c gcc_lib_third.c  

static_gcc : gcc_lib_first.o gcc_lib_sec.o gcc_lib_third.o
    ar  cqs  /tmp/libstatic_gcc.a  gcc_lib_first.o gcc_lib_sec.o gcc_lib_third.o
    gcc -o gcc_lib_main_static gcc_lib_main.c  -L /tmp -static -l static_gcc

dynamic_gcc :
    gcc -fPIC -shared -o /tmp/libdynamic_gcc.so  gcc_lib_first.c gcc_lib_sec.c gcc_lib_third.c 
    gcc -o gcc_lib_main_dynamic gcc_lib_main.c -L /tmp -l dynamic_gcc
    cp /tmp/libdynamic_gcc.so /usr/local/lib/
    ldconfig

    

4.3 执行

## 创建 静态库 链接的 可执行文件
# make static_gcc
ar  cqs  /tmp/libstatic_gcc.a  gcc_lib_first.o gcc_lib_sec.o gcc_lib_third.o
gcc -o gcc_lib_main_static gcc_lib_main.c  -L /tmp -static -l static_gcc

## 创建 动态库 链接的 可执行文件
# make dynamic_gcc
gcc -fPIC -shared -o /tmp/libdynamic_gcc.so  gcc_lib_first.c gcc_lib_sec.c gcc_lib_third.c 
gcc -o gcc_lib_main_dynamic gcc_lib_main.c -L /tmp -l dynamic_gcc
cp /tmp/libdynamic_gcc.so /usr/local/lib/
ldconfig