This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

typeid() headaches (library to main executable)


Hello all,

the problem described below is very similar to the one handled at [1].

However, that discussion doesn't fully explain why the typeid() mechanism
is handled by g++ the way it is, and both the gcc FAQ ([2]) and the
C++ specs at [3] don't really help either in my case.

I'm compiling a large MSVC/MFC (VS.NET 2003) based app using g++
(3.4.0 or 3.2.3).
One library of this app does a typeid() check on a class name (not a
class object) which is in the main executable:
if ((typeid(CTestClass) == (typeid(*pClass)) ...

This CTestClass is specified in a header file of the main executable which
this library includes, in other words the class itself does not exist in the
same binary object!

Doing such a typeid() query from a library on a class in the main executable
*works* under MSVC (for whatever reason...), but fails under g++ 3.4.0
(and 3.2.3), with

/usr/lib/gcc/i386-redhat-linux/3.4.0/../../../../include/c++/3.4.0/typeinfo:104: undefined reference to `typeinfo for CTestClass'

(I assumed the failure might have been due to "The new C++ ABI in the GCC 3.0
series uses address comparisons, rather than string compares, to determine
type equality. This leads to better performance.", but gcc 2.96 also shows
this typeinfo link error, so that doesn't seem to be the case)

If I remove all virtual methods from the class header file, the typeinfo gets
generated and typeid() works fine (since then it's a fully defined class
within the current compile unit, I assume, judging from explanations at
[expr.typeid]).
Removing all virtuals isn't a viable solution, however, so the next step was
to implement the first virtual method in the class header file instead of the
corresponding .cpp file in the main executable (as suggested by the discussion
at [1]).
This has to be done using inline, however, otherwise I will obviously get
redefinitions of this virtual method at several object files during linking
stage of my library.

Once I added the first virtual method, the typeinfo linking error vanished
and a bunch of further linking errors about all other virtual methods in this
class appeared.

And this is a killer, since this class also makes use of *system* macros
that define and implement (in the .cpp file!) virtual methods, in other words
I cannot move *all* virtual methods into the header (to satisfy the typeinfo
requirement).

Experimenting with various g++ and linker flags didn't help either.

Questions:

a) Why does using typeid() on a class with unspecified virtual methods work
   on MSVC and not on g++?
A: "because MSVC is crap since it doesn't follow current C++ specs in
several cases"? ;-)

b) What are the exact requirements for typeinfo generation of a class and why?
   Is there any difference between what C++ specs require and what g++
   actually implements? (g++ more strict??)

c) if this cannot be changed to be compatible with g++, are there any other
   ways to achieve a similar result? Any workarounds?

Environment: Red Hat RHEL3, x86

Thank you for any hints!

Andreas Mohr

Files of a sample for testing the typeid() behaviour (copy&pasted!):

** program.h **

class CBaseTestClass
{
};

class CTestClass : public CBaseTestClass
{
        void sometest();
        virtual void mytest();
        virtual void mytest2();
};

inline void CTestClass::mytest()
{
}

inline void CTestClass::mytest2()
{
}

** program.cpp **

#include <typeinfo>
#include <stdio.h>
#include "program.h"

void CTestClass::mytest()
{
}

int main(void)
{
        CBaseTestClass *pClass;
        if (typeid(*pClass) == typeid(CTestClass))
                printf("ok\n");
        return 0;
}

** libtest.cpp **

#include <typeinfo>
#include <stdio.h>
#include "program.h"

int mytest()
{
        CBaseTestClass *pClass;
        if (typeid(*pClass) == typeid(CTestClass))
        printf("ok\n");
        return 0;
}

** Makefile **

CC=g++

all: libtest.so program

libtest.o: libtest.cpp
        $(CC) $(CFLAGS) -g -pipe -Wall
 -Wno-missing-braces -Wno-parentheses -Wno-unused-value -Wno-non-virtual-dtor -
fPIC -fexceptions -fms-extensions -D "_AFXDLL"  -g -c -o $@ -c $<

libtest.so: libtest.o
        $(CC) $(CFLAGS) -shared -fPIC -Wl,--no-undefined -Wl,-soname,libtest.so
 -o libtest.so -pthread libtest.o

program:
        $(CC) $(CFLAGS) -o program program.cpp

clean:
        rm *.o *.so

[1] http://gcc.gnu.org/ml/gcc-help/2005-04/msg00218.html
[2] http://gcc.gnu.org/faq.html#dso
[3] http://www.open-std.org/jtc1/sc22/open/n2356/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]