Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subclassing class from shared library compiled with -fno-rtti

Tags:

c++

subclass

rtti

I am trying to subclass from a shared library which was compiled with -fno-rtti. Unfortunately other libraries in my code base require -frtti. As a result I am getting link errors because the superclass does not have a typeinfo struct.

Error received in a normal compilation:

out.o: in function typeinfo for MyClass:myclass.cpp(.data.rel.ro.<cpp magic>): error: undefined reference to 'typeinfo for NetlinkListener'

The class I want to subclass is an android class in libsysutils (snipped a little for space):

class NetlinkListener : public SocketListener {
    char mBuffer[64 * 1024];
    int mFormat;

public:
    static const int NETLINK_FORMAT_ASCII = 0;
    static const int NETLINK_FORMAT_BINARY = 1;

    NetlinkListener(int socket);
    NetlinkListener(int socket, int format);
    virtual ~NetlinkListener() {}

protected:
    virtual bool onDataAvailable(SocketClient *cli);
    virtual void onEvent(NetlinkEvent *evt) = 0;
};

My stub looks like:

class MyClass: public NetlinkListener {

public:
    MyClass();
    virtual ~MyClass();

    int start();
    int stop();

protected:
    virtual void onEvent(NetlinkEvent *evt);
};

All the methods in MyClass are implemented (as empty stubs)

I cannot compile the shared library -frtti. Is there any way to work around this?

like image 755
Jon L Avatar asked Feb 27 '13 00:02

Jon L


People also ask

What is .so file in C++?

The SO file stands for Shared Library. You compile all C++ code into the.SO file when you write it in C or C++. The SO file is a shared object library that may be dynamically loaded during Android runtime. Library files are larger, often ranging from 2MB to 10MB in size.

What is a shared library C++?

A shared library is an object module that can be loaded at run time at an arbitrary memory address, and it can be linked to by a program in memory. Shared libraries often are called as shared objects. On most UNIX systems they are denoted with a . so suffix and Microsoft refer to them as DLLs (dynamic link libraries).

How are shared libraries loaded in Linux?

Shared libraries are the most common way to manage dependencies on Linux systems. These shared resources are loaded into memory before the application starts, and when several processes require the same library, it will be loaded only once on the system. This feature saves on memory usage by the application.

How does shared library work?

Simply put, A shared library/ Dynamic Library is a library that is loaded dynamically at runtime for each application that requires it. Dynamic Linking doesn't require the code to be copied, it is done by just placing name of the library in the binary file.


1 Answers

1) For simple cases, you could just create a C wrapper of the interface (built with no RTTI). Then you can use the C interface in RTTI enabled programs, provided you treat them as abstract C types from your RTTI enabled program.

2) Compiling the library with RTTI is exactly what you should do (or request of the vendor), unless there is a very good reason for RTTI to be disabled (e.g. you're working in a domain where exceptions should not be used, such as a kernel, drivers, or some other no exception zone -- or where memory is tight).

3) Alter your library to not use dynamic_cast, exceptions, typeid operator, or whatever it is that causes the issue and rebuild with RTTI disabled. Similar to 1, you can make this a separate abstraction library, depending on how the program is organized.

4a) The next option is to never reference the type info for the object (e.g. do not dynamic_cast or throw it) -- and this can be a pain. That will remove linker errors of referenced type infos.

4b) It may be easiest to create an inner class (suppose there are methods you must override, and there are types you must interface with your rtti-dependent programs). You can create a type (inner) which inherits from their lib's type and performs the necessary overrides, but then calls back through some other class hierarchy (the other hierarchy is free to use rtti). Now the inner class' virtual exports are placed in a TU with rtti disabled (because it will otherwise implicitly reference its base class' type info). Then you can easily quarantine the type info dependence and build out a hierarchy which uses things like exceptions -- this hierarchy uses that inner type as a value. Of course, if that works, it's all implementation defined -- you would need to understand how RTTI and vtables are structured for your targeted platforms (see ABI refs). Even omission of RTTI is deviation from standard C++. There is no information that states that the presence of a symbol will result in proper construction of your vtables and type info of a base which was compiled without those features.

That said, 1 and 2 are your safe options, 3 is within the domain of the no-rtti platform extension (safe), and 4 is an approach which is free to work on no or only some systems.

Illustrating 4b

class MyClass // << cast me. throw/catch me. get my mangled name,
              //    but put my family's virtual exports in a TU with RTTI enabled
: public MyRTTIEnabledFamily {
public:
    MyClass() : d_inner(*this) {}
    virtual ~MyClass();
private:
    void cb_onEvent(NetlinkEvent * evt) {
        // no-rtti suggests exceptions may not be available,
        // so you should be careful if your program throws.
        someInfo = evt->getInfo();
    }
private:
    // non-rtti hierarchy
    class t_inner : public NetlinkListener {
    public:
        t_inner(MyClass& pMyClass) : NetlinkListener(), d_myClass(pMyClass) {
        }

        virtual ~t_inner(); // << put your virtual exports in a TU with RTTI disabled.
                            //    one out of line virtual definition is necessary for most compilers
    private:
        virtual void onEvent(NetlinkEvent * evt) {
            // how the callback to your imp actually happens
            this->d_myClass.cb_onEvent(evt);
        }
    private:
        MyClass& d_myClass;
    };
private:
    t_inner d_inner; // << don't do anything with my type info -- it does not exist.
};
like image 150
justin Avatar answered Nov 06 '22 00:11

justin