码界工坊

htykm.cn
人生若只如初见

Linux C++中如何实现动态链接库

在Linux环境下使用C++实现动态链接库(Dynamic Link Library,DLL)通常指的是创建共享对象(Shared Object,.so文件)。动态链接库允许你在程序运行时加载和使用库中的函数,而不是在编译时静态链接。这在多个程序需要共享相同代码时非常有用,可以节省内存并方便更新。

下面将详细介绍如何在Linux中使用C++创建和使用动态链接库,包括编写代码、编译生成共享库以及在其他程序中使用该库。

1. 创建动态链接库

步骤一:编写头文件

首先,定义你希望在共享库中导出的函数和类。例如,创建一个名为 mylib.h的头文件:

// mylib.h#ifndef MYLIB_H#define MYLIB_H#ifdef __cplusplusextern "C" { #endif// 导出函数void hello_from_lib();// 导出类class MyClass { public:    MyClass();    void greet();};#ifdef __cplusplus}#endif#endif // MYLIB_H

说明:

  • 使用 extern "C"可以防止C++的名称改编(name mangling),使得库中的函数在C语言中也能被正确调用。
  • 如果不需要导出类,可以只定义函数。

步骤二:实现库的源文件

创建一个实现头文件中声明的源文件,例如 mylib.cpp

// mylib.cpp#include "mylib.h"#include // 实现导出函数void hello_from_lib() {     std::cout << "Hello from the library!" << std::endl;}// 实现导出类MyClass::MyClass() {     // 构造函数实现}void MyClass::greet() {     std::cout << "Greetings from MyClass!" << std::endl;}

步骤三:编译生成共享库

使用 g++编译源文件,生成共享库(.so文件)。例如,生成名为 libmylib.so的共享库:

g++ -fPIC -c mylib.cpp -o mylib.og++ -shared -o libmylib.so mylib.o

参数说明:

  • -fPIC(Position Independent Code):生成位置无关代码,这是创建共享库所必需的。
  • -c:只编译不链接,生成目标文件(.o)。
  • -shared:生成共享库。

步骤四(可选):创建静态库作为中间步骤

有时,可以先创建一个静态库,再从中生成共享库:

ar rcs libmylib.a mylib.og++ -fPIC -shared -o libmylib.so -Wl,--whole-archive libmylib.a -Wl,--no-whole-archive

2. 使用动态链接库

假设你已经生成了 libmylib.so,下面是如何在其他C++程序中使用该库。

步骤一:编写使用库的程序

创建一个主程序文件,例如 main.cpp

// main.cpp#include #include "mylib.h"int main() {     // 调用库中的函数    hello_from_lib();    // 使用库中的类    MyClass obj;    obj.greet();    return 0;}

步骤二:编译主程序并链接共享库

在编译时,需要指定共享库的位置。可以使用 -L指定库路径,使用 -l指定库名(去掉 lib前缀和 .so后缀)。

假设 libmylib.so位于当前目录:

g++ -o myapp main.cpp -L. -lmylib

步骤三:设置运行时库路径

为了让程序在运行时找到 libmylib.so,需要设置 LD_LIBRARY_PATH环境变量:

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

或者,可以将共享库复制到系统的标准库路径,如 /usr/lib/usr/local/lib

步骤四:运行程序

./myapp

输出应为:

Hello from the library!Greetings from MyClass!

3. 注意事项

  1. 名称改编(Name Mangling):

    • 使用 extern "C"可以避免C++的名称改编,确保函数名在共享库中保持不变。
    • 如果不使用 extern "C",函数名会被改编,导致链接时找不到对应的符号。
  2. 编译选项:

    • 确保在编译共享库和主程序时使用相同的C++标准,以避免兼容性问题。
    • 使用 -fPIC生成位置无关代码是创建共享库的关键。
  3. 库路径和运行时搜索路径:

    • 在编译时使用 -L指定库路径。
    • 在运行时设置 LD_LIBRARY_PATH或将共享库复制到标准库路径,以确保程序能够找到共享库。
  4. 版本管理:

    • 为共享库使用版本号,可以避免不同版本之间的冲突。例如,在文件名中加入版本号:libmylib.so.1
    • 使用 soname来管理共享库的版本。
  5. 符号导出:

    • 如果需要导出更多的符号,可以使用 __attribute__((visibility("default")))来显式控制符号的可见性。

    • 例如:

      // 在头文件中#ifdef __cplusplusextern "C" { #endif__attribute__((visibility("default"))) void hello_from_lib();#ifdef __cplusplus}#endif
  6. 使用 nm工具查看符号:

    • 可以使用 nm工具查看共享库中导出的符号:

      nm -D libmylib.so
  7. 清理编译生成的文件:

    • 在重新编译共享库时,确保删除旧的目标文件和共享库,以避免版本冲突。

