From owner-freebsd-hackers Tue Feb 4 19:55:32 1997 Return-Path: Received: (from root@localhost) by freefall.freebsd.org (8.8.5/8.8.5) id TAA27497 for hackers-outgoing; Tue, 4 Feb 1997 19:55:32 -0800 (PST) Received: from paris.CS.Berkeley.EDU (paris.CS.Berkeley.EDU [128.32.34.47]) by freefall.freebsd.org (8.8.5/8.8.5) with ESMTP id TAA27478 for ; Tue, 4 Feb 1997 19:55:28 -0800 (PST) Received: (from jmacd@localhost) by paris.CS.Berkeley.EDU (8.8.3/8.8.2) id TAA11238; Tue, 4 Feb 1997 19:55:18 -0800 (PST) Date: Tue, 4 Feb 1997 19:55:18 -0800 (PST) From: Josh MacDonald Message-Id: <199702050355.TAA11238@paris.CS.Berkeley.EDU> To: hackers@freebsd.org, terry@lamber.org, terry@lambert.org Subject: Re: g++, STL and -frepo on FreeBSD-2.2-Beta Sender: owner-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk 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 template class Foo { public: Foo(T i) { printf ("%d\n", i); } virtual void foo(); }; in file foo.cc: #include "foo.h" template void Foo::foo() { } template class Foo; template class Foo; in file bar.cc: #include "foo.h" void main() { Foo a(9); Foo 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::Foo(int) 00000000 T _main 00000000 t gcc2_compiled. That seems to be missing a symbol, is something broken? Where'd Foo::Foo(char) go? It gets called when I run it. axis-~ $ nm foo.o | c++filt 00000078 T Foo::operator=(Foo const &) 000000b8 T Foo::operator=(Foo const &) 00000000 t ___gnu_compiled_cplusplus 0000009c T Foo::Foo(Foo const &) 00000030 T Foo::Foo(char) 000000dc T Foo::Foo(Foo const &) 00000004 T Foo::Foo(int) 000000f8 T Foo virtual table 00000108 T Foo virtual table 00000068 T Foo::foo(void) 00000070 T Foo::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