[关闭]
@danren-aa120 2020-03-20T01:36:31.000000Z 字数 3882 阅读 142

Linux下生成动态链接库

C++


https://blog.csdn.net/zb1593496558/article/details/79993181
1.【摘要】动态链接库是在编译器编译之后生成  obj 文件之后,将几个链接文件和动态链接库中的文件链接起来,在链接器中将几个目标文件组合在一起然后生成可执行文件  exe 文件,而生成动态链接库的这一步骤是由编译器自己完成的,它可以调用自己已经处理好的库函数,在需要时直接拿出来使用就好了。而今天,我要分享给大家一个可以自己实现动态链接库生成的小技巧,别说,这种小技巧在面试中还是会被经常问到的哦。
方法一:
第一步:
先编写两个 .c 文件(为了方便,我写了一个最简单的 add.c 和 main.c 。add.c 就是直接做加法运算,main.c 是对 add函数的调用
第二步:
       这一步很关键,要生成add的库文件 libadd.so (后面的名字是我自己起的,方便理解,你们也可以起其他的名字,但是一定要加上后缀 .so ,这是库文件的后缀)
       输入命令行  ——>   gcc -fpic -shared add.c -o libadd.so
       经过这个步骤,你的文件夹下 用 ls 就可以看到已经生成了 libadd.so 
第三步:
       生成了动态库之后,我们需要把动态库和 main.c 文件通过系统编译器链接在一起进行编译,生成 a.out 可执行文件
输入命令行——> gcc libadd.so main.c
现在你再次 ls 一下,就会发现文件夹下又多了一个 a.out 文件。但是,你现在直接 ./a.out ,系统会报错,大概意思就是找不到你的动态库地址,,这个时候你需要找到你的动态库拷到  /lib/库中,这样才可以被系统检测到
第四步
将你自己的动态库拷到/lib/目录下  
输入命令——>cp libadd.c /lib/
这个时候就已经大功告成了,你再次使用命令 ./a.out 程序就会顺利执行并且输出结果了。
方法二:

方法二的前三步和方法一都是一样的,所以如果你要想在方法一试过之后再尝试方法二,那你就需要删除 a.out 和 libadd.so 这俩文件了。
第四步:
  现在我们已经知道了,如果系统没有找到我们自己生成的动态库的路径,就无法通过编译,在方法一里面,我们是直接将动态库拷到了 /lib/目录下,相当于充当了一个库文件,这次我们直接 vim 一把 ,将动态库的路径写到一个一个库文件中
输入命令行——>   vim /etc/ld.so.conf.d/ku.conf
第五步:
       刷新一下缓冲区
  输入命令行——> ldconfig
  然后你再次输入 ./a.out 也可以相应的输出结果啦,是不是并没有那么难呢。

但是,切记,你的动态库再使用完之后还是尽快删除吧。尽管这个库文件不是很大,也没有占用多少内存,但是,在以后的实际工作中,如果你要编写的代码量很大时,还是很耗费内存的。为了减少不必要的浪费,记得删除你自己的动态库文件哦。
2Linux之make 、makefile的使用方法
◊make是什么?

  make是一个命令工具,是一个解释makefile中指令的命令工具。它可以简化编译过程里面所下达的指令,当执行 make 时,make 会在当前的目录下搜寻 Makefile (or makefile) 这个文本文件,执行对应的操作。make 会自动的判别原始码是否经过变动了,而自动更新执行档。

◊为什么要使用make?

  假设,现在一个项目里面包含了100个程序文件,如果要对这个项目进行编译,那么光是编译指令就有100条。如果要重新进行编译,那么就又得像之前一样重新来一遍。这样重复且繁琐的工作实在是让我们很不爽啊。所以,用make来进行操作,间接调用gcc岂不是很方便?如果我们更动过某些原始码档案,则 make 也可以主动的判断哪一个原始码与相关的目标文件档案有更新过, 并仅更新该档案。这样可以减少重新编译所需要的时间,也会更加方便。

◊makefile又是干什么的?

  makefile其实就是一个文档,里面定义了一系列的规则指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,它记录了原始码如何编译的详细信息! makefile一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。

  先看一下makefile的规则:

    目标(target):目标文件1 目标文件2

     gcc -o 欲建立的执行文件 目标文件1 目标文件2

  目标(target)就是我们想要建立的信息,而目标文件就是具有相关性的 object files ,建立执行文件的语法就是以 按键开头的那一行!特别留意,『 命令行必须要以 tab 按键作为开 头』才行!它的规则基本上是这样的:
  •在 makefile 当中的 # 代表批注;
  • 需要在命令行 (例如 gcc 这个编译程序指令) 的第一个字符;
  •标的 (target) 与相依档案(就是目标文件)之间需以『 :』隔开。
  下面举个例子说明:

  先分别创建三个文件,如图
  image_1e3phrsr74421h8d114e1vpp1ar39.png-287.3kB

创建一个makefile文件,然后进行规则编写

  image_1e3phs8kc1uca10d61938vm817cpm.png-27.7kB

现在就可以使用make命令编译文件了,这样是不是很方便呢?
image_1e3phsoie1lmu1155m031hu7181613.png-27.7kB
  

   如果不想让编译规则显示在屏幕上,只要在makefile里规则编写前加个@它就不会显示了~

  如果现在再对文件编译一次会发生什么?嘿嘿,大家可以自己试一下。

  如果想要下达一 个指令就直接清除掉所有的目标文件与执行文件,又该怎么做呢?

  我们可以在makefile里面定义一个clean,执行rm的操作。但是有一点要注意的是,在这里我们最好使用伪目标进行操作。makefile里伪目标用.PHONY进行声明。当一个目标被声明为伪目标后,make在执行规则时不会去试图去查找隐含规则来创建它。这样就提高了make的执行效率,也解决了文件目录中如果出现名为clean文件,clean操作不被执行的问题。
image_1e3pht2vg1f7q13t615tu15cm1el11g.png-27.7kB
 
3linux下生成动态链接库并使用(使用cmake)
总的来说CMake生成过程不复杂,但是查到的资料都坑爹,废话说了半天没有说到要点,咱直奔主题,两个步骤:

  1)切到有CMakeList.txt文件的文件夹下,执行CMake .命令(.是当前路径)
