so文件在linux中为共享库,与windows下的dll类似。
so文件中的函数可供多个进程调用,最大可能的提供二进制代码的复用。
共享库可以使代码的维护工作大大简化,当修正了一些错误或者添加了新特性的时候,用户只需要获得升级后的so并安装他就可以。
注:即使不同的进程调用同一个so文件,通过共享库并不能实现不同进程间的通讯,因为同一个so被不同进程加载加载到不同的内存空间。
so文件编译方法
–so文件的源文件中不需要有main函数,即使有也不会被执行。
–编译的时候gcc需要加-fPIC选项,这可以使gcc产生与位置无关的代码。
–连接的时候gcc使用-shared选项,指示生成一个共享库文件。
–共享库文件名要以lib开头,扩展名为.so。
编写so的例子。
int max(int a, int b) { if (a > b) return a; else return b; } int add(int a, int b) { return a + b; }
#ifndef TEST_H_ #define TEST_H_ int max(int a, int b); int add(int a, int b); #endif /* TEST_H_ */
.SUFFIXES:.c .o CC=gcc SRCS=test.c EXEC=libtest.so OBJS=$(SRCS:.c=.o) start:$(OBJS) $(CC) -shared -o $(EXEC) $(OBJS) .c.o: $(CC) -g -fPIC -o $@ -c $< clean: rm -f $(OBJS)
so文件使用方法
–为了让linux能找到so文件的位置,需要在.bash_profile中添加export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
–或者将so文件放入linux的系统目录/usr/lib/
–在c文件中使用so文件,首先需要 #inluce相关h文件。
–gcc连接时添加 –L参数指明so文件存放路径,-l参数指明so文件名
–以libtest.so文件在当前路径下举例
gcc -L. -ltest -o a a.o
其中-L.意思为在当前路径下寻找so文件
-ltest意思为要链接libtest.so这个库文件
-o a 意思为编译后的可执行文件名为a
u调用so的例子
#include "test.h" #include <stdio.h> int main() { printf("%d ", max(4, 5)); printf("%d ", add(4, 5)); return 0; }
.SUFFIXES:.c .o CC=gcc SRCS=a.c EXEC=a OBJS=$(SRCS:.c=.o) start:$(OBJS) $(CC) -L. -ltest -o $(EXEC) $(OBJS) .c.o: $(CC) -o $@ -c $< clean: rm -f $(OBJS)
当我们在cpp文件中包含test.h文件,用g++链接libtest.so这个库时会报错:
(.text+0x19): undefined reference to `max(int, int)'
(.text+0x3d): undefined reference to `add(int, int)'
为了使我们编写的so文件同时可以被C或者C++调用,我们需要修改一下h文件中的函数申明部分。
增加带有__cplusplus的预编译指令。
__cplusplus是c++编译器预定义的一个宏,比如用g++的时候这个宏就被提前定义了
编写so的例子。
–test.h头文件
如果是c++编译器会默认定义__cplusplus这个宏。
当使用gcc编译的时候产生如下结果:
int max(int a, int b);
int add(int a, int b);
当使用g++编译的时候,产生如下结果:
extern "C"{
int max(int a, int b);
int add(int a, int b);
}
#ifndef TEST_H_ #define TEST_H_ #ifdef __cplusplus extern "C"{ #endif int max(int a, int b); int add(int a, int b); #ifdef __cplusplus } #endif #endif /* TEST_H_ */