溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

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

發(fā)布時間:2020-07-03 05:41:15 來源:網(wǎng)絡 閱讀:4386 作者:堅韌的石頭 欄目:編程語言

個人博客首頁(點擊查看詳情) -- https://blog.51cto.com/11495268
 
1、簡介
    程序編譯一般需要經(jīng)預處理、編譯、匯編和鏈接,在實際應用中,有些公共代碼需要反復使用,就把這些代碼編譯成為 "庫" 文件,本文 主要 描述 Linux 平臺下 庫文件的 創(chuàng)建 和 鏈接 相關操作(既然都看 這么底層的內(nèi)容了,相信 也有一定的基礎,所以本文 對相關命令 也不會進行詳細解釋)
Linux 環(huán)境下 gcc 鏈接庫 編譯、鏈接(概覽) 以及 自動化工具Makefile的編寫
    
備注:
    linux平臺下,靜態(tài)鏈接庫是以 .a 的后綴文件,動態(tài)鏈接庫是以 .so 的后綴文件
    widows平臺下,靜態(tài)鏈接庫是以 .lib 的后綴文件,動態(tài)庫文件是以 .dll 的后綴文件
    

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

2.1 靜態(tài)庫
2.1.1 簡介
    靜態(tài)鏈接庫可以簡單看成一組目標文件.o 的集合,即很多目標文件經(jīng)過壓縮打包后形成的一個文件
    

2.1.2 原理
    鏈接器將從 靜態(tài)(鏈接)庫 取得所需的代碼,復制到生成的可執(zhí)行文件
Linux 環(huán)境下 gcc 鏈接庫 編譯、鏈接(概覽) 以及 自動化工具Makefile的編寫
    

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

2.1.4 創(chuàng)建流程
Linux 環(huán)境下 gcc 鏈接庫 編譯、鏈接(概覽) 以及 自動化工具Makefile的編寫
    

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

2.1.5 命令規(guī)則
    靜態(tài)鏈接庫的名稱 和 庫文件名稱不同但有聯(lián)系;例如,庫名稱為"static_library",那么起庫文件名為"libstatic_library.a"
    

2.2 動態(tài)庫
2.2.1 簡介
    程序在開始運行后調(diào)用 動態(tài)(鏈接)庫(Dynamic Link Library)中的函數(shù) 才被載入
    

2.2.2 原理
    程序編譯是并不會被連接到目標代碼中,而是在程序運行時才被載入
Linux 環(huán)境下 gcc 鏈接庫 編譯、鏈接(概覽) 以及 自動化工具Makefile的編寫
    

2.2.3 特點
    動態(tài)庫把對一些庫函數(shù)的鏈接載入推遲到程序運行時期
    進程之間的相同動態(tài)庫實現(xiàn)共享
    

2.2.4 創(chuàng)建
    創(chuàng)建動態(tài)庫與創(chuàng)建靜態(tài)庫不同,不需要打包工具,直接使用編譯器創(chuàng)建動態(tài)庫

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

    

2.2.5 命名規(guī)則
    動態(tài)鏈接庫的名稱 和 庫文件名稱不同但有聯(lián)系;例如,庫名稱為"dynamic_library",那么起庫文件名為"libdynamic_library.a"
    

3、庫文件 編譯、鏈接(實戰(zhàn)操作)
3.1 靜態(tài)庫 編譯、鏈接
3.1.1 靜態(tài)庫 源碼

# 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 靜態(tài)庫 編譯

# 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 靜態(tài)庫 鏈接

## -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 動態(tài)庫 編譯、鏈接
3.1.1 動態(tài)庫 源碼
    為了便于測試比較,使用 與 靜態(tài)庫編譯相同的源碼
    

3.1.2 動態(tài)庫 編譯

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

    

3.1.3 動態(tài)庫 鏈接

# 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 至 系統(tǒng)默認路徑下
# cp libdynamic_gxx.so /usr/local/lib/

## 重新讀取 庫文件信息(需root用戶執(zhí)行)
# ldconfig

    

備注:
    如果 不設置 共享路徑 或者 共享路徑下 找不到 指定的 庫文件,系統(tǒng) 就會 提示相關的錯誤信息:"./g++_lib_main_static: error while loading shared libraries: libstatic_gcc.so: cannot open shared object file: Error 40"
    

3.1.5 執(zhí)行

## 查看 依賴庫,沒有問題 就執(zhí)行
# 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 執(zhí)行

## 創(chuàng)建 靜態(tài)庫 鏈接的 可執(zhí)行文件
# 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

## 創(chuàng)建 動態(tài)庫 鏈接的 可執(zhí)行文件
# 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

    

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI