Here's one for the STL gurus. I'll start with the question I really need answered, and then describe the background of my specific problem for anyone who is interested. The question: How do you handle STL template instantiation in a large, multi-library program? I have a large C++ program that exists as multiple libraries in multiple directories. It has templates of my own design. I want to start using STL in addition to my own template classes. What is the best way to compile and link so as to get the necessary template instantiations without getting multiple copies of the template code in every .o file that uses the templates? The background: I'm running RedHat 5.2, kernel 2.2.1 on an alpha and compiling with egcs version egcs-2.91.66 19990314 (egcs-1.1.2 release). For the last few years I've been developing a large C++ program as multiple libraries in multiple directories. Some of my classes and functions are templates. I compile everything with -fno-implicit-templates and use explicit template instantiation. Until now this has worked well for me. Now I want to learn and start using STL. I started with a simple standalone program, all of which was in a single file in a single directory. I compiled this WITHOUT -fno-implicit-templates and it worked. Now I am trying to link it to some of the libraries from my big project, which are compiled WITH -fno-implicit-templates. If I compile the small test program with -fno-implicit-templates, I get a zillion "undefined reference" errors from the linker, all of which refer to stl classes and functions. If I compile it without -fno-implicit-templates, it compiles, links and runs, but this is not a useful solution for my big program, since, as I understand things, it would cause a lot of unnecessary object code bloat. I tried explicit instantiation of the STL templates I thought my program was using, but I could never get it to work. It gave error messages similar to the ones shown below for the next example. Next I tried -frepo, which works fine for my big program (that does not yet use STL), but fails when I try to compile the test program that does use STL: g++ -c -g -I../p38 -I../util -I../gold -I../jw -DALPHA -DMAKE_DATE="\"Mon Sep 13 15:34:30 UTC 1999\"" -Werror -L../lib/alpha -frepo stlsort.cc -o alpha/stlsort.o g++ -g -I../p38 -I../util -I../gold -I../jw -DALPHA -DMAKE_DATE="\"Mon Sep 13 15:34:30 UTC 1999\"" -Werror -L../lib/alpha -frepo alpha/stlsort.o -lp38 -lutil -lgold -ljw -lbsd -lcpml -lm -o alpha/stlsort alpha/stlsort.o: In function `sort__H2ZPP4JunkZPFPC4JunkPC4Junk_b_X01T0X11_v': /usr/include/g++/stl_algo.h:1060: undefined reference to `__introsort_loop__H4ZPP4JunkZP4JunkZlZPFPC4JunkPC4Junk_b_X01T0PX11X21X31_v' /usr/include/g++/stl_algo.h:1060: undefined reference to `__introsort_loop__H4ZPP4JunkZP4JunkZlZPFPC4JunkPC4Junk_b_X01T0PX11X21X31_v' /usr/include/g++/stl_algo.h:1061: undefined reference to `__final_insertion_sort__H2ZPP4JunkZPFPC4JunkPC4Junk_b_X01T0X11_v' /usr/include/g++/stl_algo.h:1061: undefined reference to `__final_insertion_sort__H2ZPP4JunkZPFPC4JunkPC4Junk_b_X01T0X11_v' collect2: ld returned 1 exit status make: *** [alpha/stlsort] Error 1 I am including the test program as an attachment. If anyone has suggestions, or if you can just tell me how you handle STL template instantiation in large multi-library programs, I would be most grateful. TIA, Jack Wathey
/*--------------------------------------------------------------------- $Id: stlsort.cc,v 1.5 1999/09/13 14:19:04 jack Exp jack $ ---------------------------------------------------------------------*/ /* simple C++ test program */ #include <iostream.h> #include <vector> #include <algorithm> #include <stdlib.h> #include <string.h> #include <Timer.h> using namespace std; //--------------------------------------------------------------------- class Junk { static const int n_elements = 10000; int value; int *p_ints; public: Junk( int i=0 ) : value( i ), p_ints(0) { p_ints = new int[n_elements]; } Junk( const Junk& original) : value( original.value ), p_ints(0) { p_ints = new int[n_elements]; bcopy( original.p_ints, p_ints, n_elements*sizeof(int) ); } friend bool junk_comp( const Junk* p1, const Junk* p2 ); bool operator<( const Junk& rhs ) const { return( value < rhs.value ); } Junk& operator=( int i ) { value = i; return *this; } Junk& operator=( const Junk& rhs ) { value = rhs.value; delete [] p_ints; p_ints = new int[n_elements]; bcopy( rhs.p_ints, p_ints, n_elements*sizeof(int) ); return *this; } ~Junk(void) { delete [] p_ints; p_ints = 0; } friend ostream& operator<<( ostream& out, const Junk& junk ); }; bool //--------------------------------------------------------------------- junk_comp( const Junk* p1, const Junk* p2 ) { return( p1->value < p2->value ); } ostream& //--------------------------------------------------------------------- operator<<( ostream& out, const Junk& junk ) { return( out << junk.value ); } #if 0 template class vector<Junk>; template void sort<Junk *>(Junk *, Junk *, bool (*)(const Junk *, const Junk *) ); #endif #if 0 template class vector<Junk>; template void sort<Junk *>(Junk *, Junk *); template void fill<Junk *, Junk>(Junk *, Junk *, Junk const &); template void __introsort_loop<Junk *, Junk, long>(Junk *, Junk *, Junk *, long); #endif int //--------------------------------------------------------------------- main( int argc, char **argv ) { int i; vector<Junk*> j(2000); for(i=0; i<j.size(); i++) { j[i] = new Junk; *j[i] = rand(); } cout << "Original contents of j:\n"; for(i=0; i<j.size(); i++) { cout << *j[i] << " "; } cout << endl; Timer sort_time( "sort" ); sort_time.start(); sort(j.begin(), j.end(), junk_comp); sort_time.stop(); cout << "Sorted contents of j:\n"; for(i=0; i<j.size(); i++) { cout << *j[i] << " "; } cout << endl; Timer::write_all_timers(); return 0; }