Makefile文件如下:

OBJS_DIR=./objs
CCFLAGS= -shared -Wall -fPIC -Wl,-soname,libcudart.so.4 -g
LDFLAGS=ifeq ($(hook),1)
CCFLAGS+=-DRUN_REAL_LIBCUDA
LDFLAGS+= -ldl
endifRTAPI_SRCS = runtime_api.c driver_intf.c
RTAPI_OBJS = $(addprefix ${OBJS_DIR}/, $(RTAPI_SRCS:.c=.o))$(OBJS_DIR)/%.o: %.cgcc $(CCFLAGS) -I./  -c $< -o $@.PHONY:all:mk-dirs rtapirtapi: mk-dirs $(RTAPI_OBJS)gcc $(CCFLAGS) -o  libcudart.so.4.0.0  $(RTAPI_OBJS) $(LDFLAGS)ln -sf libcudart.so.4.0.0 libcudart.so.4mk-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

总结:

一个动态库有三种文件名称

1.libxxx.so (一般为软连接),作用是编译程序的时候,用到的动态库必须是这种名字,gcc 中-l选项,例如 -lshared 意思是链接文件名为libshared.so的动态库

2.libxxx.so.x (一般为软连接,只包含主版本号),作用是,编译好的程序,交给用户的去运行的时候,一定要保证用户的电脑上有名称为libxxx.so.x动态库,并且要保证此名称的动态库的唯一标识符也是libxxx.so.x,例如用户电脑上存在 libshared.so.1的软连接,指向真实文件libshared.so.1.0.0,我们要保证真实文件的唯一标识符为 libshared.so.1,即编译生成真实文件libshared.so.1.0.0的时候,gcc的-Wl,-soname选项后面指定的参数也要是libshared.so.1,否则,即使程序运行时加载动态库时找到了此名称的动态库,也不能成功加载

3.libxxx.so.x.xx(真实的动态库文件,包含主版本号和次版本号),开发动态库的公司生成的动态库的文件名称

4. 从上述可以知道:

a.动态库的主版本号 不仅体现在动态库的文件名里面,而且使用 gcc的-Wl,-soname选项,以二进制数据的形式,保存在动态库中,使用动态库的可执行程序运行的时候,先用文件名libxxx.so.x找到动态库,然后检查动态库的唯一标识符是否是libxxx.so.x,是的话才能成功加载(待验证)

b.动态库的次版本号 只体现在动态库的文件名中,所以主版本号相同,次版本号不同的动态库,可以相互兼容。

关于上述总结中第2条,第4条验证结果:

有点意外,如果主版本号不同的两个库,只要保证两个库的名称相同,两个库中的接口相同,即两个库中二进制数据保存的主版本号不同,但是两个库的文件名改成一样的,两个库中函数接口相同,程序运行的时候仍然可以成功加载动态库,即上述总结中的这一点是错误地。验证程序如下:

验证程序的目录结构:

sallenkey@ubuntu:~/workspace$ tree ./
./
├── hello
│   ├── hello.c
│   └── Makefile
├── main.c
└── Makefile

其中 ./hello目录存放编译动态库libhello.so的源文件, ./目录存放调用libhello.so的源文件

./hello/hello.c:

#include <stdio.h>void hello(void){printf("hello world\r\n");
}

./hello/Makefile

NO_VER_LINK_OUTPUT := libhello.so
LINK_OUTPUT = $(addsuffix $(VER), $(addsuffix ., $(NO_VER_LINK_OUTPUT)))
OBJS_DIR = ./objs
CCFLAGS = -shared -Wall -fPIC -Wl,-soname,$(LINK_OUTPUT)HELLO_SRCS = hello.c
HELLO_OBJS = $(addprefix ${OBJS_DIR}/, $(HELLO_SRCS:.c=.o))SECOND_VER_NU = .0.0
OUTPUT = $(addsuffix ${SECOND_VER_NU}, $(LINK_OUTPUT)) $(OBJS_DIR)/%.o:%.cgcc $(CCFLAGS) -I./ -c $< -o $@.PHONY:all:$(OUTPUT)$(OUTPUT):$(OBJS_DIR) $(HELLO_OBJS)gcc $(CCFLAGS) -o $@ $(HELLO_OBJS)#ln -sf $@ $(LINK_OUTPUT)ln -sf $@ libhello.so.1 ln -sf $@ $(NO_VER_LINK_OUTPUT)$(OBJS_DIR):mkdir -p $@clean:rm -rf $(OBJS_DIR) $(OUTPUT)  $(NO_VER_LINK_OUTPUT) libhello.so.1 #$(LINK_OUTPUT)

./main.c

extern void hello();
#include <stdio.h>int main(){hello();return 0;
}

./Makefile

