Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 4 Feb 1997 19:55:18 -0800 (PST)
From:      Josh MacDonald <jmacd@CS.Berkeley.EDU>
To:        hackers@freebsd.org, terry@lamber.org, terry@lambert.org
Subject:   Re: g++, STL and -frepo on FreeBSD-2.2-Beta 
Message-ID:  <199702050355.TAA11238@paris.CS.Berkeley.EDU>

next in thread | raw e-mail | index | archive | help

As far as I know, the following is true:

a) No one implements any of the fancy methods of template instanciation
you suggest.  I know little about ELF, but I've been fighting with g++
templates for over a year now on many different platforms and I've never
run into any mention of the optimization you suggest.  As to the god-like
optimization you suggest, I think its impractical even if they could 
implement it.  It would be a pretty big performance hit, for the most
part.  You don't want every function and/or operator call inside each
function to have to switch on the object type, which it potentially
would come down to, plus the fact that the size of the type in question
would not be known until run time leaves many compiler optimizations
invalid.  Since you'd still be duplicating code, I don't see its being
very useful anyway.

b) The way you suggest of telling the compiler not to generate templates
automatically works as follows (in g++):

Specify -fno-implicit-templates for all source files you compile.  In
the source module containing the template methods (or perhaps 
multiple source files if the template methods are spread out, though
I haven't tested this) you add a line _after_ all the template 
methods have been defined.  So, 

in file foo.h:

#include <stdio.h>
template<class T> 
class Foo 
{
public: 
   Foo<T>(T i) { printf ("%d\n", i); }
   virtual void foo();
};

in file foo.cc:

#include "foo.h"

template <class T> void Foo<T>::foo() { }

template class Foo<int>;
template class Foo<char>;

in file bar.cc:

#include "foo.h"
void main() { Foo<int> a(9); Foo<int> b('f'); }

Compiles with -fno-implicit-templates (or without) and links correctly.

c) Many compilers take the following course of action (The only two
I actually have experience with are Sun CC 4.2 and g++).  Generate
a file containing enough data to generate the template at link-time.
This is what the repo patches are for.  To my knowledge, it works
by modifying the collect2 phase of linking.  As we all know, it doesn't
work without ELFkit.

d) RTTI is not working very well in g++.

I'm fairly interested in seeing that FreeBSD stays a viable C++ development
platform.  I wonder if Chuck could better describe the problem with 
Octave?

Now concerning the virtual tables, I'm not sure I understand, when I
compile the two source files above with -fno-implicit-templates, I get:

axis-~ $ nm bar.o | c++filt
00000000 t ___gnu_compiled_cplusplus
         U ___main
         U Foo<int>::Foo(int)
00000000 T _main
00000000 t gcc2_compiled.

That seems to be missing a symbol, is something broken?  Where'd 
Foo<char>::Foo(char) go?  It gets called when I run it.

axis-~ $ nm foo.o | c++filt
00000078 T Foo<char>::operator=(Foo<char> const &)
000000b8 T Foo<int>::operator=(Foo<int> const &)
00000000 t ___gnu_compiled_cplusplus
0000009c T Foo<char>::Foo(Foo<char> const &)
00000030 T Foo<char>::Foo(char)
000000dc T Foo<int>::Foo(Foo<int> const &)
00000004 T Foo<int>::Foo(int)
000000f8 T Foo<char> virtual table
00000108 T Foo<int> virtual table
00000068 T Foo<char>::foo(void)
00000070 T Foo<int>::foo(void)
         U _printf
00000000 t gcc2_compiled.

As you can see, the virtual tables have extenral linkage and the
template methods for int and char were only generated once.

> Riddle me this: if the compiler makes a 't' reference to a real 'T'
> somewhere... how can it generate the real 'T'?  It can't just pick
> one of the files at random an put it there.  I might be compiling
> incrementally.

Often you choose the complication unit containing the first virtual
function, for example, to place the virtual table in, you can use the
ordering of the class methods/decls for this purpose.  If everything
is in the header file, you lose.  People have been pointing out
for years that the UNIX compile/link proceedure is inadequate for
C++ and templates, ever since cfront invented the template repository.
You can use a pragma as well, these are all documented in the GCC info
pages (as well as the fact that Boreland solved the problem with the 
ELF trick you suggest).

[Lots of code deleted]

> a.out:
> ---------
> Personally, I expect it to be generated static in *both* of them, with
> no global reference, in the a.out case.  Anything else is an error.  If
> you run a new g++ with the a.out ld for FreeBSD, it's pilot error.
> 
> Alternately, you could have a compiler flag that was applied to
> fee..  that said "don't generate code for templates" so it only
> made a reference, and you would *not* use that flag when compiling
> foo.cc so it would generate the real thing.  Then, when you linked,
> there would be one instance and multiple references.  If you used
> the flag on everone who actualized the template class by instantiating
> it, you wouldn't get a real instance of the code.  Again, you'd be
> guilty of pilot error.

The syntax I show above has made it into the C++ standard.  See 
section 14.7.2 in a recent draft.

> Godlike compiler writer magic:
> ---------
> If, on the other hand, they were truly *godlike*, they would provide
> a method of implementing a precompiled template instantiation, and
> generate one of those an an object file.  Inside, it would use RTTI
> (run time type identification) to decide what kind of object it was
> referring to, and the compiled template code would not enforce the
> object type.  The compiler would compile fee.cc and foo.cc, and
> *not* generate the code for the template.  But it would rigidly
> enforce *at compile time* type checking *as if it had*.  Then, when
> it generated any references for the "FifoQueue of int's" public
> member functions or data, it would generate them *without* the
> linker glue for link time type checking, and rely solely on the RTTI
> to enable the class to "do the right thing".

"do the right thing slowly".  There's still lots of problems you've
ignored like where to put the static template members (something
that's pretty difficult to accomplish in eveyr c++ compiler I've
used).  The chances of actually saving space this way are small,
the overhead of making one general purpose code section would be
large, I think.  I wouldn't call it godlike, maybe impressive software
engineering.

> I find this last one extremely unlikely.  But if they are doing it,
> then the symbols are right, I am wrong.  And it's still pilot error,
> since if ther pilot did the right thing, there would be: (1) an object
> module with the type-stripped class instance, (2) multiple object
> modules with refernces to the type stripped references, and (3) an
> RTTI interface, which I don't believe currently exists in a form
> suitable for use in doing this sort of thing by hacking up the compiler
> for the special case where it is compiling a template file to generate
> an object with type-non-specific 'this' and private member data
> references.

> If I'm wrong (the declaration didn't need to be in scope), then
> it's probably that they are incorrectly applying the "don't generate
> template" flag when they shouldn't be, not creating a template
> instance object seperate from the rest of their objects, like they
> should be, or relying on linker tricks which require multiple
> instantiations to be coalesced to a single instance, which the a.out
> linker is too stupid to do, and the ELF linker is probably currently
> too stupid to do, even though ELF could support it.

The original problem had to do with the repo patches, nothing to
do with scopes.  The repo patches don't work, that's the problem.
They *should* generate all the required template code and isnert
them into a REPOsitory at link-time, but they don't so symbols
were missing, not pilot error.

> Feel free to correct me, though... I'd rather know the right answer
> than just think I knew the right answer.  If there's another way for
> me to be wrong, let me know.
> 
> 
> 					Regards,
> 					Terry Lambert
> 					terry@lambert.org
> ---
> Any opinions in this posting are my own and not those of my present
> or previous employers.

-josh



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199702050355.TAA11238>