0
votes

I'm a little confused right now. Yesterday I had undefined symbols even if I used -rdynamic with g++. But now I don't have any error and that is even more disturbing.

To explain a bit my case, I want to do some sort of plugin like shared object. I haven't decided yet which is the best way to do.

A) My shared objects all have a function called register which will be called with a parameter. This will be a plugin manager.

B) My shared object will define a class and will create and instance of that class at load time. In the constructor of that class it will try to get a static singleton from the app and auto register himself.

As far as I can tell my first attempts weren't so great so far.

main.cpp

#include "main.hpp"
#include <iostream>
#include <cstdio>
#include <dlfcn.h>

int S::shared = 0;

int main(int argc, char** argv){
    std::cout << "In main -> " << S::shared << "\n";

    void* triangle = dlopen("./libtwo.so", RTLD_LAZY);

    if(triangle == NULL){
        std::cout << "Error while loading so file\n" << dlerror() << "\n";
    }

    std::cout << "In main -> " << S::shared << "\n" << triangle;
    return 0;
}

main.hpp

class S {
    public:
    static int shared;

    S(){
        S::shared = 0;
    };
};

two.cpp

#include "main.hpp"
#include <iostream>

class MyObject {
    public:
    MyObject(){
        std::cout << "In two -> " << S::shared  << "\n";
    }
};

MyObject t();

In that sample S::shared is the static object I would share. For this simple test I only use a int but in the futur it would be an instance of a class.

My only attempt at case A) was a segfault... I really don't know what I missed.

//Results so far (today)

piplup@vika:~/dev/WebDesign/Scproci$ scons -Q
g++ -o two.os -c -fPIC two.cpp
g++ -o libtwo.so -shared two.os
g++ -o main.o -c -fPIC main.cpp
g++ -o main -Wl,--export-dynamic main.o -ldl
piplup@vika:~/dev/WebDesign/Scproci$ ./main
In main -> 0
In main -> 0
2
given that you are only showing code for the second method, its behaving as expected, based on what is shown.diverscuba23
Why doesn't it display "In two -> 0" ?Loïc Faure-Lacroix
Undefined symbol would happen since S::shared is defined in main.cpp, but when linking libtwo.so, you didn't include main.o where it was defined.Flame
You fail to create a functions called _init and _fini (old way) or a function exported __attribute__((constructor)) and __attribute__((destructor)) (new way). The _init is called when the library is loaded, _fini just before it is unloaded.diverscuba23
@Flame: No, when the library is loaded it will resolve the S::shared with the main executable the first time it is referenced (RTLD_LAZY). Unfortunately when a library is loaded unless it explicitly has initialization code supplied, it does not do any initialization, other than static initialization that can be done at compile time (i.e. simple variable assignment of PODs).diverscuba23

2 Answers

1
votes
#include "main.hpp" 
#include <iostream>  

class MyObject {     
    public:     
        MyObject(){         
            std::cout << "In two -> " << S::shared  << "\n";     
        } 
};  

MyObject* t;

__attribute__((constructor))
void init_two()
{
    t = new MyObject();
}

__attribute__((destructor))
void uninit_two()
{
    delete t;
}

This should produce what is expected. Pointers are used as it is easier to deal with them explicitly in shared objects as regular initialization doesn't happen automatically. If you don't want to use the pointers provide an explicit initialization for your class and call it in the shared library initialzation function.

* EDIT *

I did some additional experimentation and it appears that if you are using the default constructor, use it implicitly and it will be called, if you are using a non-default constructor then as normal.

so you could change your:

MyObject t();

call to:

MyObject t;

and it wil work without the explicit initialization functions being defined.

or

class MyObject {
public:
   MyObject() { /* as before */ };
   MyObject(int val)
   {
        S::shared = val;
        std::cout << "In two -> " << S::shared << "\n";
   }
};

MyObject t(10);

It appears that the compiler gets confused as to whether the MyObject t(); is a variable declaration, or a function declaration at the global scope and treats it as a function declaration.

0
votes

The problem that immediately jumps at me is that you have to separate link units. A static class member is just a global wrapped up in the namespace of that class.

Now, if you have two link units, say you main program and shared object, it is quite possible for both of them to have a global foo, and they would be distinct values.

Also, why the static initialization of t in two.cpp is not run in a shared object is not clear, its probably not guaranteed to happen before some type of main function in the shared object.