C/C++编译问题,摆脱编译时的动态库依赖

本文探讨了如何在编译时避免繁琐地指定依赖库路径,包括使用gcc命令行、cmake构建工具以及通过dl库在运行时动态加载库,以简化开发流程并管理动态库依赖关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

在编译程序时,考虑如下场景:
代码中使用到了A库的函数,此外再无其它依赖库。但是,A库中使用了B库的函数,B库依赖C库,C库依赖D库。因此在编译可执行文件时,需要找到ABCD,并指定库的路径,在链接时才不会爆出找不到某个定义的错误。
如果在交叉编译时A库的依赖项高达几十甚至更多个,会让编译变得非常麻烦,需要指定每个库的位置和库名,有些情况可能需要给库添加软链。有没有什么方法在编译时不需要指定依赖?


一、命令行gcc编译或shell脚本编译

// libfunA.so
void funA() {printf("libFunA.so\n");funB();}
// libfunB.so
void funB() {printf("libFunB.so\n");funC();}
// libfunC.so
void funC() {printf("libFunC.so\n");}

int main()
{printf("main\n");funA();}

编译动态库

gcc -fPIC -shared xxx.c -o libfunA.so
  • 此时生成的动态库中只含有一个libfunA.so字符串

  • 通过ldd命令查看libfunA.so的依赖,其中没有libfunB.so,即依赖项没有添加入动态库的二进制文件中

二、cmake编译

Cmake简单使用
cmake 编译时会默认指定一些参数,因此和上面简单的指定参数相比cmake会加入更多选项。

生成动态库时:

  • 此时生成的动态库中含有两个libfunA.so字符串
  • 当未指定动态库的依赖项时,ldd命令没有显示依赖项libfunB.so; 当指定依赖项时,ldd显示依赖libfunB.so

三、取消编译时的依赖

#include <dlfcn.h>  // link with -ldl
dlopen
dlerror
dlsym
dlclose
// loads the dynamic shared object
void *handle(const char*filename, int flags);
- filename: filename, if is null, the return handle is for the main program.
			          if contain slash("/"), relative or absolute pathname

filename: filename, if is null, the return handle is for the main program.if contain slash(“/”), relative or absolute pathname
动态库搜索:

  1. 如果过调用对象中包含DT_RPATH,不包含 DT_RUNPATH,则搜索DT_RPATH中的路径
  2. 环境变量LD_LIBRARY_PATH中的路径顺序
  3. DT_RUNPATH的目录
  4. 缓存文件/etc/ld.so.cache(由ldconfig(8)维护)
  5. 目录/lib然后/usr/lib

flags: 以下二者之一

  1. RTLD_LAZY: 使用时加载
  2. RTLD_NOW: 立即加载
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <gnu/lib-names.h>  // GNU libc so name macros
int main()
{
  void* handle; double(*cosine)(double); char* error;
  handle = dlopen(LIBM_SO, RTLD_LAZY);
  if (!handle) {exit(1);}
  dlerror(); // clear error
  cosine = (double(*)(double))dlsym(handle, "cos");
  error = dlerror();
  if (error != NULL) {printf("%s\n", error); exit(1);}
  printf("%f\n", cosine(3.1415926));
  dlclose(handle);
}

四、运行时指定依赖库路径

  1. 将动态库路径放入LD_LIBRARY_PATH

总结

在编译可执行文件时,需要找到所有已使用符号的定义,如果该符号在动态库中就需要指定动态库; 如果动态库依赖了另外的动态库,也需要指明该库。
通过dl库可在编译时避免指定动态库,方便编译。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值