《電話號碼管理系統(tǒng)》制作成靜態(tài)庫和動態(tài)庫
一、前言
上次寫了一篇關(guān)于Makefile的文章。
《利用Makfile給多文件、多目錄C源碼建立工程》
有很多粉絲留言,有的粉絲想進(jìn)一步了解cmake的使用方法,還有的粉絲想知道如何將一些函數(shù)編譯成動態(tài)庫或者靜態(tài)庫,然后再將該庫編譯到內(nèi)存中。
一口君必須安排,本篇先講如何將一些函數(shù)編譯成動態(tài)庫或者靜態(tài)庫。
這就涉及到一個庫的概念,關(guān)于制作的庫的基礎(chǔ)知識,一口君已經(jīng)在下面這篇文章中詳細(xì)的講述了相關(guān)概念,建議大家先看下面這篇文章。
《Linux庫概念,動態(tài)庫和靜態(tài)庫概念》
本文,一口君將繼續(xù)以之前的 電話號碼管理系統(tǒng)的項目為基礎(chǔ),給大家詳細(xì)講解如何將該項目中的函數(shù)制作成動態(tài)庫和靜態(tài)庫。
《從0寫一個《電話號碼管理系統(tǒng)》的C入門項目》
二、 基礎(chǔ)知識
1) 靜態(tài)庫
所謂靜態(tài)庫,就是在靜態(tài)編譯時由編譯器到指定目錄尋找并且進(jìn)行鏈接,一旦鏈接完成,最終的可執(zhí)行程序中就包含了該庫文件中的所有有用信息,包括代碼段、數(shù)據(jù)段等。
2)動態(tài)庫
所謂動態(tài)庫,就是在應(yīng)用程序運行時,由操作系統(tǒng)根據(jù)應(yīng)用程序的請求,動態(tài)到指定目錄下尋找并裝載入內(nèi)存中,同時需要進(jìn)行地址重定向。
3)庫文件命名
靜態(tài)庫的名字一般為libxxxx.a,其中xxxx是該lib的名稱;動態(tài)庫的名字一般為libxxxx.so.x.y.z,含義如下圖所示:
4)制作庫文件常用參數(shù)
首先需要了解gcc編譯庫要用到一些參數(shù),很重要。
三、 制作靜態(tài)庫
原始文件目錄如下:
- peng@ubuntu:/mnt/hgfs/code/phone3$ tree .
- .
- ├── main.c
- ├── phone.c
- └── phone.h
- 0 directories, 3 files
其中 phone.c包含了對鏈表的所有的操作函數(shù) phone.h 是phone.c中所有函數(shù)的原型說明 main.c是主程序
下面我們將phone.c制作成靜態(tài)庫。
1. 把 listd.c 編譯成.o文件
- peng@ubuntu:/mnt/hgfs/code/phone3$ gcc -c phone.c
2. 使用 ar 命令生成靜態(tài)庫libadd.a
靜態(tài)庫名字遵循靜態(tài)庫命名的規(guī)則 lib + 名字 + .a
peng@ubuntu:/mnt/hgfs/code/phone3$ ar -rc libphone.a phone.o
3. 將庫和頭文件拷貝到其他目錄下
將庫文件移動到lib目錄下
- peng@ubuntu:/mnt/hgfs/code/phone3$ mkdir lib
- peng@ubuntu:/mnt/hgfs/code/phone3$ mv libphone.a lib
移動頭文件到include目錄下
- peng@ubuntu:/mnt/hgfs/code/phone3$ mkdir include
- peng@ubuntu:/mnt/hgfs/code/phone3$ mv phone.h include/
刪除phone.c
- peng@ubuntu:/mnt/hgfs/code/phone3$ rm phone.c
此處可不刪除,下面的的編譯已經(jīng)用不到該文件 刪除僅僅是為了排除干擾,有些同學(xué)會以為這個文件還會被編譯進(jìn)去
最終文件結(jié)構(gòu)如下:
- peng@ubuntu:/mnt/hgfs/code/phone3$ tree ./
- ./
- ├── include
- │ └── phone.h
- ├── lib
- │ └── libphone.a
- ├── main.c
- └── run
- 2 directories, 6 files
lib include 目錄也可以是其他目錄,實際項目中庫文件和頭文件都會放到一些指定目錄下
4.編譯
值編譯main.c,會有以下錯誤提示,主要是因為phone.h
- peng@ubuntu:/mnt/hgfs/code/phone3$ gcc main.c
- main.c:3:19: 致命錯誤:phone.h:沒有那個文件或目錄
- 編譯中斷。
制定頭文件位置,編譯結(jié)果如下,可以看到錯誤提示,“沒有定義create”,這是因為在鏈接的時候找打不到這些函數(shù)的定義的地方
- peng@ubuntu:/mnt/hgfs/code/phone3$ gcc main.c -I ./include
- /tmp/cctUUKm9.o: In function `management':
- main.c:(.text+0x109): undefined reference to `create'
- main.c:(.text+0x120): undefined reference to `delete'
- main.c:(.text+0x137): undefined reference to `search'
- main.c:(.text+0x14e): undefined reference to `display'
- main.c:(.text+0x167): undefined reference to `allfree'
- /tmp/cctUUKm9.o: In function `main':
- main.c:(.text+0x2e3): undefined reference to `init'
- collect2: ld 返回 1
最終我們執(zhí)行
- peng@ubuntu:/mnt/hgfs/code/phone3$ gcc main.c -I ./include ./lib/libphone.a
指定了頭文件和庫文件位置,執(zhí)行結(jié)果如下:
與之前運行現(xiàn)象是一樣的。
可見,使用庫的時候我們必須制定頭文件目錄以及庫目錄。
四、 制作動態(tài)庫原始文件
- peng@ubuntu:/mnt/hgfs/code/phone3$ tree .
- .
- ├── main.c
- ├── phone.c
- └── phone.h
- 0 directories, 3 files
1. 把phone.c編譯成動態(tài)鏈接庫libphone.so
- gcc -fPIC -o libphone.o -c phone.c
- gcc -shared -o libphone.so libphone.o
也可以直接使用一條命令
- gcc -fPIC -shared -o libphone.so phone.c
2. 動態(tài)庫的安裝
通常動態(tài)庫拷貝到/lib下:
- peng@ubuntu:/mnt/hgfs/code/phone4$ sudo mv libphone.so /lib/
- [sudo] password for peng:
刪除phone.c
- peng@ubuntu:/mnt/hgfs/code/phone3$ rm phone.c
3. 編譯執(zhí)行
編譯動態(tài)庫:
- peng@ubuntu:/mnt/hgfs/code/phone4$ gcc main.c -lphone -o run
此時使用我們制作的動態(tài)庫,只需要加上 -lphone即可
- 注意觀察編譯時動態(tài)庫的名字與庫文件對應(yīng)關(guān)系
- libphone.so<--------->-lphone
執(zhí)行結(jié)果如下:
五、重新建立工程
下面我們將文件重新放置
當(dāng)前文件目錄如下:
- ./include
- └── phone.h
- ./Makefile
- ./obj
- └── Makefile
- ./src
- ├── main.c
- └── Makefile
- 0 directories, 5 files
并添加3個Makefile
編譯步驟如下:
聲明環(huán)境變量
- CC 編譯名稱
- LIBS 用到的動態(tài)庫
- SUBDIRS 子目錄
- OBJS src下所有的目標(biāo)文件
- BIN 最終生成的可執(zhí)行程序名字
- OBJS_DIR 目標(biāo)文件存放目錄
- BIN_DIR 可執(zhí)行程序存儲目錄
執(zhí)行make的默認(rèn)目標(biāo)all,依賴CHECK_DIR $(SUBDIRS)
執(zhí)行目標(biāo)CHECK_DIR ,創(chuàng)建目錄bin
執(zhí)行目標(biāo)@ ,進(jìn)入子目錄src、obj執(zhí)行子目錄的Makefile,
打印語句 echo begin compile phone!
進(jìn)入子目錄src執(zhí)行Makfile,
執(zhí)行命令
- @$(CC) -c main.c -I../include -o ../$(OBJS_DIR)/main.o
- @ :打印該條命令
- -I../include 頭文件在上一級目錄下的include中
- -o ../$(OBJS_DIR)/main.o 生成的目標(biāo)文件存放在../obj/main.o
進(jìn)入子目錄obj執(zhí)行Makfile, 目標(biāo)為../bin/phone:main.o 執(zhí)行命令
- @$(CC) -o $@ $^ $(LIBS)
- @$(CC) 同上
- $@ 表示生成的目標(biāo)文件,即../bin/phone
- $^ 表示所有的依賴文件,即上面:后面目標(biāo)文件main.o
編譯完成后就會在bin目錄下創(chuàng)建可執(zhí)行程序文件phone, 運行結(jié)果如下:
本文轉(zhuǎn)載自微信公眾號「一口Linux」