編寫庫函數和Makefile

一.什麼是庫函數:
C語言中有一些函數會執行一些標準任務,可以事先對這些函數進行編譯,然後將他們放置在一些特殊的目標代碼文件中,這些目標代碼文件稱爲庫,庫文件中的函數可以通過連接程序與應用程序進行鏈接,這樣就不用在每次執行程序時都對這些通用的函數進行編譯了。
標準的C函數庫名稱爲libc,包含了諸如內存管理或者輸入輸出操作的基本函數,這些庫放置在/usr/lib下,系統中的任何用戶都可以利用這些庫函數,用戶也可以自己建立庫。
庫的兩種形式:靜態庫;共享庫(動態庫)
二.靜態庫/動態庫:
1)基本概念:
靜態庫又稱爲文檔文件(Archive File)。它是多個.o文件的集合。Linux中靜態庫文件的後綴爲".a"。
靜態庫的代碼在編譯時就已經鏈接到應用程序中
靜態庫中的各個成員(.o文件)沒有特殊的存在格式,僅僅是一個.o文件的集合。
使用"ar"工具維護和管理靜態庫
2)如何建立和使用靜態庫
看下面的例子,包含四個文件test.c test.h main.c Makefile:
1. 編寫源文件 
test.c
# include "test.h"
# include <stdio.h>

void mystrcpy(char *des, const char *src)
   while (*des++ = *src++);
}

int mysum(int a, int b)
{
    int sum = a + b;
    return sum; 
}

void myshow(int* arrary ,int len)
{
    for (int i = 0; i < len; i++)
    {
        printf ("%d ",arrary[i]);
    }
    printf("\n");
}
test.h
#ifndef TEST_H_
#define TEST_H_
# include <stdio.h>

void mystrcpy(char *des, const char *src);
int mysum(int a, int b);
void myshow(int* arrary ,int len);

#endif

編寫測試代碼:
main.c
# include "test.h"

int main()
    {
    char a[10] = "abcdef";
    char b[10] = "\0";
int c = 50;
int d = 11;
    mystrcpy(b,a);
    int e = d + c;
    printf ("b : %s\n",b);
printf ("e : %d\n",e);
    return 0; 
    }
編寫Makefile:
file :a.out b.out

test.o:test.c
gcc -o $@ -c $^
test.a:test.o 
ar rcs $@ $^
rm -rf test.o
a.out:main.c test.a
gcc -o $@ main.c ./test.c -ldl
libtest.so:test.c
gcc -o $@ -fPIC -shared $^
b.out:main.c libtest.so
gcc -o $@ main.c -L ./ -ltest -ldl 

clean:
rm -rf a.out b.out test.o
clean1:
rm -rf a.out b.out test.o test.a libtest.so
說明:
ar的三個參數中:r代表將文件插入歸檔文件中,c代表建立歸檔文件,s代表若歸檔文件中包含了對象模式,可利用此參數建立備存文件的符號表。
lib和.a都是系統指定的靜態庫文件的固定格式,test纔是靜態庫的名稱,編譯時,鏈接器會在標準路徑(/usr/lib;/lib)或者用戶指定的路徑下去找.a的文件。
使用 -fPIC 選項,會生成 PIC 代碼。.so 要求爲 PIC,以達到動態鏈接的目的,否則,無法實現動態鏈接
用make編譯所有文件,make clean/clean1 執行刪除操作 
$@代指冒號前內容,$^代指冒號後內容,冒號前是要生成的文件,之後是被依賴的文件
使用靜態庫可以使程序不依賴於任何其他庫而獨立運行,但是會佔用很多內存空間以及磁盤空間,而且如果庫文件更新,則需重新編譯源代碼,使用起來不夠靈活。
a.out 比 b.out 大,是因爲靜態庫是在編譯時把所有庫文件拷貝到可執行文件中,而動態庫則是按需拷貝,比如show()函數沒有用到,就不再拷貝

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