標籤:makefile
0.前言 從學習C語言開始就慢慢開始接觸makefile,查閱了很多的makefile的資料但總感覺沒有真正掌握makefile,如果自己動手寫一個makefile總覺得非常吃力。所以特意藉助部落格總結makefile的相關知識,通過例子說明makefile的具體用法。 例說makefile大致分為4個部分 1.只有單個C檔案 2.含有多個C檔案 3.需要包括標頭檔路徑 4.增加宏定義 5.增加系統共用庫 6.增加自訂共用庫 7.一個實際的例子 【代碼倉庫】——makefile-example 代碼倉庫位於bitbucket,可藉助TortoiseHg(GUI工具)複製代碼或者在網頁中直接下載zip包。 【本例說明】 本例分為兩個過程,先製作一個共用庫,然後在使用這個共用庫。共用庫採用動態連結方式,尾碼為.so。 1.gcc複習 【1】gcc指令中使用共用庫使用首碼-l,共用庫尋找目錄使用-L。 【2】一般情況下DLIBS中加入共用庫,而LDFLAGS中加入共用庫尋找目錄。
2.共用庫源檔案 和產生共用庫有關的檔案位於libtest目錄中,在makefile最後把共用庫複製到同級的lib目錄中。具體內容請參考代碼倉庫並複製zip包。 【libtest.h】 指定介面,給出相應聲明
#ifndef __LIBTEST_H#define __LIBTEST_Hint sub(int a, int b);int add(int a, int b);#endif
【test-add.c】
int add(int a, int b){ return a+b;} 【test-sub.c】
int sub(int a, int b){ return a-b;}
3.共用庫的makefile 請替換其中的[tab],並以代碼倉庫中的makefile檔案為主。
# 指令編譯器和選項CC = gccCFLAGS = -Wall -std=gnu99# 目標檔案TARGET = libtest.so# C檔案SRCS = test-add.c test-sub.c# 目標檔案OBJS = $(SRCS:.c=.o)# 連結為可執行檔$(TARGET):$(OBJS)[tab]$(CC) -shared -o [email protected] $^[tab]mv $(TARGET) ../libclean:[tab]rm -rf $(TARGET) $(OBJS)# 編譯規則 [email protected]代表目標檔案 $< 代表第一個依賴檔案%.o:%.c[tab]$(CC) $(CFLAGS) -o [email protected] -fPIC -c $<
【說明】 【1】目標為libtest.so,請務必以lib開頭 .so結尾,在使用該共用庫時系統會自動的去除lib和.so,使用時寫成-ltest。 【2】多數內容和學習筆記中的多個檔案相同。 【3】在連結過程中加入-shared參數,意為共用形式的目標檔案。 【4】在編譯過程中加入-fPIC參數,意為產生和地址無關的目標檔案。 【5】在連結完成之後,通過mv指令把libtest.so移動到同級的lib目錄中。 【6】如果有必要,可以把libtest.so複製到/usr/lib目錄中,這樣使用起來會更加方便。
【驗證】
ldd test
linux-vdso.so.1 => (0x00007fffde960000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ffe55b18000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffe55750000)
/lib64/ld-linux-x86-64.so.2 (0x00007ffe55e38000)
【編譯和執行】 make clean && make
【控制台輸出】rm -rf libtest.so test-add.o test-sub.o
gcc -Wall -std=gnu99 -o test-add.o -fPIC -c test-add.c
gcc -Wall -std=gnu99 -o test-sub.o -fPIC -c test-sub.c
gcc -shared -o libtest.so test-add.o test-sub.o
mv libtest.so ../lib
【1】編譯過程中加入了-fPIC選項。
【2】連結過程中加入-shared選項。
【3】共用庫為libtest.so。
【4】最後,共用庫被移動到上一級的lib目錄中。
4.源檔案 調用共用庫指定的介面,add和sub函數。
#include <stdio.h>#include <libtest.h>int main(void){ int a = 3; int b = 2; printf("a=%d\n", a); printf("b=%d\n", b); printf("a+b=%d\n", add(a, b)); printf("a-b=%d\n", sub(a, b)); return 0;} 5.makefile 請替換其中的[tab],並以代碼倉庫中的makefile檔案為主。
# 指令編譯器和選項CC = gccCFLAGS = -Wall -std=gnu99# 目標檔案TARGET = test# C檔案SRCS = test.c# 標頭檔尋找路徑INC = -I.# 庫檔案和庫尋找路徑DLIBS = -ltestLDFLAGS = -L./lib# 指定運行時的庫檔案路徑RPATH = -Wl,-rpath=./lib# 目標檔案OBJS = $(SRCS:.c=.o)# 連結為可執行檔$(TARGET):$(OBJS)[tab]$(CC) -o [email protected] $^ $(LDFLAGS) $(DLIBS) $(RPATH)clean:[tab]rm -rf $(TARGET) $(OBJS)# 連續動作,請清除再編譯連結,最後執行exec:clean $(TARGET)[tab]@echo 開始執行[tab]./$(TARGET)[tab]@echo 執行結束# 編譯規則 [email protected]代表目標檔案 $< 代表第一個依賴檔案%.o:%.c[tab]$(CC) $(CFLAGS) $(INC) -o [email protected] -c $<
6.具體說明 【1】DLIBS = -ltest 指定共用庫,請注意共用庫的名稱為libtest.so,而-l參數只取test部分,去掉首碼lib和尾碼.so。 【2】LDFLAGS = -L./lib 指定共用庫路徑,請注意上一步中已經把共用庫複製到lib目錄中。 【3】INC = -I./lib 指定libtest.h目錄,也可把libtest.h複製到test.c所在的目錄。 【4】$(CC) -o [email protected] $^ $(LDFLAGS) $(DLIBS) 連結過程指定共用庫尋找路徑,指定共用庫名稱。 【5】第【1】和第【2】點只在連結過程有效,在執行過程中需要通過-Wl,-rpath=<path>指定共用庫路徑。 【編譯和連結】 make clean && make 【控制台輸出】rm -rf test test.o
gcc -Wall -std=gnu99 -I./lib -o test.o -c test.c
gcc -o test test.o -L./lib -ltest -Wl,-rpath=./lib
【執行】 在執行之前還可以通過ldd test查看libtest是否連結成功。./test
a=3
b=2
a+b=5
a-b=1 從控制台的輸出結果可以看出,共用庫運行正常。
7.總結 【1】-l指定共用庫名稱,-L指定共用庫路徑。
8.參考資料 【1】gcc中的-Wl,rpath=<your_lib_dir>選項 【2】makefile學習經驗(三)----編譯產生動態庫檔案(方式一)