在Linux环境下使用C++实现动态链接库(Dynamic Link Library,DLL)通常指的是创建共享对象(Shared Object,.so文件)。动态链接库允许你在程序运行时加载和使用库中的函数,而不是在编译时静态链接。这在多个程序需要共享相同代码时非常有用,可以节省内存并方便更新。
下面将详细介绍如何在Linux中使用C++创建和使用动态链接库,包括编写代码、编译生成共享库以及在其他程序中使用该库。
1. 创建动态链接库
步骤一:编写头文件
首先,定义你希望在共享库中导出的函数和类。例如,创建一个名为 mylib.h 的头文件:
// mylib.h
#ifndef MYLIB_H
#define MYLIB_H
#ifdef __cplusplus
extern "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.o
g++ -shared -o libmylib.so mylib.o
参数说明:
-fPIC(Position Independent Code):生成位置无关代码,这是创建共享库所必需的。-c:只编译不链接,生成目标文件(.o)。-shared:生成共享库。
步骤四(可选):创建静态库作为中间步骤
有时,可以先创建一个静态库,再从中生成共享库:
ar rcs libmylib.a mylib.o
g++ -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. 注意事项
-
名称改编(Name Mangling):
- 使用
extern "C"可以避免C++的名称改编,确保函数名在共享库中保持不变。 - 如果不使用
extern "C",函数名会被改编,导致链接时找不到对应的符号。
- 使用
-
编译选项:
- 确保在编译共享库和主程序时使用相同的C++标准,以避免兼容性问题。
- 使用
-fPIC生成位置无关代码是创建共享库的关键。
-
库路径和运行时搜索路径:
- 在编译时使用
-L指定库路径。 - 在运行时设置
LD_LIBRARY_PATH或将共享库复制到标准库路径,以确保程序能够找到共享库。
- 在编译时使用
-
版本管理:
- 为共享库使用版本号,可以避免不同版本之间的冲突。例如,在文件名中加入版本号:
libmylib.so.1。 - 使用
soname来管理共享库的版本。
- 为共享库使用版本号,可以避免不同版本之间的冲突。例如,在文件名中加入版本号:
-
符号导出:
-
如果需要导出更多的符号,可以使用
__attribute__((visibility("default")))来显式控制符号的可见性。 -
例如:
// 在头文件中 #ifdef __cplusplus extern "C" { #endif __attribute__((visibility("default"))) void hello_from_lib(); #ifdef __cplusplus } #endif
-
-
使用
nm工具查看符号:-
可以使用
nm工具查看共享库中导出的符号:nm -D libmylib.so
-
-
清理编译生成的文件:
- 在重新编译共享库时,确保删除旧的目标文件和共享库,以避免版本冲突。
4. 示例总结
目录结构
project/
├── include/
│ └── mylib.h
├── src/
│ └── mylib.cpp
├── main.cpp
└── Makefile
Makefile 示例
为了简化编译过程,可以编写一个 Makefile:
# 编译器
CXX = g++
# 编译选项
CXXFLAGS = -Wall -fPIC
# 链接选项
LDFLAGS = -shared
# 源文件
SRCS = src/mylib.cpp
MAIN_SRC = main.cpp
# 目标文件
OBJECTS = $(SRCS:.cpp=.o)
MAIN_OBJECT = $(MAIN_SRC:.cpp=.o)
# 共享库名称
LIB_NAME = libmylib.so
# 可执行文件名称
EXEC_NAME = myapp
all: $(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)
使用说明
- 将上述文件按照目录结构放置。
- 在项目根目录下运行
make命令进行编译。 - 运行生成的可执行文件
./myapp。
5. 参考资料
通过以上步骤,你可以在Linux环境下使用C++成功创建和使用动态链接库。如果有进一步的问题,欢迎继续提问!
以上就是关于“Linux C++中如何实现动态链接库”的相关介绍,筋斗云是国内较早的云主机应用的服务商,拥有10余年行业经验,提供丰富的云服务器、租用服务器等相关产品服务。云服务器资源弹性伸缩,主机vCPU、内存性能强悍、超高I/O速度、故障秒级恢复;电子化备案,提交快速,专业团队7×24小时服务支持!
简单好用、高性价比云服务器租用链接:https://www.jindouyun.cn/product/cvm