|
|
There are some unique problems that can be encountered when using automatic instantiation and preparing archive libraries (.a files) that contain template-based code. However, the bottom line is that the automatic instantiation system should handle most of them without user invention; the material in this section is for rare situations where this does not happen, or for those looking to fine-tune their instantiations.
To begin with, consider this simple example:
$ cat A.h template<class T> class A { public: int fff(); int ggg(); int hhh(); };#include "A.C"
$ cat A.C template<class T> int A<T>::fff() { return (T) 1; }
template<class T> int A<T>::ggg() { return (T) 2; }
template<class T> int A<T>::hhh() { return (T) 3; }
$ cat al1.C #include "A.h"
int al1() { A<int> a; return a.fff() + a.ggg(); }
$ cat al2.C #include "A.h"
int al2() { A<int> a; return a.fff() + a.hhh(); }
$ cat main.C int al1(); int al2();
int main() { return al1() + al2(); }
The main function calls two other functions. The two other functions each call member functions of the same template instantiation.
However, as it happens the two other functions are in separate archive libraries, so we build the first library:
$ CC -c al1.C $ CC -Tprelink_objects al1.o prelink: INFO: C++ prelinker: executing: CC -c al1.C $ ar rv libal1.a al1.o a - al1.o UX:ar: INFO: Creating libal1.aand then the second library:
$ CC -c al2.C $ CC -Tprelink_objects al2.o prelink: INFO: C++ prelinker: executing: CC -c al2.C $ ar rv libal2.a al2.o a - al2.o UX:ar: INFO: Creating libal2.aNow, pretend we are using an earlier release of the UDK C++ compiler. We build the main program executable and link it against the two archive libraries.
$ CC -c main.C $ CC -L. main.o -lal1 -lal2 UX:ld: ERROR: ./libal2.a(al2.o): fatal error: symbol `A<T1>::fff(void) [with T1=int, return type=int]` multiply-defined, also in file ./libal1.a(al1.o)What happened? After the prelinking and archiving, libal1.a:al1.o has definitions of "A<int>:fff()" and "A<int>:ggg()", while libal2.a:al2.o has definitions of "A<int>:fff()" and "A<int>:hhh()". When the main program pulls in libal1.a:al1.o to resolve al1() and libal2.a:al2.o to resolve al2(), it also pulls in both definitions of "A<int>:fff()", and hence the error.
This is a very common situation to get into when using archive libraries for template-based code. There are four possible solutions:
However, there are two disadvantages. Extra copies of template instantiations are still kept in the .o files making up the archive, and depending upon the application this could lead to significant code bloat.
In addition, certain arrangements of template source code and usages, especially those developed under the gcc compiler using the -frepo option, may not be linkable in this approach without significantly rearranging the contents of the archives, a rearrangement that may not be feasible.