Linux下靜態庫/動態庫製作及gcc命令詳解

(一)概述

       一個C語言程序從編寫完成到執行需要經歷預處理(生成.i)->編譯(生成.s)->彙編(生成.o)->鏈接(生成可執行文件)幾個步驟,如下圖所示。
在這裏插入圖片描述

(二)gcc命令參數詳解

這裏推薦一篇講解的比較全面的博客——GCC常用參數詳解
我們最常用的gcc編譯選項主要有以下幾個:

  • (1) 無選項鍊接
    gcc test.o -o test
    將編譯輸出文件test.o鏈接成最終可執行文件test。

  • (2) -c
      只激活預處理->編譯->彙編,也就是他只把程序做成obj文件。
      例子用法:
      gcc -c hello.c
      他將生成.o的obj文件
      gcc -c test.s
      將彙編輸出文件test.s編譯輸出test.o文件。

  • (3) -S
      只激活預處理和編譯,就是指把文件編譯成爲彙編代碼。
      例子用法:
      gcc -S hello.c
      他將生成.s的彙編代碼,你可以用文本編輯器察看
      gcc -S test.i
      將預處理輸出文件test.i彙編成test.s文件

  • (4) -E
      只激活預處理,這個不生成文件,你需要把它重定向到一個輸出文件裏面.
      例子用法:
      gcc -E hello.c >; pianoapan.txt
      gcc -E hello.c | more
      一個hello word 也要與處理成1000+行的代碼
      gcc -E test.c -o test.i

  • (5) -o
      制定目標名稱,缺省的時候,gcc 編譯出來的文件是a.out,很難聽,如果你和我有同感,改掉它,哈哈
      例子用法:
      gcc -o hello.exe hello.c (哦,windows用習慣了)
      gcc -o hello.asm -S hello.c

  • (6) -l參數和-L參數
    -l參數就是用來指定程序要鏈接的庫,-l參數緊接着就是庫名,那麼庫名跟真正的庫文件名有什麼關係呢?就拿數學庫來說,他的庫名是m,他的庫文件名是libm.so,很容易看出,把庫文件名的頭lib和尾.so去掉就是庫名了。
    好了現在我們知道怎麼得到庫名了,比如我們自已要用到一個第三方提供的庫名字叫libtest.so,那麼我們只要把libtest.so拷貝到/usr/lib裏,編譯時加上-ltest參數,我們就能用上libtest.so庫了(當然要用libtest.so庫裏的函數,我們還需要與libtest.so配套的頭文件)。
    放在/lib和/usr/lib和/usr/local/lib裏的庫直接用-l參數就能鏈接了,但如果庫文件沒放在這三個目錄裏,而是放在其他目錄裏,這時我們只用-l參數的話,鏈接還是會出錯,出錯信息大概是:“/usr/bin/ld: cannot find -lxxx”,也就是鏈接程序ld在那3個目錄裏找不到libxxx.so,這時另外一個參數-L就派上用場了,比如常用的X11的庫,它放在/usr/X11R6/lib目錄下,我們編譯時就要用-L/usr/X11R6/lib -lX11參數,-L參數跟着的是庫文件所在的目錄名。再比如我們把libtest.so放在/aaa/bbb/ccc目錄下,那鏈接參數就是-L/aaa/bbb/ccc -ltest。

(三)靜態鏈接和動態鏈接

以下是幾篇講的比較好的博客:

       靜態鏈接就是在執行之前講已經編譯好的靜態庫加載鏈接合併到程序中,而動態鏈接則是在程序運行的時候動態加載鏈接庫(當碰到內存中已經加載進來該庫的時候,只進行虛擬地址空間的映射,這樣可以提升內存利用率)。其實#include<stdio.h>只是定義了printf這些函數的函數原型,具體的代碼要在鏈接的過程中才會被加載進來。

  • 下面使用靜態庫編譯程序生成可執行代碼
    在這裏插入圖片描述
    在這裏插入圖片描述
  • 下面使用動態庫編譯程序生成可執行代碼
    在這裏插入圖片描述
  • 其中Pow_test.c的源代碼如下:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
    unsigned int x, y;
    unsigned long long res;
    if((argc < 3) || (sscanf(argv[1], "%u", &x) != 1) || (sscanf(argv[2], "%u", &y) != 1))
    {
        printf("Usage: pow base exponent\n");
        exit(1);
    }
    res = unsgn_pow(x, y);
    printf("%u ^ %u = %u\n", x, y, res);
    return 0;
}

  • 其中unsgn_pow.c的源代碼如下:
unsigned long long unsgn_pow(unsigned int x, unsigned int y)
{
    unsigned long long res = 1;
    if(!y)
    {
        res = 1;
    }
    else if(y == 1)
    {
        res = x;
    }
    else
    {
        res = x * unsgn_pow(x, y - 1);
    }
    return res;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章