把源碼編譯打包爲動態庫so文件,做平臺的可能對這些不熟悉。
對我們這些算是經常用到的。
總結個模板,一看就懂的那種,提供給有需要的人。
前提條件,機器上有 gcc工具鏈。
如果文件個數少,可以直接單個編譯,如下:
Building shared lib...
g++ -c -fPIC Quote.cpp -o Quote.o
g++ -c -fPIC QuoteExport.cpp -o QuoteExport.o
g++ -c -fPIC Start.cpp -o Start.o
Generating shared lib...
g++ -shared -fPIC -o libQuoteLib.so ./Quote.o ./QuoteExport.o ./Start.o
cp libQuoteLib.so ../
OK!
如果文件個數較多,或者誇文件夾了,層層嵌套。
那麼就整個makefile模板文件,放到代碼的根目錄下,直接執行一個make即可。
模板文件如下:
############################################################################
#makefile,created by yangyongzhen qq:534117529
############################################################################
#****************************************************************************
# Cross complie path
#****************************************************************************
#GCC_PATH=D:\msysgit\mingw
CROSS_COMPILE=
CC := $(CROSS_COMPILE)gcc
CXX := $(CROSS_COMPILE)g++
AS := $(CROSS_COMPILE)as
AR := $(CROSS_COMPILE)ar
LD := $(CROSS_COMPILE)ld
RANLIB := $(CROSS_COMPILE)ranlib
OBJDUMP:= $(CROSS_COMPILE)objdump
OBJCOPY:= $(CROSS_COMPILE)objcopy
STRIP := $(CROSS_COMPILE)strip
#****************************************************************************
# Flags
#****************************************************************************
CFLAGS=
LDSCRIPT=
LDFLAGS=
#****************************************************************************
# Source files
#****************************************************************************
SRC_C=$(shell find . -name "*.cpp")
OBJ_C=$(patsubst %.cpp, %.o, $(SRC_C))
SRCS := $(SRC_C) $(SRC_C)
OBJS := $(OBJ_C)
#****************************************************************************
# Targets of the build
#****************************************************************************
TARGET := libQuoteLib
.PHONY: clean
all: prebuild $(TARGET).so
#****************************************************************************
# TARGET
#****************************************************************************
prebuild:
@echo Building shared lib...
$(TARGET).so : $(OBJS)
@echo Generating shared lib...
$(CXX) -shared -fPIC -o $(TARGET).so $(OBJS)
cp $(TARGET).so ../
@echo OK!
%.o : %.cpp
$(CXX) -c -fPIC $(CFLAGS) $< -o $@
clean:
@echo The following files:
rm -f $(TARGET) *.so
find . -name "*.[od]" |xargs rm
@echo Removed!
注:在linux上,源文件的函數或方法前,不需要聲明 __declspec(dllexport)
在WIn32上才需要。
所以在頭文件中一般會看到:
#ifdef _WIN32
#define TAP_CDECL __cdecl
#define TAP_DLLEXPORT __declspec(dllexport)
#else
#define TAP_CDECL
#define TAP_DLLEXPORT
#endif
__cdecl 是C Declaration的縮寫(declaration,聲明),表示C語言默認的函數調用方法:所有參數從右到左依次入棧,這些參數由調用者清除,稱爲手動清棧。
被調用函數不會要求調用者傳遞多少參數,調用者傳遞過多或者過少的參數,甚至完全不同的參數都不會產生編譯階段的錯誤。
_stdcall 是StandardCall的縮寫,是C++的標準調用方式:所有參數從右到左依次入棧,如果是調用類成員的話,最後一個入棧的是this指針。這些堆棧中的參數由被調用的函數在返回後清除,使用的指令是 retnX,X表示參數佔用的字節數,CPU在ret之後自動彈出X個字節的堆棧空間。稱爲自動清棧。函數在編譯的時候就必須確定參數個數,並且調用者必須嚴格的控制參數的生成,不能多,不能少,否則返回後會出錯。
C中不加說明默認函數爲_cdecl方式(C中也只能用這種方式),C++也一樣,但是默認的調用方式可以在IDE環境中設置。
帶有可變參數的函數必須且只能使用_cdecl方式
__cdecl __fastcall與__stdcall,三者都是調用約定(Calling convention),它決定以下內容:1)函數參數的壓棧順序,2)由調用者還是被調用者把參數彈出棧,3)以及產生函數修飾名的方法。
1、__stdcall調用約定:函數的參數自右向左通過棧傳遞,被調用的函數在返回前清理傳送參數的內存棧。
2、__cdecl是C和C++程序的缺省調用方式。每一個調用它的函數都包含清空堆棧的代碼,所以產生的可執行文件大小會比調用_stdcall函數的大。函數採用從右到左的壓棧方式。注意:對於可變參數的成員函數,始終使用__cdecl的轉換方式。
3、__fastcall調用約定:它是通過寄存器來傳送參數的(實際上,它用ECX和EDX傳送前兩個雙字(DWORD)或更小的參數,剩下的參數仍舊自右向左壓棧傳送,被調用的函數在返回前清理傳送參數的內存棧)。
4、thiscall僅僅應用於"C++"成員函數。this指針存放於CX寄存器,參數從右到左壓。thiscall不是關鍵詞,因此不能被程序員指定。
5、nakedcall採用1-4的調用約定時,如果必要的話,進入函數時編譯器會產生代碼來保存ESI,EDI,EBX,EBP寄存器,退出函數時則產生代碼恢復這些寄存器的內容。naked call不產生這樣的代碼。naked call不是類型修飾符,故必須和_declspec共同使用。
關於__declspec的解釋,轉自:CSDN博主「fengbingchun」
原文鏈接:https://blog.csdn.net/fengbingchun/article/details/78825004
__declspec是Microsoft VC中專用的關鍵字,它配合着一些屬性可以對標準C/C++進行擴充。__declspec關鍵字應該出現在聲明的前面。
__declspec(dllexport)用於Windows中的動態庫中,聲明導出函數、類、對象等供外面調用,省略給出.def文件。即將函數、類等聲明爲導出函數,供其它程序調用,作爲動態庫的對外接口函數、類等。
.def文件(模塊定義文件)是包含一個或多個描述各種DLL屬性的Module語句的文本文件。.def文件或__declspec(dllexport)都是將公共符號導入到應用程序或從DLL導出函數。如果不提供__declspec(dllexport)導出DLL函數,則DLL需要提供.def文件。
__declspec(dllimport)用於Windows中,從別的動態庫中聲明導入函數、類、對象等供本動態庫或exe文件使用。當你需要使用DLL中的函數時,往往不需要顯示地導入函數,編譯器可自動完成。
不使用__declspec(dllimport)也能正確編譯代碼,但使用__declspec(dllimport)使編譯器可以生成更好的代碼。編譯器之所以能夠生成更好的代碼,是因爲它可以確定函數是否存在於DLL中,這使得編譯器可以生成跳過間接尋址級別的代碼,而這些代碼通常會出現在跨DLL邊界的函數調用中。聲明一個導入函數,是說這個函數是從別的DLL導入。一般用於使用某個DLL的exe中。
---------------------