使用-fno-rtti编译的共享库中的子类

Subclassing class from shared library compiled with -fno-rtti

本文关键字:子类 共享 编译 使用 -fno-rtti      更新时间:2023-10-16

我正在尝试从使用-fno rtti编译的共享库中派生子类。不幸的是,我的代码库中的其他库需要-frtti。结果我得到了链接错误,因为超类没有typeinfo结构。

在正常编译中收到错误:

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

我想要子类化的类是libsysutils中的一个android类(为节省空间而略作删减(:

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;
};

我的存根看起来像:

class MyClass: public NetlinkListener {
public:
    MyClass();
    virtual ~MyClass();
    int start();
    int stop();
protected:
    virtual void onEvent(NetlinkEvent *evt);
};

MyClass中的所有方法都实现了(作为空存根(

我无法编译共享库-frtti。有什么办法解决这个问题吗?

1(对于简单的情况,您可以只创建接口的C包装器(不使用RTTI构建(。然后,您可以在支持RTTI的程序中使用C接口,前提是您将它们视为支持RTTI程序中的抽象C类型。

2( 使用RTTI编译库正是应该做的(或供应商的要求(,除非有充分的理由禁用RTTI(例如,您在不应该使用异常的域中工作,例如内核、驱动程序或其他无异常区域,或者内存紧张(。

3( 将库更改为不使用dynamic_cast、exceptions、typeid运算符或任何导致问题的运算符,并在禁用RTTI的情况下重新生成。与1类似,您可以将其作为一个单独的抽象库,这取决于程序的组织方式。

4a(下一个选项是永远不要引用对象的类型信息(例如,不要dynamic_cast或抛出它(——这可能会很痛苦。这将删除引用类型infos的链接器错误。

4b(创建内部类可能是最简单的(假设有一些方法必须重写,并且有一些类型必须与依赖rtti的程序接口(。您可以创建一个类型(inner(,该类型继承自其lib的类型并执行必要的重写,但随后通过某些其他类层次结构进行回调(其他层次结构可以自由使用rtti(。现在,inner类的虚拟导出被放置在禁用rtti的TU中(因为它将隐式引用其基类的类型信息(。然后,您可以很容易地隔离类型信息依赖性,并构建一个使用异常之类的东西的层次结构——该层次结构使用inner类型作为值。当然,如果有效,那么这都是实现定义的——您需要了解RTTI和vtables是如何为您的目标平台构建的(请参阅ABI参考文献(。即使省略RTTI也是对标准C++的偏离。没有任何信息表明,符号的存在将导致vtables的正确构建,以及在没有这些功能的情况下编译的基的类型信息。

也就是说,1和2是你的安全选项,3在无rtti平台扩展(安全(的范围内,4是一种可以在无系统或仅在某些系统上自由工作的方法。

说明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.
};

根据gcc的文档,传递-fno-rtti仅禁用dynamic_casttypeid功能。您应该能够在没有任何问题的情况下派生类和使用虚拟方法。

如果您将函数声明为virtual而没有为其提供定义,则通常会出现undefined reference to typeinfo for class错误

事实上,我看到AOSP中的NetlinkHandler.hNetlinkHandler.cpp正是在做你想要做的事情,我没有发现这些文件和你发布的代码片段之间有任何区别。