Linux下动态链接库的创建和使用
来源:互联网 发布:淘宝80字好评 编辑:程序博客网 时间:2024/06/08 11:13
1、链接库的基本知识
库是一种软件组件技术,库里面封装了数据和函数。它的使用,可以是程序模块化。在程序中使用,我们可以称之为程序函数库。 程序函数库可分为3种类型:静态函数库(static libraries)、共享函数库(shared libraries)、动态函数库(dynamically loaded libraries): 1、静态函数库,是在程序执行前就加入到目标程序中去了; 2、共享函数库,则是在程序启动的时候加载到程序中,它可以被不同的程序共享 3、动态函数库,并非另外一种库函数格式,它只是使用动态加载方式加载共享函数库。 Windows系统包括静态链接库(.lib文件)和动态链接库(.dll文件)。 Linux通常把库文件存放在/usr/lib或/lib目录下 Linux库文件名由:前缀lib、库名和后缀3部分组成,其中共享链接库以.so.X最为后缀, .X是版本号,静态链接库通常以.a作为后缀。 Linux下标准库链接的三种方式(全静态 , 半静态 (libgcc,libstdc++), 全动态。 三种标准库链接方式的选项及区别见下表。
三种标准库链接方式的选项及区别:
上述三种标准库链接方式中,比较特殊的是 半静态链接方式,主要在于其还需要在链接前增加额外的一个步骤:
ln -s ‘g++ -print-file-name=libstdc++.a’,作用是将 libstdc++.a(libstdc++ 的静态库)符号链接到本地工程链接目录
-print-file-name在gcc中的解释如下: Display the full path to library
ldd 简介:该命令用于打印出某个应用程序或者动态库所依赖的动态库 ,使用该命令我们可以观察到Linux标准库三种链接方式的区别。
从实际应用当中发现,最理想的标准库链接方式就是半静态链接,通常会选择将 libgcc 与 libstdc++ 这两个标准库静态链接,从而避免应用程序在不同 Linux 版本间标准库依赖不兼容的问题发生。
size 简介:该命令用于显示出可执行文件的大小
示例链接选项中所涉及命令(引用 GCC 原文):
- -llibrary
- -l library:指定所需要的额外库
- -Ldir:指定库搜索路径
- -static:静态链接所有库
- -static-libgcc:静态链接 gcc 库
- -static-libstdc++:静态链接 c++ 库
2、静态链接库的创建和使用
涉及命令:ar, ar是创建、修改、提取静态库的操作。 ar -t 显示静态库的内容 ar -d 从库中删除成员文件 ar -r 在库中加入成员文件,若存在,则替换 ar -c 创建一个库 ar -s 无论ar命令是否修改了库内容,都强制重新生成库符号表 步骤如下: 1、在一个头文件种声明静态库所导出的函数。 2、在一个源文件种实现静态库所导出的函数。 3、编译源文件,生成可执行代码。 4、将可执行代码所在的目标文件加入到某个静态库中,并将静态库拷贝到系统默认的存放库文件的目录下。
下面通过一个例子来说明:mylib.h种存放的是静态库提供给用户使用的函数的声明,mylib.c实现了mylib.h种声明的函数。
mylib.h
#ifndef _MYLIB_H_#define _MYLIB_H_void weclome(void);void outString(const char *str);#endif
mylib.cpp
#include "mylib.h"void welcome(void){ printf("welcome to libmylib\n");}void outString(const char *str){ if(str != NULL) printf("%s\n", str);}
test.cpp
#include "mylib.h"#include int main(void){ printf("create and use library:\n"); welcome(); outString("it's successful\n"); return 0;}
- 编译mylib.c生成目标文件:gcc -o mylib.o -c mylib.cpp
- 将目标文件加入到静态库中:ar rcs libmylib.a mylib.o
- 将静态库copy到Linux的库目录(/usr/lib或者/lib)下:cp libmylib.a /usr/lib/libmylib.a
- 使用静态库编译,编译时无需带上前缀和后缀:gcc -o test test.cpp -lmylib
- 运行可执行程序test: ./test
合并静态链接库的脚本代码清单:
echo CREATE demo.a > ar.mac echo SAVE >> ar.mac echo END >> ar.mac ar -M < ar.mac ar -q demo.a CdtLog.o echo OPEN demo.a > ar.mac echo ADDLIB xml.a >> ar.mac echo SAVE >> ar.mac echo END >> ar.mac ar -M < ar.mac rm ar.mac
Linux makefile 中使用 ar 脚本方式进行静态库的创建,可以编写如下代码:
define BUILD_LIBRARY $(if $(wildcard $@),@$(RM) $@) $(if $(wildcard ar.mac),@$(RM) ar.mac) $(if $(filter %.a, $^), @echo CREATE $@ > ar.mac @echo SAVE >> ar.mac @echo END >> ar.mac @$(AR) -M < ar.mac ) $(if $(filter %.o,$^),@$(AR) -q $@ $(filter %.o, $^)) $(if $(filter %.a, $^), @echo OPEN $@ > ar.mac $(foreach LIB, $(filter %.a, $^), @echo ADDLIB $(LIB) >> ar.mac ) @echo SAVE >> ar.mac @echo END >> ar.mac @$(AR) -M < ar.mac @$(RM) ar.mac ) endef $(TargetDir)/$(TargetFileName):$(OBJS) $(BUILD_LIBRARY)
Linux 静态库链接顺序问题及解决方法:
为了解决这种库链接顺序问题,我们需要增加一些链接选项 :
通过将所有需要被链接的静态库放入 -Xlinker “-(” 与 -Xlinker “-)” 之间,可以是 g++ 链接过程中, 自动循环链接所有静态库,从而解决了原本的链接顺序问题。
3、共享函数库的创建和使用
GNU标准建议所有的函数库文件都放在/usr/local/lib目录下,而且建议命令可执行程序都放在/usr/local/bin目录下。 文件系统层次化标准FHS(Filesystem Hierarchy Standard)规定了在一个发行包中大部分的函数库文件应该安装到/usr/lib目录下,但是如果某些库是在系统启动的时候要加载的,则放到/lib目录下,而那些不是系统本身一部分的库则放到/usr/local/lib下面。 上面两个路径的不同并没有本质的冲突。GNU提出的标准主要对于开发者开发源码的,而FHS的建议则是针对发行版本的路径的。具体的置信息可以看/etc/ld.so.conf里面的配置信息,通过对它的修改,可以增加自己的目录。 如果你想覆盖某个库中的一些函数,用自己的函数替换它们,同时保留该库中其他的函数的话,你可以在 /etc/ld.so.preload中加入你想要替换的库(.o结尾的文件),这些preloading的库函数将有优先加载的权ldconfig可以更新/etc/ld.so.cache。/etc/ld.so.cache可以大大提高访问函数库的速度。 HP-UX系统下,就是用SHLIB_PATH这个变量,而在AIX下则使用LIBPATH这个变量。
共享函数库创建的一个标准命令格式:
gcc -shared -Wl,-soname,your_soname -o library_name file_list library_list
例子:
- 1、创建Object文件:
gcc -fPIC -g -c -Wall a.c
gcc -fPIC -g -c -Wall b.c - 2、创建共享函数库
gcc -shared -Wl,-soname,liblusterstuff.so.1 -o liblusterstuff.so.1.0.1 a.o b.o -lc
如果是C++项目,最简单是使用Cmake来完成共享库的创建,步骤如下:
如果创建的是JNI链接库,则需要将 jdk/include/jni.h 和 jdk/include/linux/jni_md.h 复制到 /usr/include 目录下。反正执行make命令的时候将会报错
1、确保gcc-c++编译环境, 安装命令::
yum install gcc-c++2、安装Cmake
wget https://cmake.org/files/v3.5/cmake-3.5.1.tar.gz
tar -xvf cmake-3.5.1.tar.gz
cd cmake-3.5.1
./bootstrap
make
make install3、如果您使用的windows系统,则将您的项目上传到Linux,进入Linux下该项目的文件夹,创建CMakeLists.txt,内容格式如下:
CMAKE_MINIMUM_REQUIRED(VERSION 2.6) # cpp 文件 SET(test_SRCS source/test1.cpp source/test2.cpp ......) # 头文件SET(test_HDRS include/test1.h include/test2.h ..... ) INCLUDE_DIRECTORIES(include) # test: 是生产的库的名字, 这里可以加上SHARED或者STATIC或者MODULE,分别表示动态库、静态库、模块。不加则默认是静态库ADD_LIBRARY(test SHARED/STATIC/MODULE ${test_SRCS} ${test_HDRS}) # 生成可执行文件# ADD_EXECUTABLE(test ${test_SRCS} ${test_HDRS})
- 4、创建动态链接库:
ccmake directory #用于配置编译选项,如VTK_DIR目录,一般这一步不需要配置
cmake directory #用于根据CMakeLists.txt生成Makefile文件
make #用于执行Makefile文件,编译程序,生成可执行文件
共享函数库的使用
一旦你定义了一个共享函数库,你还需要安装它。其实简单的方法就是拷贝你的库文件到指定的标准的目录(例如/usr/lib),然后运行ldconfig。如果你没有权限去做这件事情, 那么最简单的方法就是运行ldconfig: ldconfig -n directory_with_shared_libraries 然后设置LD_LIBRARY_PATH这个环境变量,它是一个以逗号分隔的路径的集合: LD_LIBRARY_PATH=$LD_LIBRARY_PATH,my_program 如果一个新版的函数库要和老版本的二进制的库不兼容,则soname需要改变。对于C语言,有四种情况会出现不兼容问题: · 一个函数的行文改变了,这样它就可能与最开始的定义不相符合。 · 输出的数据项改变了。 · 某些输出的函数删除了。 · 某些输出函数的接口改变了。**
4、共享函数库的动态加载
共享函数库可以在程序运行过程中的任何时间加载,它们特别适合在函数中加载一些模块和plugin扩展模块的场合,因为它可以在当程序需要某个plugin模块时才动态的加载。 Linux系统下,DL函数库与其他函数库在格式上没有特殊的区别。通常C语言环境下,需要包含这个头文件。 Linux中使用的函数和Solaris中一样,都是dlpoen()API。当然不是所有的平台都使用同样的接口,例如HP-UX使用shl_load()机制,而Windows平台用另外的其他的调用接口。
dlopen()
dlopen函数打开一个函数库然后为后面的使用做准备。C语言原形是: void * dlopen(const char *filename, int flag); 如果文件名filename是以“/”开头,也就是使用绝对路径,那么dlopne就直接使用它,而不去查找某些环境变量或者系统设置的函数库所在的目录了。否则dlopen()就会按照下面的次序查找函数库文件: 1. 环境变量LD_LIBRARY指明的路径。 2. /etc/ld.so.cache中的函数库列表。 3. /lib目录,然后/usr/lib。不过一些很老的a.out的loader则是采用相反的次序,也就是先查 /usr/lib,然后是/lib。 dlopen()函数中,参数flag的值必须是RTLD_LAZY或者RTLD_NOW,RTLD_LAZY的意思是resolve undefined symbols as code from the dynamic library is executed,而RTLD_NOW的含义是resolve all undefined symbols before dlopen() returns and fail if this cannot be done' 注意函数库的加载顺序。
dlerror()
通过调用dlerror()函数,我们可以获得最后一次调用dlopen(),dlsym(),或者dlclose()的错误信息。
dlsym()
void * dlsym(void *handle, char *symbol); 函数中的参数handle就是由dlopen打开后返回的句柄,symbol是一个以NIL结尾的字符串。 如果dlsym()函数没有找到需要查找的symbol,则返回NULL。典型的调用过程如下:
dlerror(); /*clear error code */ s = (actual_type)dlsym(handle, symbol_being_searched_for); if((error = dlerror()) != NULL){ /* handle error, the symbol wasn't found */ } else { /* symbol found, its value is in s */ }
dlclose()
dlopen()函数的反过程就是dlclose()数,dlclose()函数用力关闭一个DL函数库。真正释放的时候,如果函数库里面有_fini()这个函数,则自动调用_fini()这个函数,做一些必要的处理。Dlclose()返回0表示成功,其他非0值表示错误。
动态函数库的创建:
动态函数库并非另外一种库函数格式,可只是在程序运行的任何时候动态的加载的共享函数库或。它的创建可以参考共享函数库的创建。
动态函数库的使用:
int main(int argc, char *argv){ void *handle; char *error; double (*cosine )(double); handle = dlopen("/lib/libm.so.6", RTLD_LAZY); if(!handle){ fputs(dlerror(), stderr); exit(1); } cosine = dlsym(handle, "cos"); if((error = dlerror()) != NULL){ fputs(error, stderr); exit(1); } printf("%f", (*cosine)(2, 0)); dlclose(handle); return 0; }
如果这个程序名字叫test.c,那么用下面的命令来编译:
gcc -o test test.c –ldl
- Linux下动态链接库的创建和使用
- linux下动态链接库的创建和使用
- Linux下动态链接库的创建和使用
- Linux下动态链接库的创建和使用及C调用matlab动态库问题
- Linux下动态链接库的创建和使用及C调用matlab动态库问题
- linux 动态链接库的创建和使用--动态连接
- linux 动态链接库的创建和使用--动态连接
- Linux 下动态链接库的创建与使用
- linux 动态链接的创建和使用
- windows下动态链接库的创建和使用
- linux的动态链接库的创建和使用
- LINUX下动态链接库的创建
- Linux环境下c语言静态链接库和动态链接库创建和使用
- Linux环境下c语言静态链接库和动态链接库创建和使用
- Linux环境下c语言静态链接库和动态链接库创建和使用
- Linux静态/动态链接库的创建和使用
- Linux静态/动态链接库的创建和使用
- Linux静态/动态链接库的创建和使用
- 关于jquery的$.extend(true,{},m,n)的一个小问题
- Apache实现主域名301自动跳转到www二级域名
- BoneCP连接池参数详解
- Xcode中工作空间下项目编译成功却无法开启模拟器的解决办法
- 欢迎使用CSDN-markdown编辑器
- Linux下动态链接库的创建和使用
- 双链表的简单实现
- Android5.0以太网流程源码情景分析
- #4变量的包装类#
- Json数据格式
- Qt相对路径的问题
- 网络爬虫开发技术——数据存储以及多线程
- 源码分析之LinkedList
- java IO字符流的使用记录