4. 示例总结

目录结构

project/├── include/│   └── mylib.h├── src/│   └── mylib.cpp├── main.cpp└── Makefile

Makefile 示例

为了简化编译过程,可以编写一个 Makefile

# 编译器CXX = g++# 编译选项CXXFLAGS = -Wall -fPIC# 链接选项LDFLAGS = -shared# 源文件SRCS = src/mylib.cppMAIN_SRC = https://www.yisu.com/ask/main.cpp"hljs">$(LIB_NAME) $(EXEC_NAME)$(LIB_NAME): $(OBJECTS)	$(CXX) $(LDFLAGS) -o $@ $^$(EXEC_NAME): $(MAIN_OBJECT) $(LIB_NAME)	$(CXX) -o $@ $^ -L. -lmylib%.o: %.cpp	$(CXX) $(CXXFLAGS) -Iinclude -c $< -o $@clean:	rm -f $(OBJECTS) $(MAIN_OBJECT) $(LIB_NAME) $(EXEC_NAME)

使用说明

  1. 将上述文件按照目录结构放置。
  2. 在项目根目录下运行 make命令进行编译。
  3. 运行生成的可执行文件 ./myapp

5. 参考资料

  • C++ Shared Libraries
  • Linux Dynamic Linking and Loading Library
  • GNU C++ Compiler Documentation

通过以上步骤,你可以在Linux环境下使用C++成功创建和使用动态链接库。如果有进一步的问题,欢迎继续提问!

未经允许不得转载 » 本文链接:http://htykm.cn/html/741c699252.html

推荐文章

  • nohup命令在Linux中的输出重定向是如何工作的

    nohup命令在Linux中用于在后台运行命令,即使关闭终端或断开连接,该命令也会继续运行。默认情况下,nohup会将命令的输出重定向到一个名为nohup.out的文件中。以下是nohup命令在Lin ...

  • 姓名域名是什么意思?姓名域名有何价值?

    姓名域名是什么意思?姓名域名有何价值?近年来,与体育界名人相关的域名引发了米农的广泛关注,早在不久之前,就有很多以体育界名人姓名拼音为前缀的域名被高价拍卖或注册,很多人都想姓名域名的价值只适用于投资, ...

  • 域名怎么续费便宜?聚名活动对域名续费力度多大?

    域名怎么续费便宜?聚名活动对域名续费力度多大?域名续费要便宜实惠,选择合适的续费时间点非常重要,比如域名服务商周年纪念日、域名注册局周年纪念日,以及各种节日、双11、年中、年末、双节等。此外,续签年限 ...

  • xyz和com区别有哪些?选择哪种域名好?

    xyz和com区别有哪些?选择哪种域名好?域名com和xyz的主要区别在于域名类型不同。Com属于最早的一批通用顶级域名后缀,xyz属于新的通用顶级域名后缀。下面聚名网小编就带大家看看xyz和com区 ...

  • CentOS readdir如何实现递归读取

    在 CentOS 系统中,你可以使用 find命令来实现递归读取目录find /path/to/directory -type d这个命令会从指定的目录/path/to/directory)开始,递归 ...

  • 域名好的状态是如何的?如何寻找好域名?

    域名好的状态是如何的?如何寻找好域名?站长们在平常都会进行一些建站经验的交流,域名是互联网的门牌号,一个好的域名就像是一个好地段的房产权一样,一个好的域名也是你的网站成功基石。下面聚名网小编就带大家看 ...

  • 域名注册前需掌握哪些技巧?有什么方法?

    域名注册前需掌握哪些技巧?有什么方法?选择注册域名看似一个简单的事情,其实关乎到我们网站的发展和以后的运行,一个好的域名有利于用户的体验,容易记住我们的域名,也有利于搜索引擎对我们网站或者品牌的收录, ...

  • 域名本身有价值吗?如何评估域名本身价值?

    域名本身有价值吗?如何评估域名本身价值?我们如何为自己的待售域名做出一个合理的市场价值的判断?在本文中将充分介绍域名价值评估的各方面标准,也为各位参与域名投资行为的朋友购买域名提供了一个有利的可参考资 ...