Linux 编译动态库_makefile编译动态库

Linux 编译动态库_makefile编译动态库1.动态链接库简介动态库又叫动态链接库,是程序运行的时候加载的库,当动态链接库正确安装后,所有的程序都可以使用动态库来运行程序。动态库是目标文件的集合,目标文件在动态库中的组织方式是按特殊的方式组织形成的。在动态库中函数和变量的地址是相对地址而不是绝对地址,其真实地址在调用动态库的程序加载时形成的。动态库的名字有别名(soname),真名(realname)和链接名(linke…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

1. 动态链接库简介

  • 动态库又叫动态链接库,是程序运行的时候加载的库,当动态链接库正确安装后,所有的程序都可以使用动态库来运行程序。动态库是目标文件的集合,目标文件在动态库中的组织方式是按特殊的方式组织形成的。在动态库中函数和变量的地址是相对地址而不是绝对地址,其真实地址在调用动态库的程序加载时形成的。

  • 动态库的名字有别名(soname), 真名(realname)和链接名(linkername)。别名是由一个lib前缀,然后是库的名字,最后以“.so”结尾来构成。真名是动态链接库的真实名字,一般总是在别名的基础上添加一个版本号信息。除此之外还有一个链接名,他是在程序链接的时候使用的名字。

  • 动态库安装的时候,总是复制库文件到某一个目录,然后使用一个软链接生成一个别名,在库文件更新的时候,仅仅更新软链接即可。

2. 生成动态链接库

生成动态链接库的命令比较简单:

2.1 使用-shared 告诉编译器生成一个动态链接库
2.2 使用选项-fPIC或者-fpic,使得生成的代码与位置无关
gcc -shared -Wl, -soname, libstr.so -o libstr.so.1 string.c

其中,“-shared” 表示要生成的为动态链接库文件;
“-soname, libstr.so” 表示生成的动态链接库的别名为“libstr.so”;
“-o libstr.so” 表示生成名字为“libstr.so.1”的实际动态链接库文件;

2.3 动态链接库的安装

生成动态链接库后,一个很重要的操作是安装,一般情况下,我们将库文件放到系统默认的搜索路径下,常用的有/lib, /usr/lib, /usr/local/lib 。将 动态链接库放到这三个中任意个目录都可以。

3. 动态链接库的配置文件

一般情况下,动态链接库不能随意使用。如果要在运行的程序中使用动态链接库,需要制定系统的动态链接库搜索路径,只有让系统能找到运行时需要的动态链接库才能使用它。 系统中的配置文件/etc/ld.so.conf便是动态链接库的搜索路径配置文件。在这个文件内存放着可以被Linux共享的动态链接库所在目录的名字(系统默认的/lib, /usr/lib除外)。 多个目录之间可以使用空格,换行符进行隔开
在ubantu虚拟机下查看“/ld.so.conf”文件:

book@www.100ask.org:~$ cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf 

根据内容然后查看“/etc/ld.so.conf.d/”目录下的文件:

book@www.100ask.org:/etc/ld.so.conf.d$ cat *.conf
/usr/lib/x86_64-linux-gnu/libfakeroot
# libc default configuration
/usr/local/lib
/usr/lib/vmware-tools/lib32/libvmGuestLib.so
/usr/lib/vmware-tools/lib64/libvmGuestLib.so
/usr/lib/vmware-tools/lib32/libvmGuestLibJava.so
/usr/lib/vmware-tools/lib64/libvmGuestLibJava.so
/usr/lib/vmware-tools/lib32/libDeployPkg.so
/usr/lib/vmware-tools/lib64/libDeployPkg.so
# Multiarch support
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu/mesa-egl
/usr/lib/x86_64-linux-gnu/mesa
# Legacy biarch compatibility support
/lib32
/usr/lib32
book@www.100ask.org:/etc/ld.so.conf.d$ 

所以这个百问网的虚拟机动态库的搜索路径包含了上述列出的目录。

4. 动态链接库管理命令

为了让新增加的动态链接库能够被系统所共享,我们需要设置运行动态链接库的管理命令ldconfig。 ldconfig命令的作用是在系统的默认搜索路径(/lib, /usr/lib, /usr/local/lib)以及动态链接库配置文件所列出的目录里搜索动态链接库,然后创建动态链接装入程序需要的链接和缓存文件。 搜索完毕后将结果写入到缓存文件“/etc/ld.so.cache”中, 文件中保存的是已经排好序的动态链接库名字列表,一般情况下里面的动态链接库很多,我们可以使用ldconfig -p命令来查看列表对应的动态库信息:

book@www.100ask.org:/etc$ ldconfig -p
1137 libs found in cache `/etc/ld.so.cache'
	libzvbi.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzvbi.so.0
	libzvbi-chains.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzvbi-chains.so.0
	libzmq.so.5 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzmq.so.5
	libzeitgeist-2.0.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzeitgeist-2.0.so.0
	libzeitgeist-1.0.so.1 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzeitgeist-1.0.so.1
	libz.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libz.so.1
	libz.so.1 (libc6) => /usr/lib32/libz.so.1
	... ...

使用ldconfig命令默认情况下不输出扫描的结果信息,它的作用是更新系统默认搜索路径和配置文件中制定的搜索路径,然后将扫描结果缓存到“/etc/ld.so.cache”中,供运行程序快速访问调用。

我们也可以通过ldconfig命令来直接指定搜索路径:ldconfig 目录名

但这个是指临时制定,重新执行ldconfig则不会再包括制定的目录,除非在配置文件中添加上该目录。

5. 使用动态链接库

在编译程序的时候,使用动态链接库和静态链接库是一致的, 使用“-l库名”的形式,编译器在生成可执行文件的时候会链接该链接库文件。例如:

gcc -o test main.c -L ./ -lstr

-L : 指定链接动态库的路径
-lstr : 制定链接的动态库名称

这里需要注意的是: 编译的链接动态库和运行的动态链接库并不一致。 运行时的动态链接库需要放到系统搜索路径下。

6. 动态加载库的使用

动态加载库和动态链接库不同的是, 一般的动态链接库需要在程序启动的时候就要寻找动态链接库,找到库函数。而动态加载库可以使用程序的方法控制什么时候 加载。

动态加载库主要函数有: dlopen(), dlclose(), dlsym()和dlerror()。

6.1 打开动态库dlopen()函数

函数dlopen()按照用户指定的方式打开动态链接库。

void *dlopen(const char *filename, int flags);
# filename: 为动态链接库的文件名,当然可以包括路径部分
# flags: 打开方式,一般选择RTLD_LASY
# 函数返回值为库指针 

例如我们可以使用下面的栗子打开指定目录下的动态库libbhd_client.so:

void *handle = dlopen("/tos/so/libbhd_client.so", RTLD_LASY);

6.2 获取函数指针dlsys()函数

我们使用动态链接库的最主要目的便是使用其中的函数接口(一个原因是模块间互相独立开发,另一个在于非开源保密)。 函数dlsys()可以获取指定函数名的函数指针,之后我们可以使用函数指针进行相关操作。

void *dlsym(void *handle, char *symbol)
# handle : 为使用函数dlopen()获取到的动态链接库指针
# symbol : 函数的名称
# 返回值为函数指针

6.3 使用动态加载库的栗子1:

#include <stdio.h>
       #include <stdlib.h>
       #include <dlfcn.h>
       #include <gnu/lib-names.h> /* Defines LIBM_SO (which will be a string such as "libm.so.6") */
       int main(void)
       { 
   
           void *handle;
           double (*cosine)(double);
           char *error;
           handle = dlopen(LIBM_SO, RTLD_LAZY);
           if (!handle) { 
   
               fprintf(stderr, "%s\n", dlerror());
               exit(EXIT_FAILURE);
           }
           dlerror();    /* Clear any existing error */
           cosine = (double (*)(double)) dlsym(handle, "cos");
/* According to the ISO C standard, casting between function pointers and 'void *', as done above, produces undefined results. POSIX.1-2003 and POSIX.1-2008 accepted this state of affairs and proposed the following workaround: *(void **) (&cosine) = dlsym(handle, "cos"); This (clumsy) cast conforms with the ISO C standard and will avoid any compiler warnings. The 2013 Technical Corrigendum to POSIX.1-2008 (a.k.a.POSIX.1-2013) improved matters by requiring that conforming implementations support casting 'void *' to a function pointer. Nevertheless, some compilers (e.g., gcc with the '-pedantic' option) may complain about the cast used in this program. */
           error = dlerror();
           if (error != NULL) { 
   
               fprintf(stderr, "%s\n", error);
               exit(EXIT_FAILURE);
           }
           printf("%f\n", (*cosine)(2.0));
           dlclose(handle);
           exit(EXIT_SUCCESS);
       }

6.4 使用动态加载库的栗子2:

由于我们可以通过程序指定动态加载库的时间,通过动态加载库可以实现模块的动态扩展。
思路如下:

  • 在某个特定目录放不同模块编译生成的动态库;
  • 程序中遍历该目录下所有的符合条件的动态库,然后打开动态库获取相关函数(例如module_init()),一般为模块的注册或者初始化函数,完成相应模块的加载或初始化操作;
  • 这种情况下有个特点:每一个模块的初始化函数名都是固定的(如module_init()),这样便可以完成模块的动态加载。
    具体代码如下:
#define BFD_CLIENT_REG_FUNC_NAME "bfd_client_register"
static int bfd_client_reg_init(const char *path)
{ 
   
	struct dirent *dp;
	DIR *dfd = NULL;
	struct stat stbuf;
	memset(&stbuf, 0, sizeof(struct stat));
	if(stat(path, &stbuf))
	{ 
   
		bfd_debug("can not access:%s.\n", path);
		goto err_out;
	}
	if ((stbuf.st_mode & S_IFMT) != S_IFDIR)
	{ 
   
		bfd_debug("st_mode error:%d.\n", stbuf.st_mode);
		goto err_out;
	}

	if((dfd = opendir(path)) == NULL)
	{ 
   
		bfd_debug("open error:%s\n", path);
		goto err_out;
	}
	while((dp = readdir(dfd)) != NULL)
	{ 
   
		if(0 == strcmp(dp->d_name, ".") || 0 == strcmp(dp->d_name, ".."))
		{ 
   
			continue;
		}
		if(dp->d_name == strstr(dp->d_name, "libtos_ipp_"))
		{ 
   
			char client_path[256];
			strcpy(client_path, path);
			if('/' != path[strlen(path) -1])
			{ 
   
				strcat(client_path, "/");
			}
			strcat(client_path, dp->d_name);
			bfd_client_reg_load(client_path);
		}
	}
	closedir(dfd);
	
	return 0;
err_out:
	if(NULL != dfd)
	{ 
   
		closedir(dfd);
	}
	return -1;
}
static int bfd_client_reg_load(const char *dl_name)
{ 
   
	int id = -1;
	bfd_client_init_func func;
	void *handle;
	char *error;

	handle = dlopen(dl_name, RTLD_LAZY);
	if(NULL == handle)
	{ 
   
		goto err_out;
	}

	func = dlsym(handle, BFD_CLIENT_REG_FUNC_NAME); /*bfd_client_register: 使用模块注册函数完成相应模块的注册*/
	if((error = dlerror()) != NULL)
	{ 
   
		goto err_out;
	}
	id = func();   /*执行注册函数*/
	if(id < 0 || id > 5)
	{ 
   
		bfd_debug("id err:%d.\n", id);
		goto err_out;
	}
	return 0;
err_out:
	bfd_debug("err_out.\n");
	if(handle)
	{ 
   
		dlclose(handle);
	}
	return -1;
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/189023.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 九九乘法表

    九九乘法表九九乘法表

    2022年4月24日
    44
  • 图像处理之霍夫变换(直线检测算法)

    图像处理之霍夫变换(直线检测算法)图像处理之霍夫变换 直线检测算法 霍夫变换是图像变换中的经典手段之一 主要用来从图像中分离出具有某种相同特征的几何形状 如 直线 圆等 霍夫变换寻找直线与圆的方法相比与其它方法可以更好的减少噪声干扰 经典的霍夫变换常用来检测直线 圆 椭圆等 nbsp 霍夫变换算法思想 以直线检测为例 每个像素坐标点经过变换都变成都直线特质有贡献的统一度量 一个简单的例子如下 一条直线在图

    2025年9月27日
    5
  • vue filters过滤器的统一封装「建议收藏」

    vue filters过滤器的统一封装「建议收藏」目录统一封装规则统一封装规则1、src文件夹下创建filters文件夹,然后再filters文件夹下创建index.js即:src/filters/index.js2、在main.js中引入src/filters/index.js文件,并在下方遍历调用filters中的方法,使用VUE.filters切记:将遍历代码写在newVUE()上方3、在src/utils文件夹下的文件中创建各种工具类方法4、在src/filters/index.js中引入utils中的方法进行调用src

    2022年5月22日
    38
  • 解决GitHub下载速度太慢的问题「建议收藏」

    解决GitHub下载速度太慢的问题「建议收藏」方法一:从GitHub下载文件一直非常慢,查看下载链接发现最终被指向了Amazon的服务器,下载地址是http://github-cloud.s3.amazonaws.com/,从国内访问Amazon非常慢,所以总是下载失败,解决方法时更改host文件,使该域名指向香港的服务器:更改hosts文件:Windows更改C:\Windows\System32\driver…

    2022年5月3日
    44
  • webservice有哪些框架_前端主流js框架

    webservice有哪些框架_前端主流js框架Webservice框架CXF最新版本:2.2.2开源服务框架,可以通过API,如JAX-WS,构建和开发服务。服务可以使多种协议的,例如SOAP,XML/HTTP,RESTfulHTTP, CORBA,并可以工作与多种传输协议之上,如HTTP,JMS,JBI。主要特性l 支持Webservice标准:包括SOAP,theBasicProfile,WSDL,WS-Addres…

    2022年9月21日
    7
  • 点击率预估算法:FM与FFM[通俗易懂]

    点击率预估算法:FM与FFM[通俗易懂]点击率预估算法:FFM@(计算广告)[计算广告]点击率预估算法FFM1FM1背景11线性模型12二项式模型2FM21FM基本原理22数据分析23参数个数24计算时间复杂度25梯度26训练时间复杂度2FFM1背景及基本原理2模型与最优化问题21模型22最优化问题23自适应学习率24FFM算法的最终形式3完整算法流程31计算梯度32

    2022年4月30日
    82

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号