1. 程式人生 > >Linux 環境下 gcc 鏈接庫 編譯、鏈接(概覽) 以及 自動化工具Makefile的編寫

Linux 環境下 gcc 鏈接庫 編譯、鏈接(概覽) 以及 自動化工具Makefile的編寫

help .so 使用 規則 好的 object 源碼 fault 編寫

個人博客首頁(點擊查看詳情) -- https://blog.51cto.com/11495268
 
1、簡介
    程序編譯一般需要經預處理、編譯、匯編和鏈接,在實際應用中,有些公共代碼需要反復使用,就把這些代碼編譯成為 "庫" 文件,本文 主要 描述 Linux 平臺下 庫文件的 創建 和 鏈接 相關操作(既然都看 這麽底層的內容了,相信 也有一定的基礎,所以本文 對相關命令 也不會進行詳細解釋)
技術分享圖片
    
備註:
    linux平臺下,靜態鏈接庫是以 .a 的後綴文件,動態鏈接庫是以 .so 的後綴文件
    widows平臺下,靜態鏈接庫是以 .lib 的後綴文件,動態庫文件是以 .dll 的後綴文件
    

2、庫文件
    庫是寫好的 現有的、成熟的 一種可執行、可以復用代碼的二進制形式(註,其本身不可執行),可以被操作系統載入內存執行;分為 靜態鏈接庫 和 動態鏈接庫
    

2.1 靜態庫
2.1.1 簡介
    靜態鏈接庫可以簡單看成一組目標文件.o 的集合,即很多目標文件經過壓縮打包後形成的一個文件
    

2.1.2 原理
    鏈接器將從 靜態(鏈接)庫 取得所需的代碼,復制到生成的可執行文件
技術分享圖片
    

2.1.3 特點
    靜態庫對函數庫的鏈接是放在程序編譯時期完成
    程序在運行時對函數庫再無瓜葛(因為所有相關的目標文件和牽涉到的函數庫被鏈接合成一個可執行文件)
    浪費空間和資源(因為所有相關的目標文件和牽涉到的函數庫被鏈接合成一個可執行文件)
    

2.1.4 創建流程
技術分享圖片
    

備註:
    linux下使用ar工具(windows下用lib.exe)將目標文件壓縮到一起,並且對其進行編號和索引,以便於查找和索引
    

2.1.5 命令規則
    靜態鏈接庫的名稱 和 庫文件名稱不同但有聯系;例如,庫名稱為"static_library",那麽起庫文件名為"libstatic_library.a"
    

2.2 動態庫
2.2.1 簡介
    程序在開始運行後調用 動態(鏈接)庫(Dynamic Link Library)中的函數 才被載入
    

2.2.2 原理
    程序編譯是並不會被連接到目標代碼中,而是在程序運行時才被載入
技術分享圖片
    

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 共享路徑設置(不詳細解釋)

## 共享路徑設置 :
##     [email protected]:LD_LIBRARY_PATH 修改 這個全局變量
##     [email protected]:修改 /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

    

Linux 環境下 gcc 鏈接庫 編譯、鏈接(概覽) 以及 自動化工具Makefile的編寫