image_1e3pihj6d17it167e1tek2co1snh1t.png-22.4kB

  2)执行make命令即可
image_1e3pihu771ib4qq9hm51ako1s672a.png-28.9kB

  然后就发现生成了libDetour.so文件,这个就是自己的文件依赖的recast库。

  当然这中间最重要的就是CMakeList.txt,这个文件剪短,具体如下:

CMAKE_MINIMUM_REQUIRED(VERSION 2.6)

SET(detour_SRCS
Source/DetourAlloc.cpp
Source/DetourCommon.cpp
Source/DetourNavMesh.cpp
Source/DetourNavMeshBuilder.cpp
Source/DetourNavMeshQuery.cpp
Source/DetourNode.cpp
)

SET(detour_HDRS
Include/DetourAlloc.h
Include/DetourAssert.h
Include/DetourCommon.h
Include/DetourNavMesh.h
Include/DetourNavMeshBuilder.h
Include/DetourNavMeshQuery.h
Include/DetourNode.h
)

INCLUDE_DIRECTORIES(Include)

ADD_LIBRARY(Detour ${detour_SRCS} ${detour_HDRS})


  其中ADD_LIBRARY(Detour ${detour_SRCS} ${detour_HDRS})这个是里面的需要加上SHARED表示动态库文件,而不是静态库文件,方便自己的项目中包含进来。(PS昨天弄了好久,就是这个地方没有改过来)
  类型有三种: SHARED,动态库STATIC,静态库MODULE,在使用dyld的系统有效,如果不支持dyld,则被当作SHARED对待。EXCLUDE_FROM_ALL参数的意思是这个库不会被默认构建,除非有其他的组件依赖或者手工构建。具体更多参数和CMakeList.txt的编写规范这里就不多说了,可以参考CMake官方文档。

三、G++编译生成最终的动态库文件
  闲话少叙,先附上来命令:g++ -I /usr/local/jdk1.7.0_10/include/linux/ -I /usr/local/jdk1.7.0_10/include/ -I ./Include/ -L ./ -l Detour -fPIC -shared -o librecast.so PathFinding.cpp。

  注意:要生成的是recast.so需要在java里面加载的,然后是务必命名为librecast

System.load("recast");

  还有就记得加上-L ./ -lDetour这个参数,否则就算正常编译,运行的时候会报错can not find symbol 某个函数的错误,不能正常运行。

  这样就搞定了。

  接下来是具体的参数说明。

-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件。

-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。 

-L.:表示要连接的库在当前目录中 

-l Detour:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称

-I 项目中include包含的头文件寻找路径

...更多参数(请参阅G++编译参数)

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注