2013-02-27 14 views
8

Próbuję uzyskać podklasę z biblioteki współdzielonej, która została skompilowana z opcją -fno-rtti. Niestety inne biblioteki w mojej bazie kodu wymagają -frtti. W rezultacie otrzymuję błędy łącza, ponieważ nadklasa nie ma struktury typuinfo.Klasa podklas z biblioteki współużytkowanej skompilowanej za pomocą -fno-rtti

Błąd otrzymał w normalnej kompilacji:

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

Klasa chcę podklasy jest androidem klasa w libsysutils (ucięte trochę na przestrzeni):

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

Moja stub wygląda następująco:

class MyClass: public NetlinkListener { 

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

    int start(); 
    int stop(); 

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

Wszystkie metody w MyClass są zaimplementowane (jako puste kody)

Nie mogę skompilować udostępnionej biblioteki -frtti. Czy istnieje sposób obejścia tego?

+0

Czy możesz podać przykładowy kod opisujący sposób, w jaki próbujesz dokonać podklasy nadklasy? – Tuxdude

+0

@Tuxdude Dodano nagłówki. Nie ma implementacji podklasy (tylko stubs). Kod dla super klasy to ASOP typu open source. –

Odpowiedz

4

1) W prostych przypadkach można po prostu utworzyć wrapper C interfejsu (zbudowany bez RTTI). Następnie możesz użyć interfejsu C w programach obsługujących RTTI, pod warunkiem, że traktujesz je jako abstrakcyjne typy C z twojego programu obsługującego RTTI.

2) Kompilowanie biblioteki z RTTI jest dokładnie tym, co powinno wykonać (lub na żądanie dostawcy), chyba że istnieje bardzo dobry powód, aby wyłączyć RTTI (np. Pracujesz w domenie, w której wyjątki nie powinny być używane, takie jak jądro, sterowniki lub jakaś inna strefa wyjątkowa - lub gdzie pamięć jest ciasna).

3) Zmień bibliotekę tak, aby nie używała funkcji dynamic_cast, wyjątków, operatora typu, lub cokolwiek innego, co powoduje problem i odbudowuje go przy wyłączonym RTTI. Podobnie jak 1, możesz uczynić to oddzielną biblioteką abstrakcji, w zależności od organizacji programu.

4a) Następną opcją jest nigdy nie odwoływać się do informacji o typie obiektu (np. Nie dynamic_cast ani nie wyrzucać go) - a to może być uciążliwe. Spowoduje to usunięcie błędów linkerów w informacjach o typie referencyjnym.

4b) Najłatwiej jest stworzyć wewnętrzną klasę (przypuśćmy, że istnieją metody, które musisz przesłonić, i są typy, które musisz połączyć z programami zależnymi od rtti). Możesz utworzyć typ (inner), który dziedziczy po typie swojej biblioteki i wykonuje niezbędne przesłonięcia, ale następnie wywołuje zwrotnie przez inną hierarchię klas (druga hierarchia może dowolnie używać rtti). Teraz wirtualne eksporty klasy inner są umieszczane w jednostce tłumaczeniowej z rtti wyłączonym (ponieważ inaczej niejawnie odwołają się do informacji o typie klasy podstawowej). Następnie możesz łatwo poddać kwarantannie zależność od informacji o typie i zbudować hierarchię, która używa rzeczy takich jak wyjątki - ta hierarchia używa tego typu jako wartości. Oczywiście, , jeśli działa to, to cała implementacja zdefiniowana - trzeba zrozumieć, w jaki sposób RTTI i vtables są skonstruowane dla twoich docelowych platform (patrz dane ABI). Nawet pominięcie RTTI jest odchyleniem od standardowego C++. Nie ma informacji, które stwierdzałyby, że obecność symbolu spowoduje prawidłową konstrukcję twoich vtables i wpisanie informacji o bazie, która została skompilowana bez tych cech.

Powiedziałeś, że 1 i 2 są twoimi bezpiecznymi opcjami, 3 jest domeną rozszerzenia platformy bez sejfu (bezpieczne), a 4 jest podejściem, które może działać na nie lub tylko na niektórych systemach.

Ilustrowanie 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. 
}; 
+0

Zajrzałem do rozwiązania 1, ale problem polega na tym, że istnieje metoda "wirtualny void onEvent (...)', którą moja podklasa musi przesłonić, i zostanie wywołana przez metodę zdefiniowaną przez nadklasę (onDataAvailable). Jak mogę napisać opakowanie, ale uda się odzyskać to połączenie? –

+0

Twoje rozwiązanie 4b wydaje się radzić sobie z tą sytuacją. Czy możesz podać mi kodeks, jak dokładnie ustawić taki rodzaj spadku? –

+0

@JonL w prawo - musisz nadal mieć podklasę za interfejsem C, a następnie po prostu utworzyć podstawowy interfejs wywołania zwrotnego. podstawową formą oddzwaniania do klienta jest 'typedef void (* t_netlink_event_callback) (void * pContextInfo, NetlinkEvent * pEvent);' - a więc wywołanie wskaźnika funkcji C klienta w override, przy użyciu informacji kontekstowych, które minęły . ill.code: – justin

0

Przechodząc -fno-rtti wyłącza tylko funkcjonalność dynamic_cast i typeid jak na dokumentacji GCC. Powinieneś być w stanie wyprowadzać klasy i używać wirtualnych metod bez żadnych problemów.

Błąd undefined reference to typeinfo for class zwykle pojawia się, jeśli deklarujesz funkcję jako virtual, nie podając jej definicji.

W rzeczywistości widzę NetlinkHandler.h i NetlinkHandler.cpp w AOSP dokładnie to, co próbujesz zrobić i nie znajduję żadnej różnicy między tymi plikami a opublikowanymi fragmentami kodu.

+0

Mój kod musi się kompilować za pomocą '-frtti' z powodu innej biblioteki, która potrzebuje funkcji' dynamic_cast'. AOSP NetlinkHandler in vold (libvold) kompiluje '-fno-rtti', który pasuje do libsysutils, więc nie ma tego problemu. –

Powiązane problemy