gpt4 book ai didi

c++ - 动态加载库和共享全局符号

转载 作者:IT王子 更新时间:2023-10-29 00:13:43 28 4
gpt4 key购买 nike

由于我在动态加载的库中观察到全局变量的一些奇怪行为,因此我编写了以下测试。

首先我们需要一个静态链接库:头文件test.hpp

#ifndef __BASE_HPP
#define __BASE_HPP

#include <iostream>

class test {
private:
int value;
public:
test(int value) : value(value) {
std::cout << "test::test(int) : value = " << value << std::endl;
}

~test() {
std::cout << "test::~test() : value = " << value << std::endl;
}

int get_value() const { return value; }
void set_value(int new_value) { value = new_value; }
};

extern test global_test;

#endif // __BASE_HPP

和源代码test.cpp

#include "base.hpp"

test global_test = test(1);

然后我写了一个动态加载的库:library.cpp

#include "base.hpp"

extern "C" {
test* get_global_test() { return &global_test; }
}

和加载此库的客户端程序:client.cpp

#include <iostream>
#include <dlfcn.h>
#include "base.hpp"

typedef test* get_global_test_t();

int main() {
global_test.set_value(2); // global_test from libbase.a
std::cout << "client: " << global_test.get_value() << std::endl;

void* handle = dlopen("./liblibrary.so", RTLD_LAZY);
if (handle == NULL) {
std::cout << dlerror() << std::endl;
return 1;
}

get_global_test_t* get_global_test = NULL;
void* func = dlsym(handle, "get_global_test");
if (func == NULL) {
std::cout << dlerror() << std::endl;
return 1;
} else get_global_test = reinterpret_cast<get_global_test_t*>(func);

test* t = get_global_test(); // global_test from liblibrary.so
std::cout << "liblibrary.so: " << t->get_value() << std::endl;
std::cout << "client: " << global_test.get_value() << std::endl;

dlclose(handle);
return 0;
}

现在我编译静态加载的库

g++ -Wall -g -c base.cpp
ar rcs libbase.a base.o

动态加载的库

g++ -Wall -g -fPIC -shared library.cpp libbase.a -o liblibrary.so

和客户

g++ -Wall -g -ldl client.cpp libbase.a -o client 

现在我观察到:客户端和动态加载的库拥有不同版本的变量 global_test。但在我的项目中,我使用的是 cmake。构建脚本如下所示:

CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(globaltest)

ADD_LIBRARY(base STATIC base.cpp)

ADD_LIBRARY(library MODULE library.cpp)
TARGET_LINK_LIBRARIES(library base)

ADD_EXECUTABLE(client client.cpp)
TARGET_LINK_LIBRARIES(client base dl)

分析创建的 makefile 我发现 cmake 使用

g++ -Wall -g -ldl -rdynamic client.cpp libbase.a -o client

这最终导致一个略有不同但致命的行为:客户端的 global_test 和动态加载的库是相同的,但将在程序结束时被销毁两次。

我是否以错误的方式使用 cmake?有没有可能客户端和动态加载的库使用相同的global_test却没有这个双重破坏的问题?

最佳答案

g++ -Wall -g -ldl -rdynamic client.cpp libbase.a -o client

CMake 添加了 -rdynamic 选项,允许加载的库在加载的可执行文件中解析符号...所以你可以看到这是你不想要的。如果没有这个选项,它只是意外地错过了这个符号。

但是……你不应该在那里做任何那样的事情。您的库和可执行文件应该不要共享符号,除非它们确实应该共享。

始终将动态链接视为静态链接。

关于c++ - 动态加载库和共享全局符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3004318/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com