This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
Template instanciantion problem on Red-Hat 6.2 & 6.1
- To: gcc-bugs at gcc dot gnu dot org
- Subject: Template instanciantion problem on Red-Hat 6.2 & 6.1
- From: Philippe Nobili <pnobili at cgg dot com>
- Date: Thu, 03 Aug 2000 16:01:34 +0200
- CC: "nobili, philippe" <pnobili at group dot cgg dot com>, "thomas, dominique" <dthomas at cgg dot com>
- Organization: CGG
Hello,
gcc-2.95.2 (release, october 1999), seems to have problems
to correctly instanciate templates on Red-Hat 6.1/6.2 even on
very simple examples.
Attached
---------
WorkSession.[Ch]
WSHistLog.h
List.[Ch] template class
WorkSession.rpo ==> repository file produced on red-hat 6.2
WorkSession.rpo.sol7 ==> repository file produced on solaris7
OS (uname -a):
---------
Linux [hostname] 2.2.14-24mdk_i486 #1 Sun Feb 13 21:52:19 CET 2000 i686
unknown
AND
Linux [hostname] 2.2.14-6.1.1 #1 Thu Apr 13 20:01:58 EDT 2000 i686
unknown
GCC (gcc -v)
-------------
Reading specs from
/u/nobili/linux/lib/gcc-lib/i686-pc-linux-gnu/2.95.2/specs
gcc version 2.95.2 19991024 (release)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
How to reproduce:
-----------------
a) gcc -c -frepo WorkSession.C
============================
Generates WorkSession.o and WorkSession.rpo
Output: none
b) gcc WorkSession.o
==========
Makes the necessary template instanciations, recompiling
WorkSession.C if needed and places instanciations in
WorkSession.o
Ouput: (NOT OK)
======
collect: recompiling WorkSession.C
collect: relinking
/usr/lib/crt1.o(.text+0x18): undefined reference to `main'
WorkSession.o: In function `GmList<GmWorkSessionHistoryLog
*>::~GmList(void)':
WorkSession.o(.text+0xfb): undefined reference to
`GmList<GmWorkSessionHistoryLog *>::clear(void)'
collect2: ld returned 1 exit status
The compiler failed to instanciate
-----------------------------------
'GmList<GmWorkSessionHistoryLog *>::clear(void)'
=====================================================================
Hint: comparing with what happend on solaris 7
====================================================================
If I compare the repository file obtained on Linux (WorkSession.rpo)
with that obtained on Solaris-7 (WorkSession.rpo.sol7), the two
following lines differ :
> diff WorkSession.rpo WorkSession.rpo.sol7
Produces:
5c5,6
< O clear__t6GmList1ZP23GmWorkSessionHistoryLog
---
> O _._t10GmListNode1ZP23GmWorkSessionHistoryLog
> C clear__t6GmList1ZP23GmWorkSessionHistoryLog
The line '_._t10GmListNode1ZP23GmWorkSessionHistoryLog' is not
present on Linux, whereas the line
'clear__t6GmList1ZP23GmWorkSessionHistoryLog' is flagged
'O' instead of 'C'
OS (uname -a):
-------------------
SunOS [hostname] 5.7 Generic_106541-09 sun4u sparc SUNW,Ultra-80
GCC (gcc -v):
-------------
Reading specs from
/usr/local/lib/gcc-lib/sparc-sun-solaris2.7/2.95.2/specs
gcc version 2.95.2 19991024 (release)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Results on Solaris 7 :
=======================================
a) gcc -c -frepo WorkSession.C
b) gcc WorkSession.o
Ouput: (OK)
collect: recompiling WorkSession.C
collect: relinking
collect: recompiling WorkSession.C
collect: relinking
Undefined first referenced
symbol in file
main
/usr/local/lib/gcc-lib/sparc-sun-solaris2.7/2.95.2/crt1.o
ld: fatal: Symbol referencing errors. No output written to a.out
collect2: ld returned 1 exit status
All templates are correctly instanciated
-----------------------------------------
Thank you for your help,
Cheers,
P. Nobili
--
___________________________________________________________
Philippe Nobili
CGG
Office M1 335
1, rue Leon Migaux, 91341 Massy Cedex
Tel : 01 64 47 40 90
Fax : 01 64 47 45 14 E-mail : pnobili@cgg.com
___________________________________________________________
#ifndef List_C
#define List_C
#include "List.h"
#include <stdlib.h>
#include <iostream.h>
// List's nodes...
////////////////////////////////////////////////////////////////////////////////
template <class T>
class GmListNode
{
public :
GmListNode<T>* tl ;
T hd ;
GmListNode() {}
~GmListNode() {}
GmListNode( const T& h, GmListNode<T>* t = 0) : hd(h), tl(t) {}
#ifdef POOL // voir fin du fichier
void * operator new( size_t ) { return pool_.alloc() ; }
void operator delete( void * p ) { pool_.free( p ) ; }
private :
static <T>Pool pool_ ;
#endif // POOL
} ;
// GmList
////////////////////////////////////////////////////////////////////////////////
#ifdef POOL // voir fin du fichier
<T>Pool <T>GmListNode::pool_( sizeof(<T>GmListNode) ) ;
#endif // POOL
template <class T>
GmList<T>::GmList()
{
P = 0 ;
}
template <class T>
GmList<T>::GmList( const GmList<T>& a )
{
if( a.P == 0 )
{
P = 0 ;
return ;
}
GmListNode<T> * p = a.P->tl ;
GmListNode<T> * h = new GmListNode<T>( p->hd ) ;
P = h ;
for( ;; )
{
if( p == a.P )
{
P->tl = h ;
return ;
}
p = p->tl ;
GmListNode<T> * n = new GmListNode<T>( p->hd ) ;
P->tl = n ;
P = n ;
}
}
template <class T>
GmList<T>::~GmList()
{
clear() ;
}
template <class T>
GmList<T>& GmList<T>::operator = ( const GmList<T>& a )
{
if( P == a.P ) return *this ;
clear() ;
if( a.P == 0 ) return *this ;
GmListNode<T> * p = a.P->tl ;
GmListNode<T> * h = new GmListNode<T>( p->hd ) ;
P = h ;
for( ;; )
{
if( p == a.P )
{
P->tl = h ;
break ;
}
p = p->tl ;
GmListNode<T> * n = new GmListNode<T>( p->hd ) ;
P->tl = n ;
P = n ;
}
return *this ;
}
template <class T>
void GmList<T>::append( GmList<T>& b )
{
GmListNode<T> * t = b.P ;
// destructif : la liste b est dorenavant vide.
b.P = 0 ;
if( P == 0 )
{
P = t ;
}
else if( t != 0 )
{
GmListNode<T> * f = P->tl ;
P->tl = t->tl ;
t->tl = f ;
P = t ;
}
}
template <class T>
void GmList<T>::prepend( GmList<T>& b )
{
GmListNode<T> * t = b.P ;
// destructif : la liste b est dorenavant vide.
b.P = 0 ;
if( P == 0 )
{
P = t ;
}
else if( t != 0 )
{
GmListNode<T> * f = P->tl ;
P->tl = t->tl ;
t->tl = f ;
}
}
template <class T>
GmBoolean GmList<T>::isEmpty() const
{
return P == 0 ? GmTRUE : GmFALSE ;
}
template <class T>
int GmList<T>::count() const
{
int sum = 0 ;
GmListNode<T> * n = P ;
if( n )
{
do
{
n = n->tl ;
sum++ ;
} while( n != P ) ;
}
return sum ;
}
template <class T>
void GmList<T>::clear()
{
if( P == 0 ) return ;
GmListNode<T> * p = P->tl ;
P->tl = 0 ;
P = 0 ;
while( p != 0 )
{
GmListNode<T> * nxt = p->tl ;
delete p ;
p = nxt ;
}
}
template <class T>
GmAny GmList<T>::append( const T& item )
{
GmListNode<T> * t = new GmListNode<T>(item) ;
if( P == 0 )
{
t->tl = P = t ;
}
else
{
t->tl = P->tl ;
P->tl = t ;
P = t ;
}
return GmAny(t) ;
}
template <class T>
GmAny GmList<T>::prepend( const T& item )
{
GmListNode<T> * t = new GmListNode<T>(item) ;
if( P == 0 )
{
t->tl = P = t ;
}
else
{
t->tl = P->tl ;
P->tl = t ;
}
return GmAny(t) ;
}
template <class T>
GmAny GmList<T>::first() const
{
return !P ? 0 : GmAny( P->tl ) ;
}
template <class T>
GmAny GmList<T>::seek( const T& item ) const
{
if( P == 0 )
{
return GmAny( 0 ) ; // empty list
}
GmListNode<T> * t = P->tl ; // first
do
{
if( t->hd == item ) break ; // found
t = t->tl ;
} while( t != P ) ;
if( t->hd != item ) return GmAny( 0 ) ; // not found
return GmAny( t ) ;
}
template <class T>
GmAny GmList<T>::seek( unsigned int pos ) const
{
if( P == 0 )
{
return GmAny( 0 ) ; // empty list
}
int l = 0 ;
GmListNode<T> * t = P->tl ;
do
{
if( l == pos )
{
return GmAny( t ) ;
}
t = t->tl ;
l++ ;
} while( t != P->tl ) ;
return GmAny( 0 ) ;
}
template <class T>
void GmList<T>::next( GmAny& p ) const
{
p = (p==0 || p==P) ? 0 : GmAny( ((GmListNode<T>*)p)->tl ) ;
}
template <class T>
T& GmList<T>::operator () ( GmAny p ) const
{
if( !p )
{
GmFatalError( "T& GmList<T>::operator () ( GmAny p )",
"Null iterator p" ) ;
}
return ((GmListNode<T>*)p)->hd ;
}
template <class T>
T GmList<T>::pop()
{
if( P == 0 )
{
GmFatalError( "T GmList<T>::pop()", "Empty list" ) ;
}
GmListNode<T> * t = P->tl ;
T res = t->hd ;
if( t == P )
{
P = 0 ;
}
else
{
P->tl = t->tl ;
}
delete t ;
return res ;
}
template <class T>
GmBoolean GmList<T>::owns( GmAny p ) const
{
GmListNode<T> * t = P ;
if( t != 0 && p != 0 )
{
do
{
if( GmAny(t) == p ) return GmTRUE ;
t = t->tl ;
} while( t != P ) ;
}
return GmFALSE ;
}
template <class T>
GmBoolean GmList<T>::owns( const T& item ) const
{
GmListNode<T>* t = P ;
if( t == 0 )
{
return GmFALSE ;
}
do
{
if( t->hd == item )
{
return GmTRUE ;
}
t = t->tl ;
} while( t != P ) ;
return GmFALSE ;
}
template <class T>
T& GmList<T>::head() const
{
if( P == 0 )
{
GmFatalError( "T& GmList<T>::head()", "Empty list" ) ;
}
return P->tl->hd ;
}
template <class T>
T& GmList<T>::tail() const
{
if( P == 0 )
{
GmFatalError( "T& GmList<T>::tail()", "Empty list" ) ;
}
return P->hd ;
}
template <class T>
GmAny GmList<T>::insertAfter( GmAny p, const T& item )
{
GmListNode<T> * u = (GmListNode<T>*)p ;
GmListNode<T> * t = new GmListNode<T>( item ) ;
if( P == 0 )
{
t->tl = P = t ;
}
else if ( u == 0 )
{
// insertAfter 0 means prepend
t->tl = P->tl ;
P->tl = t ;
}
else
{
t->tl = u->tl ;
u->tl = t ;
if( u == P ) P = t ;
}
return GmAny( t ) ;
}
template <class T>
void GmList<T>::substitute( GmAny p, const T& item )
{
if( p == 0 )
{
GmError(
"void GmList<T>::substitute( GmAny p, const T& item )",
"Null iterator p" ) ;
return ;
}
GmListNode<T> * u = (GmListNode<T>*)p ;
u->hd = item ;
}
template <class T>
void GmList<T>::removeAfter( GmAny p )
{
GmListNode<T> * u = (GmListNode<T>*)p ;
// cannot del_after last
if( P == 0 )
{
GmError(
"void GmList<T>::removeAfter( GmAny p )",
"Empty list" ) ;
return ;
}
if( u == P )
{
GmError(
"void GmList<T>::removeAfter( GmAny p )",
"Can't remove after list item" ) ;
return ;
}
if( u == 0 ) u = P ; // del_after 0 means delete first
GmListNode<T> * t = u->tl ;
if( u == t )
{
P = 0 ;
}
else
{
u->tl = t->tl ;
if( P == t ) P = u ;
}
delete t ;
}
template <class T>
void GmList<T>::remove( const T& item )
{
if( P == 0 )
{
GmError(
"void GmList<T>::remove( const T& item )",
"Empty list" ) ;
return ;
}
GmListNode<T> * t = P->tl ; // first
GmListNode<T> * p = 0 ; // previous node
do
{
if( t->hd == item ) break ; // found
p = t ;
t = t->tl ;
} while( t != P ) ;
if( t->hd != item )
{
GmError(
"void GmList<T>::remove( const T& item )",
"Unable to found item" ) ;
return ; // not found
}
removeAfter( GmAny(p) ) ;
}
template <class T>
void GmList<T>::reverse()
{
if( P == 0 )
{
return ; // empty list
}
GmListNode<T> * l = P ;
GmListNode<T> * p = P->tl ;
GmListNode<T> * new_last = p ;
while( p != P )
{
GmListNode<T> * nxt = p->tl ;
p->tl = l ;
l = p ;
p = nxt ;
}
P->tl = l ;
P = new_last ;
}
template <class T>
void GmList<T>::sort( GmBoolean (*sort_proc)( T&, T& ) )
{
GmList<T> sorted ;
if( isEmpty() ) return ;
// le premier element appartient forcement a la liste triee.
sorted.append( head() ) ;
GmAny i = first() ;
for( next( i ) ; i!=0 ; next( i ) )
{
T to_sort = (*this)(i) ;
GmAny j, j_prev=0 ;
// recherche du 1er element superieur a l'item a classer.
for( j=sorted.first() ; j!=0 ; sorted.next( j ) )
{
if( (*sort_proc)( to_sort, sorted( j ) ) ) break ;
j_prev = j ;
}
// j_prev = 0 correspond a un prepend.
// si j == 0, j_prev pointe sur le dernier elt de sorted.
sorted.insertAfter( j_prev, to_sort ) ;
}
clear() ;
append( sorted ) ;
}
#ifdef POOL
///////////////////////////////// POOL /////////////////////////////////////////
/*
Systeme d'allocation specifique des noeuds de liste
qui s'est avere efficace lors de la destruction de
listes de plusieurs milliers d'elements.
Conserve ici pour une evolution possible...
*/
class <T>Pool {
private :
struct Link { Link * next ; } ;
unsigned esize ; // element size.
Link * head ;
<T>Pool( <T>Pool& ) {} // forbid copy.
void operator=( <T>Pool& ) {} // idem.
void grow() ;
public :
<T>Pool( unsigned ) ;
~<T>Pool() ;
void * alloc() ;
void free( void* ) ;
} ;
<T>Pool::<T>Pool( unsigned size ) : esize( size ) {
head = 0 ;
}
<T>Pool::~<T>Pool() {
}
void <T>Pool::grow() {
const int overhead = 12 ;
const int chunk_size = 8*1024-overhead ;
const int nelem = (chunk_size-esize)/esize ;
char * start = new char[chunk_size] ;
char * last = &start[(nelem-1)*esize] ;
for( char * p=start ; p<last ; p+=esize ) {
((Link*)p)->next = (Link*)(p+esize) ;
}
((Link*)last)->next = 0 ;
head = (Link*)start ;
}
void * <T>Pool::alloc() {
if( head == 0 ) grow() ;
Link * p = head ;
head = p->next ;
return p ;
}
void <T>Pool::free( void * b ) {
Link * p = (Link*)b ;
p->next = head ;
head = p ;
}
#endif // POOL
#endif // List_C
#ifndef _Gm_List_h_
#define _Gm_List_h_ 1
typedef unsigned char GmBoolean ;
typedef void* GmAny ;
#ifdef __xlC__
#pragma implementation("List.C")
#endif
template <class T>
class GmListNode ;
template <class T>
class GmList
{
public :
GmList() ;
GmList( const GmList<T>& ) ;
~GmList() ;
GmList<T>& operator=( const GmList<T>& ) ;
void append( GmList<T>& ) ;
void prepend( GmList<T>& ) ;
GmBoolean isEmpty() const ;
int count() const ;
void clear() ;
GmAny prepend( const T& ) ;
GmAny append ( const T& ) ;
GmAny first() const ;
GmAny seek( const T& ) const ;
GmAny seek( unsigned int ) const ;
void next( GmAny& ) const ;
T& operator()( GmAny ) const ;
T pop() ;
void substitute( GmAny, const T& ) ;
GmBoolean owns( GmAny ) const ;
GmBoolean owns( const T& ) const ;
T& head() const ;
T& tail() const ;
GmAny insertAfter( GmAny, const T& ) ;
void removeAfter( GmAny ) ;
void remove( const T& ) ;
void reverse() ;
void sort( GmBoolean (*)( T&, T& ) ) ;
protected :
GmListNode<T> * P ;
} ;
#if defined(__GNUC__)
#include "List.C"
#endif
#endif // ! _Gm_List_h_
#include "WorkSession.h"
#include "WSHistLog.h"
GmWorkSession::GmWorkSession()
{
state_ = GmWS_IDLE;
}
GmWorkSession::~GmWorkSession()
{
}
void GmWorkSession::addHistoryLog( GmWorkSessionHistoryLog& w_s_hist_log )
/*
Purpose : Ajout d'un histoy_log.
*/
{
history_logs_.append( &w_s_hist_log );
}
#ifndef _Gm_WorkSession_h_
#define _Gm_WorkSession_h_
#include "List.h"
class GmWorkSessionHistoryLog;
enum GmWorkSessionState
{
GmWS_IDLE,
GmWS_WORKING
};
class GmWorkSession {
public :
GmWorkSession();
virtual ~GmWorkSession();
virtual void addHistoryLog( GmWorkSessionHistoryLog&);
protected :
GmWorkSessionState state_;
GmList<GmWorkSessionHistoryLog*> history_logs_;
private :
};
#endif /* _Gm_WorkSession_h_ */
M WorkSession.C
D /gem/gemdev/Core-Linux/Core/lib/Linux2.2/static/lintest
A '-c' '-frepo'
O __t10GmListNode1ZP23GmWorkSessionHistoryLogRCP23GmWorkSessionHistoryLogPt10GmListNode1ZP23GmWorkSessionHistoryLog
O clear__t6GmList1ZP23GmWorkSessionHistoryLog
C append__t6GmList1ZP23GmWorkSessionHistoryLogRCP23GmWorkSessionHistoryLog
C _._t6GmList1ZP23GmWorkSessionHistoryLog
C __t6GmList1ZP23GmWorkSessionHistoryLog
M WorkSession.C
D /gem/gemdev/Core-Linux/Core/lib/Linux2.2/static/lintest
A '-c' '-frepo'
O __t10GmListNode1ZP23GmWorkSessionHistoryLogRCP23GmWorkSessionHistoryLogPt10GmListNode1ZP23GmWorkSessionHistoryLog
O _._t10GmListNode1ZP23GmWorkSessionHistoryLog
C clear__t6GmList1ZP23GmWorkSessionHistoryLog
C append__t6GmList1ZP23GmWorkSessionHistoryLogRCP23GmWorkSessionHistoryLog
C _._t6GmList1ZP23GmWorkSessionHistoryLog
C __t6GmList1ZP23GmWorkSessionHistoryLog
#ifndef _Gm_WSHistLog_h_
#define _Gm_WSHistLog_h_
#include "List.h"
class GmWorkSession;
class GmWorkSessionEvent;
class GmWorkSessionHistoryLog
{
public :
GmWorkSessionHistoryLog( GmWorkSession& work_session);
virtual ~GmWorkSessionHistoryLog();
virtual void record( GmWorkSessionEvent& w_s_event );
private :
GmList<GmWorkSessionEvent*> work_session_events_;
GmWorkSession& work_session_;
};
#endif /* _Gm_WSHistLog_h_ */