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 
	void log_1();//函数在.h头文件中声明

源码test1.c

#include "test1.h"
//函数在.C文件中实现
void log_1(){
        printf("This is file test1!\n");
}

源码test2.h

#include 
	void log_2();

源码test2.c

#include "test2.h"

void log_2(){
        printf("This is file test2!\n");
}

源码test3.h

#include 
	void log_3();

源码test3.c

#include "test3.h"

void log_3(){
        printf("This is file test3!\n");
}

源码test_main.h

#include 

#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//同样正常运行程序

Linux静态库.a与动态库.so的生成与区别、以及.so库文件的封装与使用_第1张图片
.so文件:动态库文件,在程序运行的时候载入动态库文件,程序要正常运行必须依赖于它需要使用的动态库文件;
优点:只有在程序执行的时候, 那些需要使用的函数代码才被拷贝到内存中。动态库在内存中可以被被多个程序使用,又称之为共享库,节约了内存和磁盘空间,以时间效率去换取空间效率;当调用接口没改变,库文件发生改变重新编译,而调用的主程序可不用重新编译;
缺点:运行速度不及静态库文件;
静态库与动态库的选取使用,请结合自己的场景进行取舍,我不知道客户要使用的频率,我选择使用动态库的形式;
#三、.so库文件的封装以及使用
首先查看目录层次,可以看到就当前目录分别由一个lib的库目录、Makefile、ReadMe.txt、测试调用库函数的源码和用户使用的库头文件

ls -R

这里写图片描述

也可以安装tree工具,查看所有文件更有目录层次

sudo apt-get install tree//安装
sudo tree --help//查看命令选项
tree -a//列出当前目录的所有文件名(文件和文件夹)

Linux静态库.a与动态库.so的生成与区别、以及.so库文件的封装与使用_第2张图片
最重要就是把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 
#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  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  We read data from the USB handle. Data_ad is used to save collected image of ad value. 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  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  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  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 

#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  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  We read data from the USB handle. Data_ad is used to save collected image of ad value. 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  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  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  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

库文件的封装就介绍到此。

你可能感兴趣的:(Linux下C语言编程)