Linux動態庫.a與動態庫.so的生成與區別、以及.so庫檔案的封裝與使用
一、前言
如果有公司需要使用你們產品的一部分功能(通過程式碼呼叫這些功能),如果不想提供原始碼,那麼就可以通過封裝成庫檔案的形式提供給對方使用。本文主要介紹了生成動態庫與靜態庫檔案的過程、以及封裝和使用庫檔案的方法。
二、靜態庫.a與動態庫.so的生成與區別
.o檔案 :二進位制目標檔案,可用於打包成庫檔案也可以連結生成可執行檔案;
c檔案編譯後連結,生成可執行檔案
gcc test1.c test2.c test3.c test_main.c -o test_main
./test_main
將.o目標檔案連結生成可執行檔案
gcc -c test1.c test2.c test3.c test_main.c//編譯成.o目標檔案
gcc test1.o test2.o test3.o test_main.o -o test_main_1//把.o檔案連結成可執行檔案
./test_main_1
原始碼test1.h
#include <stdio.h>
void log_1();//函式在.h標頭檔案中宣告
原始碼test1.c
#include "test1.h"
//函式在.C檔案中實現
void log_1(){
printf("This is file test1!\n");
}
原始碼test2.h
#include <stdio.h>
void log_2();
原始碼test2.c
#include "test2.h"
void log_2(){
printf("This is file test2!\n");
}
原始碼test3.h
#include <stdio.h>
void log_3();
原始碼test3.c
#include "test3.h"
void log_3(){
printf("This is file test3!\n");
}
原始碼test_main.h
#include <stdio.h>
#include "test1.h"//引入標頭檔案
#include "test2.h"
#include "test3.h"
void log_1();//宣告test1.h中的函式
void log_2();
void log_3();
原始碼test_main.c
#include "test_main.h"
int main(int argc, char* argv[]){
log_1();//呼叫test1.h中的函式
log_2();
log_3();
return 0;
}
.a檔案 :靜態庫檔案,靜態庫在編譯時已經被連結到目的碼中,執行程式不依賴該靜態庫檔案;
優點:將程式使用的函式的機器碼複製到最終的可執行檔案中,提高了執行速度;如果庫函式改變,整個程式需要重新編譯
缺點:所有需用到靜態庫的程式都會被新增靜態庫的那部分內容,使得可執行程式碼量相對變多,佔用記憶體和硬碟空間
ar rc libtest.a test1.o test2.o test3.o//把.o檔案打包成.a的庫檔案
gcc test_main.c -L. -ltest -o test_main_a//連結生成可執行檔案
./test_main_a//執行測試程式
rm libtest.a //刪除靜態庫檔案
./test_main_a//同樣正常執行程式
.so檔案:動態庫檔案,在程式執行的時候載入動態庫檔案,程式要正常執行必須依賴於它需要使用的動態庫檔案;
優點:只有在程式執行的時候, 那些需要使用的函式程式碼才被拷貝到記憶體中。動態庫在記憶體中可以被被多個程式使用,又稱之為共享庫,節約了記憶體和磁碟空間,以時間效率去換取空間效率;當呼叫介面沒改變,庫檔案發生改變重新編譯,而呼叫的主程式可不用重新編譯;
缺點:執行速度不及靜態庫檔案;
靜態庫與動態庫的選取使用,請結合自己的場景進行取捨,我不知道客戶要使用的頻率,我選擇使用動態庫的形式;
三、.so庫檔案的封裝以及使用
首先檢視目錄層次,可以看到就當前目錄分別由一個lib的庫目錄、Makefile、ReadMe.txt、測試呼叫庫函式的原始碼和使用者使用的庫標頭檔案
ls -R
也可以安裝tree工具,檢視所有檔案更有目錄層次
sudo apt-get install tree//安裝
sudo tree --help//檢視命令選項
tree -a//列出當前目錄的所有檔名(檔案和資料夾)
最重要就是把lib裡面的所有檔案編譯成一個.so的庫檔案;
lib庫裡的Makefile
OBJS:=adTorgb.cpp.o descriptors.c.o error.c.o linux.c.o satusbimage.cpp.o usb.c.o
#把所有[.c]檔案編譯成[.o]檔案
#-fPIC; 代表編譯為位置獨立的程式碼,滿足了不同的程序對所載入動態庫的共享;
#-c; 表示只編譯原始檔但不連結;
#$<; 表示所搜尋到與第一個相匹配的檔案,即第一個[.c]檔案;
#-o; 指定輸出檔名;
#[email protected]; 與[.c]檔案相對應的[.o]檔案;
#-I.; 需用到的標頭檔案在本目錄中找.
%.c.o:%.c
gcc -fPIC -c $< -o [email protected] -I.
%.cpp.o:%.cpp
g++ -fPIC -c $< -o [email protected] -I.
#-shared: 該選項指定生成動態連線庫
all:$(OBJS)
@echo "Compile..."
g++ -shared -fpic -o libsatusb.so $(OBJS)
@echo "End"
clean:
rm -fr *.o *.so
對比封裝lib庫與測試目錄satusbimage.h的區別,以下為封裝庫的標頭檔案:
#ifndef _SATUSBIAMGE_H_
#define _SATUSBIMAGE_H_
#endif
#include <usb.h>
#include "color_tables_rgb.h"
#define USB_VID 0x0547 //CY7C68014A的產商ID
#define USB_PID 0x0503 //CY7C68014A的產品ID
#define EP0ADDR 0x01 //埠0地址,通道0
#define EP1ADDR 0x81 //埠1地址,通道1
#define EP2ADDR 0x02 //埠2地址,通道2
#define EP3ADDR 0x86 //埠3地址,通道3
#define USB_TIMEOUT 10000 //傳輸資料的時間延遲
#define IR_ROW 288
#define COL 1024
#define IR_IMAGE_SIZE IR_ROW*COL*2 //IR一幀影象的大小
/*
*@find_device. We can find out the USB device that we need to use from USB bus. We need to open USB device for getting USB handle.
*@param Void
*@return Non-null value indicates that the function is called successfully, and the function of return value is an USB device.
*/
struct usb_device* find_device();
/*
*@open_device We can obtain a handle from the USB device after function call,the handle can be used to the parameter of reading Usb data.
*@param <dev> Dev means that we will choose which USB device to open.
*@return Non-null value indicates that the function is called successfully. and the function of return value is a USB handle.
*/
usb_dev_handle* open_device(struct usb_device* dev);
/*
*@bulk_read_data. If you want to watch the image, please use the bulk_read_data function.
*@parameter <handle> We read data from the USB handle.<data_ad> Data_ad is used to save collected image of ad value.<data_rgb> Data_rgb is used to save the having been disposed of RGB of image data.
*@return Value greater than zero indicates that the function is called successfully.
*/
int bulk_read_data(usb_dev_handle* handle, char* data_ad, _rgb_item* data_rgb);
/*@close_usb_handle. When you do not keep watch on the image, please use the close_usb_handle function to close the usb device,the parameter device_handle is the open_device function's return value.
*@parameter <handle> We will close the USB device through hanlde. the parameter device_handle is the open_device function's return value.
*@return Value greater than zero indicates that the function is called successfully.
*/
int close_usb_handle(usb_dev_handle* handle);
/*@set_level_value. To set the brightness of picture
*@parameter <value> The value of brightness
*@return Return true if the parameter value between 0 and 255,else return false
*/
bool set_level_value(int value);
/*@set_span_value. To set the contrast of picture
*@parameter <value> The value of contrast
*@return Return true if the parameter value between 0 and 255,else return false
*/
bool set_span_value(int value);
以下是測試函式所用到的標頭檔案;
#ifndef _SATUSBIMAGE_H_
#define _SATUSBIMAGE_H_
#endif
#include <usb.h>
#define IR_ROW 288
#define COL 1024
#define IR_IMAGE_SIZE IR_ROW*COL*2
struct _rgb_item
{
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char reserved;
};
typedef struct _rgb_item rgb_item;
/*
*@find_device. We can find out the USB device that we need to use from USB bus. We need to open USB device for getting USB handle.
*@param Void
*@return Non-null value indicates that the function is called successfully, and the function of return value is an USB device.
*/
struct usb_device* find_device();
/*
*@open_device We can obtain a handle from the USB device after function call,the handle can be used to the parameter of reading Usb data.
*@param <dev> Dev means that we will choose which USB device to open.
*@return Non-null value indicates that the function is called successfully. and the function of return value is a USB handle.
*/
usb_dev_handle* open_device(struct usb_device* dev);
/*
*@bulk_read_data. If you want to watch the image, please use the bulk_read_data function.
*@parameter <handle> We read data from the USB handle.<data_ad> Data_ad is used to save collected image of ad value.<data_rgb> Data_rgb is used to save the having been disposed of RGB of image data.
*@return Value greater than zero indicates that the function is called successfully.
*/
int bulk_read_data(usb_dev_handle* handle, char* data_ad, _rgb_item* data_rgb,unsigned char color_table);
/*@close_usb_handle. When you do not keep watch on the image, please use the close_usb_handle function to close the usb device,the parameter device_handle is the open_device function's return value.
*@parameter <handle> We will close the USB device through hanlde. the parameter device_handle is the open_device function's return value.
*@return Value greater than zero indicates that the function is called successfully.
*/
int close_usb_handle(usb_dev_handle* handle);
/*@set_level_value. To set the brightness of picture
*@parameter <value> The value of brightness
*@return Return true if the parameter value between 0 and 255,else return false
*/
bool set_level_value(int value);
/*@set_span_value. To set the contrast of picture
*@parameter <value> The value of contrast
*@return Return true if the parameter value between 0 and 255,else return false
*/
bool set_span_value(int value);
通過對比發現,兩個標頭檔案並不一樣,如果不想讓一些資訊透露給三方,就可以封裝成庫,給第三方使用者提供需要呼叫的介面即可,具體的實現在lib庫中的.cpp中;
測試函式資料夾中的Makefile
all:
#-L./lib: 編譯時到當前路徑的lib資料夾中去需找libsatusb.so庫檔案
gcc satimagetest.c -L./lib -lsatusb -o satimagetest
#如果要執行編譯完成的可執行檔案,必須得設定下環境變數(執行程式時會去連結這個.so庫檔案,如果不設定環境變數,就找不到該庫檔案,程式執行失敗),或者把生成的.so庫檔案拷貝到已設定的路徑下(可以查環境變數LD_LIBRARY_PATH,但移植性不高)。
#export LD_LIBRARY_PATH=/opt/satImage/lib/:$LD_LIBRARY_PATH
庫檔案的封裝就介紹到此。