Shared Object Question

Hello,

I am new to programming shared objects and I was hoping someone could tell me if what I want to do is possible, or else lead me in the right direction.

I have a main program that contains an abstract base class. I also have a subclass that I'm compiling as a shared object. The subclass includes headers that are in the main project, but the definitions are not included. When I dynamically load the subclass, it is has unresolved dependencies from those headers it included.

Is there a way to resolve those dependencies when I load the shared object into my main program (which has the definitions)?

Not sure if it's relevant, but I am using Qt to load the shared object.

Thanks,

  • Derek

Link in those dependencies when you create the library.

Oh I see. Is it a problem that the definitions will be in both?

Not from what I've seen.

Thanks, it works like you said Corona668. However, there is one problem. One of the classes that is included in the project and the shared object had a static member and it seems that both have their own copy...

---------- Post updated at 01:25 AM ---------- Previous update was at 12:04 AM ----------

Ok so I found out from a site (can't post the URL because I don't have 5 posts...) that the shared object could have unresolved symbols that will be resolved when linked with my main application. You can do this if you compile your main application with -Wl,-export-dynamic to export the symbols.

However, I am still getting unresolved symbols after loading the library...

That's weird. Perhaps your header is actually defining some things in the class, not just declaring them?

Nope, just a class declaration. When I had it working by including the definitions in the project and the library, I set the static variable in the project and didn't set it in the library. The former had an an address and the latter was NULL.

Instead of including the definitions in both, I'd like to try the other approach I mentioned (exporting dynamic symbols in the project). This time, however, the library isn't even loading because of unresolved definitions. I used nm on the main executable and the unresolved symbols (from the library) mentioned in the error message are in there.

I really don't think you can make one member of a class be exported from the code into the library, and the rest exported from the library to the code. The whole thing gets instantiated as one 'thing'.

It might work if you make it a global variable instead of a member, but you'll have to do it backwards from the rest of the library: In the shared library, it'll be an extern "C" whatever *variable; and in your library-using code it's extern "C" { whatever *variable=stuff; } That'd definitely work with static linking. Dynamic I'm less sure: It might demand that the variable actually exists to be able to create the shared library.

That exports your code's symbols. Not the universe.

You might just have to add a call to set the static member.

1 Like

Yep, that's why I want to take the base class cpp file (which has the static menber) out of the library since it's also in the main app.

Here's how it's set up: In the project I have a base class header and cpp. In the library I have a subclass header and cpp. The library also includes the base class header. It doesn't have the base class definition, which I want to be resolved when the library is loaded in.

Earlier, I was adding in the base class cpp to the library (plus whatever else it needed). But I did some research and it seems I don't need to include all those definitions in both. As one site puts it:

(Sorry, I have to mangle this url because I'm not allowed to post links yet)

www
.informit.
com/articles
/article.aspx?p=22435&rll=1:

Since I took unnecessary definitions outside of the library the library hasn't even been loading. If I can get it to load, I am hoping that static member won't be duplicated.

Edit: Just to make sure we're using the same terms: by definition I mean cpp and by declaration I mean header.

They would seem to be necessary, then. Remember that exporting dynamic symbols from your project exports your symbols, not the entire universe...

Also make sure your library isn't last in the link order, the stuff you want it to link to should come after it. I'm not sure that'll help, but sometimes that matters for static linking...

I don't think it works that way for the reasons I stated above.

The compiler doesn't know any difference between header files and source files. What matters is what you put in them. So it's entirely possible for the wrong kind of declaration in a header file to create many conflicting symbols when included in several files.

I don't suppose you could reduce this to a minimal example?

Sure, I'll try to post a sample by tomorrow.

The library is being loaded at runtime using dlopen().

I really think you're going to have to link in the libraries you need when you create the library, then.

Hi Corona688,

I made a simple example and it works. When you create a library, you do not need definitions that are also in the main app since they can be resolved when the object is loaded.

Main App: BaseClass.h, BaseClass.cpp, OtherClass.h, OtherClass.cpp, main.cpp
Shared Library: ChildClass.h, ChildClass.cpp, BaseClass.h, OtherClass.h

Note: I included OtherClass to show that the definition did not need to exist in the shared library.

BaseClass.h

#ifndef BASE_CLASS_H
#define BASE_CLASS_H

#include <string>
#include "OtherClass.h"

using std::string;

class BaseClass
{
public:
    static int val;

    BaseClass();
    virtual ~BaseClass(); 
    
    virtual string getString() = 0;

private:
    
};

#endif

BaseClass.cpp

#include "BaseClass.h"

int BaseClass::val = 5;

BaseClass::BaseClass()
{
}

BaseClass::~BaseClass()
{
}

ChildClass.h

#ifndef CHILD_CLASS_H
#define CHILD_CLASS_H

#include "BaseClass.h"

class ChildClass : public BaseClass
{
public:
    ChildClass();

    string getString();
};

extern "C" BaseClass * create();

#endif

ChildClass.cpp

#include "ChildClass.h"

ChildClass::ChildClass(): BaseClass()
{
    OtherClass oc(4);
    oc.getValue();
}

string ChildClass::getString()
{
    return "child class";
}

BaseClass * create()
{
    return new ChildClass();
}

OtherClass.h

#ifndef OTHER_CLASS_H
#define OTHER_CLASS_H

class OtherClass
{
public:
    OtherClass(int value);
    int getValue();

private:
    int value;
};

#endif

OtherClass.cpp

#include "OtherClass.h"

OtherClass::OtherClass(int value)
{
    this->value = value;
}

int OtherClass::getValue()
{
    return value;
}

main.cpp

#include "BaseClass.h"

#include <iostream>
#include <dlfcn.h>

using std::cout;
using std::endl;

int main()
{
    typedef BaseClass * (*CreateFunc)();

    void *handle = dlopen("./libsltest.so.1.0", RTLD_NOW);
    if (handle)
    {
        cout << "loaded library" << endl;
        CreateFunc cf = (CreateFunc)dlsym(handle, "create");
        
        if (cf)
        {
            cout << "loaded create function" << endl;
            BaseClass *b = cf();
            cout << b->getString() << endl;
            dlclose(handle);

            cout << BaseClass::val << endl;
            cout << b->val << endl;
        }
        else
        {
            cout << "could not load create function" << endl;
        }
    }
    else
    {
        cout << "could not load library" << endl;
    }
    
    return 0;
}

The static values are the same, as expected.

In the project where I'm getting unresolved errors, I'm using Qt to make the shared library. The problem could be there. I'll post again if I have any leads.

Thanks for your help,
-- Derek

I'm not sure what this code is supposed to prove, since it's not doing anything remotely like what you've described your actual project trying to do.

You can export your own symbols into the library. You can't export something else's symbols. How can you possibly export something you never have? These dependencies remain unresolved up until runtime!

You do seem to be able to have a library import your definition of a static member, much to my surprise. So if it's complaining about being doubly defined, that's because it is. Take the extra definition out of your library.