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; 指定輸出文件名;
#$@; 與[.c]文件相對應的[.o]文件;
#-I.; 需用到的頭文件在本目錄中找.
%.c.o:%.c 
        gcc -fPIC -c $< -o $@ -I.

%.cpp.o:%.cpp
        g++ -fPIC -c $< -o $@ -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

庫文件的封裝就介紹到此。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章