Makefile文件如下:
OBJS_DIR=./objs CCFLAGS= -shared -Wall -fPIC -Wl,-soname,libcudart.so.4 -g LDFLAGS= ifeq ($(hook),1) CCFLAGS+=-DRUN_REAL_LIBCUDA LDFLAGS+= -ldl endif RTAPI_SRCS = runtime_api.c driver_intf.c RTAPI_OBJS = $(addprefix ${OBJS_DIR}/, $(RTAPI_SRCS:.c=.o)) $(OBJS_DIR)/%.o: %.c gcc $(CCFLAGS) -I./ -c $< -o $@ .PHONY: all:mk-dirs rtapi rtapi: mk-dirs $(RTAPI_OBJS) gcc $(CCFLAGS) -o libcudart.so.4.0.0 $(RTAPI_OBJS) $(LDFLAGS) ln -sf libcudart.so.4.0.0 libcudart.so.4 mk-dirs: mkdir -p $(OBJS_DIR) clean: rm -rf $(OBJS_DIR) rm -rf libcudart.so*
这里主要解析CCFlags变量的含义:
-shared 生成共享库
-Wall 输出编译过程中的警告
-fPIC 生成与地址无关的二进制代码,这样的动态库可以被加载到所有进程都可以访问的一块内存中,而不用每一个进程都在各自的内存中保留动态库的copy,造成内存浪费,但是不要妄想通过在动态库里定义全局变量实现进程间通信,因为,linux采用写时拷贝(copy-on-write技术),在某一进程试图改变动态库里的全局变量时,linux会将动态库的全局变量拷贝至该进程的私有内存空间(如果只读不写,则不拷贝),因此无法通过此路径实现进程间通信,参考:
http://www.cnblogs.com/lovevivi/archive/2013/01/10/2854584.html
https://blog.csdn.net/zxh821112/article/details/8969541这篇文章中有介绍不适用-fPIC选项的后果,将产生装载时重定向的代码(修改代码中所有地址),使只加载一次动态库,所有进程共享这一内存成为不可能。
-Wl,-soname -Wl指明接下来的参数传递给链接器,-soname制定共享库的soname(简单共享名,short for shared object name),soname是库的唯一标示,而不是库的文件名,但一般soname和库的文件名相关(库文件名包含详细版本信息,soname只包含主版本信息),这样同一主版本下,此版本更新方便升级,不同版本的库虽然文件名不同但是soname一定要一致,如果主版本更新,则一般不兼容上一版本,所以使用此库的可执行程序要重新改写源码并编译。
上面库的文件名为libcudart.so.4.0.0,库的soname为libcudart.so.4与库的软链接相同
-g 用于gdb调试。
LDFLAGS变量的含义:
-ldl 链接一个名字为libdl.a的库,这个库里有几个函数dlopen、dlsym、dlclose、dlerror,可以用于显示的打开动态库,并且获取其中的函数地址。
RTAPI_OBJS = $(addprefix ${OBJS_DIR}/, $(RTAPI_SRCS:.c=.o))
这句话的效果是 首先将RTAPI_SRCS变量中所有的.c结尾的字符串替换成.o结尾的字符串, 然后调用makefile的addprefix函数为.o添加前缀./objs/
https://blog.csdn.net/zhoudengqing/article/details/41775353
下面我们来说一下生成动态库和使用动态库的注意事项:
-Wl,-soname,xxx 选项用来指定共享库的唯一标识:简单共享名,不指定时默认为:
1.若-o指定的要生成的库的文件名为标准的lib**.so.x.x.x这种格式,则soname是去掉版本信息的部分,即lib**.so(若没有版本信息,则库文件名和soname同名)
2.若-o指定的为非标准格式,则gcc会取库文件名的主体部分(点号前面的部分,没有点号则取全部文件名)加上lib前缀和.so后缀作为soname。
soname是主程序运行时加载动态库的唯一标识,所以要想程序成功加载动态库,则需要创建soname同名的指向动态库文件的软连接,或者直接将动态库的名称改为soname(不推荐)
主程序编译时的注意事项:
编译时使用动态库要使用-l指令,要想编译成功,需要建立一个软连接,名称为-l后的字符串加上lib前缀和.so后缀。
下面举例:
shared.c文件生成动态库文件libshared.so.1.0.0,指定soname为libshared.so.1
gcc -shared -fpic -Wall -Wl,-soname,libshared.so.1 -o libshared.so.1.0.0 shared.c
main.c生成exe文件
先创建软连接:
ln -s libshared.so.1.0.0 libshared.so
ln -s libshared.so.1.0.0 libshared.so再编译,没有名字libshared.so的软连接,编译将出错。
gcc -lshared -L. -o exe main.c
运行exe文件时要先建立另一个软链接,此软链接要和soname必须同名:
ln -s libshared.so.1.0.0 libshared.so.1
另外运行时要将软链接所在路径添加到环境变量LD_LIBRARY_PATH中去,才能正确运行
export LD_LIBRARY_PATH=$(pwd):LD_LIBRARY_PATH