jac@sundance.llnl.gov (James Crotinger) (09/19/90)
I have a question concerning the use of libraries in C++. Suppose I'm trying to write a library like iostream.h. The library instantiates cout and iostream.h contains the line: extern iostream_whatever cout; [I'm grossly simplifying that, but you get the point.] Now the actual declaration of cout is in libiostream.a. My question is, does cout get initialized. On the Sun, the answer would apparently be "no". A short example is helpful. Consider the following class: // B.h #include <stdio.h> class B { public: B(char *str) { printf(str); printf("\n"); } }; and the "library" implementation file: // B.cc #include "B.h" B foobar("B.c"); and the main program: // main.cc #include <stdio.h> #include "B.h" extern B foobar; // should really go in B.h main() { printf("In main()\n"); B foo("main()"); } Now, if I compile this with the following line: CC -o test main.cc B.cc then things work as expected and the following output is generated: B.c In main() main() Now if I instead build a library and link to it: ar rc libfoo.a B.o ranlib libfoo.a CC -o test main.cc -L. -lfoo I only get: In main() main() i.e. the constructor for foobar is never called. [note that g++ gives the same behavior] Examination of the CC script which comes with Sun C++ shows why this is true. They use the UNIX "nm" utility to find the names of the static constructors; e.g.: CC -o test main.o -L. -lfoo nm test | munch > tmp.cc CC -o test main.o tmp.cc -L. -lfoo The probem is that nm is only run on the executable and not on the libraries. Since the linker didn't see any calls to the __st[id]__.* functions which were to initialize foobar, it did not load that function into the executable and thus nm/munch can't find it and so it doesn't get called. The question is: is this broken behavior? It is apparent from the implementation of iostream.h that this behavior is known and expected. They handle initialization of cout, etc., by declaring a static instance of class Iostream_init() which apparently initializes the standard streams when the first instance of Iostream_init is created and destroys them when the last instance of Iostream_init is destroyed. This seems like an unnecessary kludge. Why not run the constructors for all of the global objects declared in a library? Granted it would be better to run them for only the objects which you use, but lacking that it would seem to be less of a hack to just run them all, and keep the sizes of you libraries small. Jim -- ----------------------------------------------------------------------------- James A. Crotinger Lawrence Livermore Nat'l Lab // The above views jac@gandalf.llnl.gov P.O. Box 808; L-630 \\ // are mine and are not (415) 422-0259 Livermore CA 94550 \\/ necessarily those of LLNL.