Subject: Re: B20: make confused with //a style drive specifiers
From: Graham Dumpleton <[email-masked]>
To: [email-masked] (Mumit Khan)
Cc: [email-masked], [email-masked]
Date: Tue, 16 Feb 1999 13:47:19 +1100 (EST)

> Hi Graham,
 > 
 > Could you possibly put together a test case so I can try and get a fix in
 > before egcs-1.1.2 is released? What you see sounds like a bug in emitting
 > .linkonce directive (somewhat like "weak" symbols in ELF, but done at the
 > section level instead of symbol level) for certain inlines.
 > 
 > In the meantime, I'll download the latest release and try it out.
 > 
 > Regards,
 > Mumit

Worked out a way of duplicating the problem with a small example. This code
compiles and links fine with Cygnus GNUPRO C++ 98r1 on Solaris 2.5.1. What
I am doing here has also worked when I have built OSE on Linux RH5.2, which
I think was using EGCS.

There are a couple of strange things to note about how I handle templates.
The first is that template implementations would never usually be seen
when compiling non main object file. Further, for a template which is
totally inline as is the case here, the #pragma interface/implementation
are only used when builing main object file. That is, for any non main
object file, inlines of template if they are expanded should only have
local/weak scope. When building main object, template is implemented with
extern linkage. Normally, this should override weak linkage in non main
object files, but this isn't what is happening here, as non main object
symbols are not local/weak.

<<<< h1.hh >>>>

  #if defined(EXPAND_TEMPLATES)
  #pragma implementation "h1.hh"
  #pragma interface "h1.hh"
  #endif

  template<class T>
  class ONE
  {
    public:
      ONE(void* anIter) { anIter = 0; }
  };

<<<< o1.cc >>>>

  #include "h1.hh"

  void func1()
  {
    ONE<int> iter((void*)0);
  }

<<<< m1.cc >>>>

  #define EXPAND_TEMPLATES 1

  #include "h1.hh"

  main()
  {
    ONE<int> iter((void*)0);

    return 0;
  }

Commands to run ar:

  g++ -c o1.cc
  g++ -c -fexternal-templates m1.cc
  g++ m1.o o1.o

Actual log of this is as follows. Note that when building OSE, you don't
usually see the pragma warning. I have never been able to work out what it
is about how I do this in OSE that results in the compiler not generating
the warning even though I am doing the exact same thing.

bash-2.02$ g++ -c o1.cc
bash-2.02$ g++ -c -fexternal-templates m1.cc
In file included from m1.cc:3:
h1.hh:2: warning: `#pragma implementation' for "h1.hh" appears after its #include
bash-2.2$ g++ m1.o o1.o
o1.o(.text$__t3ONE1ZiPv+0x0):o1.cc: multiple definition of `ONE<int>::ONE(void *)'
m1.o(.text+0x0):m1.cc: first defined here
collect2: ld returned 1 exit status

Note that doing an nm on o1.o reveals:

  bash-2.02$ nm o1.o | c++filt
  00000000 b .bss
  00000000 d .data
  00000000 t .text
  00000000 t .ONE<int>::text$(void *)
  00000000 t ___gnu_compiled_cplusplus
  00000000 T ONE<int>::_(void *)
  00000000 T _func1(void)
  00000000 t gcc2_compiled.

Ie., "ONE<int>::_(void *)" has "T" and not "t". I am presuming that "t"
means local/weak.

An nm on m1.o produces:

  bash-2.02$ nm m1.o | c++filt
  00000000 b .bss
  00000000 d .data
  00000000 t .text
  00000000 t ___gnu_compiled_cplusplus
	   U ___main
  00000000 T ONE<int>::_(void *)
  00000014 T _main
  00000000 t gcc2_compiled.

If you need to know more, let me know.

-- 
Graham Dumpleton ([email-masked])