动态加载库和共享全局符号 [英] Dynamic loaded libraries and shared global symbols

查看:125
本文介绍了动态加载库和共享全局符号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Since I observed some strange behavior of global variables in my dynamically loaded libraries, I wrote the following test.

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

At first we need a statically linked library: The header 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

Then I wrote a dynamically loaded library: library.cpp

#include "base.hpp"

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

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

and a client program loading this library: 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;
}



现在我用

Now I compile the statically loaded library with

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。构建脚本如下所示:

Now I observe: The client and the dynamically loaded library possess a different version of the variable global_test. But in my project I'm using cmake. The build script looks like this:

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)

分析创建的 / code> s我发现cmake使用

analyzing the created makefiles I found that cmake builds the client with

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

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

This ends up in a slightly different but fatal behavior: The global_test of the client and the dynamically loaded library are the same but will be destroyed two times at the end of the program.

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

Am I using cmake in a wrong way? Is it possible that the client and the dynamically loaded library use the same global_test but without this double destruction problem?

推荐答案


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


CMake添加 -rdynamic 选项加载库来解析加载可执行文件中的符号...所以你可以看到,这是你不想要的。没有这个选项,它只是偶然错过了这个符号。

CMake adds -rdynamic option allowing loaded library to resolve symbols in the loading executable... So you can see that this is what you don't want. Without this option it just misses this symbol by accident.

但是...你不应该做那样的东西。

But... You should not do any stuff like that there. Your libraries and executable should not share symbols unless they are really should be shared.

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

Always think of dynamic linking as static linking.

这篇关于动态加载库和共享全局符号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