【发布时间】:2011-03-01 13:33:50
【问题描述】:
由于我在动态加载的库中观察到全局变量的一些奇怪行为,因此我编写了以下测试。
首先我们需要一个静态链接库:标题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)
分析创建的makefiles我发现cmake构建客户端是用
g++ -Wall -g -ldl -rdynamic client.cpp libbase.a -o client
这最终会导致一个稍微不同但致命的行为:客户端的global_test 和动态加载的库是相同的,但会在程序结束时被销毁两次。
我是否以错误的方式使用 cmake?客户端和动态加载的库是否有可能使用相同的global_test,但没有这种双重破坏问题?
【问题讨论】:
-
我的第一反应是质疑这个全局变量的必要性。
-
好的,在我的原始程序中,这个全局变量是一个静态链接库提供的常量。但是在cmake版本中还是会被破坏两次
-
同样的问题适用于任何单例模式,所以我看不出全局有问题
标签: c++ linux g++ shared-libraries cmake