Note that there are some explanatory texts on larger screens.

plurals
  1. PODynamic loaded libraries and shared global symbols
    primarykey
    data
    text
    <p>Since I observed some strange behavior of global variables in my dynamically loaded libraries, I wrote the following test. </p> <p>At first we need a statically linked library: The header <code>test.hpp</code></p> <pre><code>#ifndef __BASE_HPP #define __BASE_HPP #include &lt;iostream&gt; class test { private: int value; public: test(int value) : value(value) { std::cout &lt;&lt; "test::test(int) : value = " &lt;&lt; value &lt;&lt; std::endl; } ~test() { std::cout &lt;&lt; "test::~test() : value = " &lt;&lt; value &lt;&lt; std::endl; } int get_value() const { return value; } void set_value(int new_value) { value = new_value; } }; extern test global_test; #endif // __BASE_HPP </code></pre> <p>and the source <code>test.cpp</code></p> <pre><code>#include "base.hpp" test global_test = test(1); </code></pre> <p>Then I wrote a dynamically loaded library: <code>library.cpp</code></p> <pre><code>#include "base.hpp" extern "C" { test* get_global_test() { return &amp;global_test; } } </code></pre> <p>and a client program loading this library: <code>client.cpp</code></p> <pre><code>#include &lt;iostream&gt; #include &lt;dlfcn.h&gt; #include "base.hpp" typedef test* get_global_test_t(); int main() { global_test.set_value(2); // global_test from libbase.a std::cout &lt;&lt; "client: " &lt;&lt; global_test.get_value() &lt;&lt; std::endl; void* handle = dlopen("./liblibrary.so", RTLD_LAZY); if (handle == NULL) { std::cout &lt;&lt; dlerror() &lt;&lt; std::endl; return 1; } get_global_test_t* get_global_test = NULL; void* func = dlsym(handle, "get_global_test"); if (func == NULL) { std::cout &lt;&lt; dlerror() &lt;&lt; std::endl; return 1; } else get_global_test = reinterpret_cast&lt;get_global_test_t*&gt;(func); test* t = get_global_test(); // global_test from liblibrary.so std::cout &lt;&lt; "liblibrary.so: " &lt;&lt; t-&gt;get_value() &lt;&lt; std::endl; std::cout &lt;&lt; "client: " &lt;&lt; global_test.get_value() &lt;&lt; std::endl; dlclose(handle); return 0; } </code></pre> <p>Now I compile the statically loaded library with</p> <pre><code>g++ -Wall -g -c base.cpp ar rcs libbase.a base.o </code></pre> <p>the dynamically loaded library</p> <pre><code>g++ -Wall -g -fPIC -shared library.cpp libbase.a -o liblibrary.so </code></pre> <p>and the client</p> <pre><code>g++ -Wall -g -ldl client.cpp libbase.a -o client </code></pre> <p>Now I observe: The client and the dynamically loaded library possess a different version of the variable <code>global_test</code>. But in my project I'm using cmake. The build script looks like this:</p> <pre><code>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></pre> <p>analyzing the created <code>makefile</code>s I found that cmake builds the client with</p> <pre><code>g++ -Wall -g -ldl -rdynamic client.cpp libbase.a -o client </code></pre> <p>This ends up in a slightly different but fatal behavior: The <code>global_test</code> of the client and the dynamically loaded library are the same but will be destroyed two times at the end of the program.</p> <p>Am I using cmake in a wrong way? Is it possible that the client and the dynamically loaded library use the same <code>global_test</code> but without this double destruction problem?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload