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.