1. 程式人生 > >Linux下的C/C++開發基礎(編寫makefile、編譯C/C++、連結、可執行程式)

Linux下的C/C++開發基礎(編寫makefile、編譯C/C++、連結、可執行程式)

本文重點介紹C/C++原始碼工程的編譯連結,編譯器gcc/g++的安裝配置略過... 1. 安裝配置gcc g++ 2. 建立檔案 test.h /test.c / file.h  / file.cpp  3. 編譯.o庫: gcc -c / g++ -c     連結生成靜態庫.a庫: ar -r    連結生成動態庫.soK庫:gcc -shared -o/ g++ -shared -o    編譯可執行程式並連結.a或.so 庫 g++ -o file file.cpp -L. -ltest / gcc -o test test.c -L. -lfile    執行可執行程式 ./file  / ./test    note:l指定庫名稱,優先連結so動態庫,沒有動態庫再連結.a靜態庫;          如果連結的是靜態庫就可以直接運行了,如果連結的是動態庫可能會提示:./cppmain: error while loading shared libraries: libCAdd.so: cannot open shared object file: No such file or directory,是因為Linux系統程式和Windows不一樣,Linux系統只會從系統環境變數指定的路徑載入動態庫,可以把生成的動態庫放到系統目錄,或者執行export LD_LIBRARY_PATH=./設定當前路徑為系統連結庫目錄就可以了。

3.1 編譯 C調C++庫     a. 編譯C++ .o 庫:                g++ -c file.cpp     b. 連結生成靜態 .a庫:             ar -r libfile.a file.o     c. 編譯C檔案並連結 .a庫生成可執行程式:    gcc -o test test.c -L. -llibfile     d. 執行可執行程式:                ./test

3.2 編譯C++調C庫     a. 編譯C .o庫:                gcc -c test.c     b. 連結生成靜態.a 庫:            ar -r libtest.a test.o     c. 編譯C++檔案並連結.a 庫生成可執行程式:     g++ file file.cpp -L. -llibtest     d. 執行可執行程式:                ./file

4. 檢視符號表: $ nm test.o 0000000000000000 T test $ nm test1.o 0000000000000000 T _Z4testiPc C語言編譯後的函式符號還是原函式名,而C++編譯後的函式符號由test變成了_Z4testiPc,test前面有個數字4應該是函式名長度,test後面i Pc應該就是函式的引數簽名。C++之所以這樣規定編譯後的函式符號是因為對面物件的C++具有函式過載功能,以此來區分不同的函式。

5. linux下的.o .a .so .o,是目標檔案,相當於windows中的.obj檔案  .a為靜態庫,是好多個.o合在一起,用於靜態連線 .so 為共享庫,是shared object,用於動態連線的,相當於windows下的dll  程式的執行都要經過編譯和連結兩個步驟。假如檔案test.c,使用命令gcc -c test.c進行編譯,生成test.o中間檔案,使用命令ar -r libtest.a test.o可以生成libadd.a靜態庫檔案。靜態庫檔案其實就是對.o中間檔案進行的封裝,使用nm libtest.a命令可以檢視其中封裝的中間檔案以及函式符號。  連結靜態庫就是連結靜態庫中的.o檔案,這和直接編譯多個檔案再連結成可執行檔案一樣。 動態連結庫是程式執行的時候直接呼叫的“外掛”,使用命令gcc -shared -o libtest.so test.c生成so動態庫。 動態庫連結的時候可以像靜態庫一樣連結,告訴編譯器函式的定義在這個靜態庫中(避免找不到函式定義的錯誤),只是不把這個so打包到可執行檔案中。如果沒有標頭檔案的話,可以使用dlopen/dlsum函式手動去載入相應的動態庫

6.linux下的Makefile編寫: 6.1 純C或純C++檔案: test: test.o test1.o test2.o     gcc test.o test1.o test2.o -o libtest  #-o連結成可執行程式 test.o: test.c       gcc -c test.c -o test.o  #加-c 指定生成為可重連結.o檔案 test1.o: test1.c     gcc -c test1.c -o test1.o test2.o: test2.c     gcc -c test2.c -o test2.o

.PHONY:clean clean:     -rm -rf *.o libtest

每個命令列前必須要有tab符號(如Makefile中書寫方法); 上面的Makefile檔案就是要編譯出一個libtest的可執行檔案; test:test.o test1.o test2.o :test依賴於test.o test1.o、test2.o三個目標檔案; gcc test.o test1.o test2.o -o libtest:編譯出可執行檔案libtest, -o表示指定可執行檔案的名稱; test.o: test.c: test.o 依賴於 test.c 檔案; gcc -c test.c -o test.o 編譯出test.o檔案,-c表示只把給它的檔案編譯成目標檔案,用原始碼檔案的檔名命名,但把其後綴由“.c”變成“.o”;也可以省略 -o test.o ,編譯器預設生成test.o clean: rm -rf *.o firstTest:當鍵入make clean的時候,會刪除所有.o檔案和libtest檔案 如果要編譯c++檔案,把gcc改成g++即可。如果一行寫的內容過多,可以用“\”來分解多行,注意“\”後面不加空格.

6.2 C/C++混合編譯:

CC = gcc C++ = g++ LINK = g++

#LIBS = -lz -lm -lpcre(#如果還要連結其他庫如libz、libm、libpcre等,加上這句) #must add -fPIC option CCFLAGS = $(COMPILER_FLAGS) -c -g -fPIC C++FLAGS = $(COMPILER_FLAGS) -c -g -fPIC

TARGET=libtestmain

INCLUDES = -I. -I../../

C++FILES = testmain.cpp  CFILES = test.c test1.c test2.c

OBJFILE = $(CFILES:.c=.o) $(C++FILES:.cpp=.o)

all:$(TARGET)

$(TARGET): $(OBJFILE)     $(LINK) $^ $(LIBS) -Wall -fPIC (編so加 -shared)-o [email protected]

%.o:%.c     $(CC) -o [email protected] $(CCFLAGS) $< $(INCLUDES)

%.o:%.cpp     $(C++) -o [email protected] $(C++FLAGS) $< $(INCLUDES)

install:     tsxs -i -o $(TARGET)

clean:     rm -rf $(TARGET)     rm -rf $(OBJFILE)

上面的Makefile是實現編譯C檔案編譯成.o,然後一起連線到cpp編譯的.o(或.so)上編譯出可執行檔案; note: a.如果LIBS的位置放置不對,這幾個基礎庫將不會編進so中。LIBS只應該在最後連結為so時才呼叫,前面編譯c和cpp檔案時用不到。 b.c原始檔放到CFILES巨集後面, cpp檔案放到C++Files巨集後面,第三方庫放到LIBS巨集後面,標頭檔案的包含路徑放到INCLUDES後面,庫檔案的包含路徑放到使用-L./等表示式放到LIBS中的開頭即可。 c.這裡嚴格區分c和cpp檔案的目的是,c檔案使用gcc編譯,而cpp檔案會使用g++編譯,它們必須嚴格區分開。