TEST_SRCS:=$(wildcard *.c)
OBJS_DIRS:=./objs
LDFLAGS:=-lhello -L./helloTEST_OBJS:=$(addprefix $(OBJS_DIRS)/, $(TEST_SRCS:.c=.o))
OUTPUT:=$(basename $(TEST_SRCS))all:$(OBJS_DIRS) $(OUTPUT)$(OUTPUT):$(TEST_OBJS)gcc -o $@ $^ $(LDFLAGS) -Wl,-rpath=./hello$(OBJS_DIRS)/%.o:%.cgcc -o $@ -c $^$(OBJS_DIRS):mkdir -p $@clean:rm -rf $(OBJS_DIRS) $(OUTPUT)

验证方式:

1.切换到./hello目录,执行命令:  make VER=1,生成主版本为1的libhello.so

2.切换到./目录,执行命令: make,生成可执行文件main, 运行./main,发现成功输出hello world

3.切换到./hello目录,执行命令 make clean VER=1,清除主版本号为1的libhello.so

4.执行命令  make VER=2,生成主版本号为2的libhello.so

5.切换到./目录,运行./main,发现仍然可以成功输出hello world

gcc生成动态链接库相关推荐

  1. dll = MinGW gcc 生成动态链接库 dll 的一些问题汇总

    MinGW gcc 生成动态链接库 dll 的一些问题汇总 https://blog.csdn.net/liyuanbhu/article/details/42612365 网络上关于用 MinGW  ...

  2. gcc 生成动态链接库

    http://blog.csdn.net/ngvjai/article/details/8520840 Linux下文件的类型是不依赖于其后缀名的,但一般来讲: .o,是目标文件,相当于windows ...

  3. 如何用gcc编译器生成动态链接库*.so文件(动态库)

    如何用gcc编译器生成动态链接库*.so文件(动态库) 当源文件为string.c时,生成动态链接库,假设名称为libstr.so 生成动态链接库的命令行为: gcc -fPIC -shared -o ...

  4. linux 中如何将文件粘贴到usr下的lib内,学会在Linux下GCC生成和使用静态库和动态库...

    一.基本概念1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同(主 ...

  5. Linux下c和cuda混合编译,并生成动态链接库.so和使用

    Linux下c和cuda混合编译,并生成动态链接库.so和使用 2016-08-27 14:27 98人阅读 评论(0) 收藏 举报 分类: Linux 版权声明:本文为博主原创文章,未经博主允许不得 ...

  6. Linux下Gcc生成和使用静态库和动态库详解

    参考文章:http://blog.chinaunix.net/uid-23592843-id-223539.html 一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库 ...

  7. linux gcc 静态 动态链接库

    linux gcc 静态 动态链接库 静态链接库 首先生成依赖函数的目标文件 gcc -c source1.c source2.c; 然后归档目标文件到静态库 ar -rcs libYourID.a ...

  8. Linux下Gcc生成和使用静态库和动态库详解(转)

    一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同( ...

  9. GCC生成的汇编代码

    假设我们写了一个C代码文件 code.c包含下面代码: int accum = 0; int sum(int x, int y) {     int t = x + y;     accum += t ...

最新文章

  1. React.js 小书 Lesson5 - React.js 基本环境安装
  2. YII 控件使用笔记
  3. python限制输入值范围_求python 中if 里如何设定一个值的范围
  4. 外部方法调用内部_私有属性和私有方法
  5. JavaScript No Overloading 函数无重载之说
  6. php运行汇编,php脚本的执行过程(编译与执行相分离)
  7. Understanding node.js
  8. mybatis plus当月数据查询_Springboot+mybatis(plus)+druid多数据源
  9. PCL之计算点云质心---pcl::compute3DCentroid()
  10. 利用中间结果减少计算量
  11. dbutilsjar包下载_commons dbutils 下载-commons dbutils.jar下载 v1.6官方版--pc6下载站
  12. 【Qt】 使用QMovie加载Gif动画
  13. 2017cad光标大小怎么调_把cad光标变大的方法步骤详解
  14. 华为笔试:拼音与英文互相转换python
  15. 数据库系统(DBS)组成
  16. js版四舍六入五成双方法
  17. 自制三维激光扫描建模
  18. 3.9、互斥锁(互斥量)
  19. YTU OJ Problem 2013
  20. 前端酷炫效果之那些漂亮的登录界面

热门文章

  1. java访问domino数据库_怎样实现Java远程访问Domino数据库
  2. 华为折叠屏刷屏,他把三星逼上绝路!
  3. 联邦学习的基本概念、三种框架和应用场景
  4. 来CCF HPC China 2019走一走,领略别样的算力之美
  5. 666碉堡了!这个微信开源神器,能自动用表情包回复“拍一拍”
  6. 视频会议电视终端网络部署场景与操作步骤
  7. 【深度报道】阿里云、华为云、用友云,企业服务的三种新生态
  8. 计算机专业的人的优势
  9. python3-Request库详解
  10. 程序员修炼之路(四)走近腾讯 走进腾讯(一个关于面试准备的记录)