gcc生成动态链接库

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

猜你喜欢

转载自blog.csdn.net/xiaoyink/article/details/80098251