Path: utzoo!utgpu!water!watmath!clyde!att!rutgers!ucsd!ucbvax!decwrl!sun!pitstop!sundc!seismo!uunet!mcvax!cernvax!ethz!iis!prl From: prl@iis.UUCP (Peter Lamb) Newsgroups: comp.lang.c++ Subject: Re: Global constructors and C++ I/O streams; problems and questions. Message-ID: <656@eiger.iis.UUCP> Date: 21 Oct 88 21:46:40 GMT References: <5955@columbia.edu> Reply-To: prl@iis.UUCP (Peter Lamb) Organization: Integrated Systems Lab., ETH Zuerich Lines: 111 In article <5955@columbia.edu> beshers@select.UUCP () writes: > The following program suffers a memory fault before it ever gets > to the first line of main(). The problem lies in the constructor > of the global instance 'example hello'; the reference to the > cout stream occurs before the initialization of that stream. > Because global instances are initialized in the order in which > they are declared, this is expected; only external references to > these streams are present in stream.h, and so their actual > declaration gets packaged into libC.a. I was going to mail this to beshers@select, but I ended up writing a reasonably long section about handling cross-file global constructor dependencies, so I have posted to news instead. I compiled and ran your code and it gave me exactly the right answer; ie it printed Hello, world We never get to the first line... [[ I deleted the example. 'Hello, world' is printed by a static constructor, `We never...' is printed by main() ]] Also note; global (and file static) instances are executed in the order that they are *defined*, not the order of their *declaration*. It appears that there is something wrong with either your library or your CC script. Possibly the library object files are in the wrong order in the library. This order is of paramount importance. Another possibility is that `munch' isn't being run correctly and/or its output isnt being compiled and linked into your program. CC should do the following: Compile any C or C++ code to object Link the object modules, if no errors, then run nm -pg | munch > __ctdt.c Compile __ctdt.c Re-link the object modules, including __ctdt.o. nm must be run with the -p flag on BSD. I seem to remember that CC as distributed had nm without flags. I tried changing the nm flags to just -g, and it crashed in exactly the way you mentioned. I think that this is most likely your problem. > So, the question, is there any way around this? It seems like > this would problem would exist for *any* class instances are > declared in some library. Sure, I don't *really* need this > feature, but it is nice. Although the streams and other libC classes should work properly, you are quite right in believing that initialisation of static objects whose correct initialisation depends on the initialisation of other static objects is something that is *very* hokey in C++. It _is_ very useful; the problem is that the Unix, and most other, loaders are too dumb. Some rules of thumb for doing this are (this assumes BSD4.[23]. I am not familiar enough with the finer points of the SysV ld and loader utilities to know if all of these things will work there): 1) Don't overuse the feature and try to avoid (where possible) static objects that depend on the initialisation of static objects in other files. 2) Use explicit loads of object modules rather than libraries. You have more control over them. The BSD loader and munch together will ensure that the static constructors in the last-mentioned files (and libraries) will be executed before those in the earlier modules. Static destructors will be called for the object files left-to-right. 3) If you need to put interdependent static objects in libraries use the old Unix v7 commands lorder and tsort to try to persuade the objects to be put into the library in the correct order: eg, for make: universal_class_lib.a: $(OBJECTS) rm -f universal_class_lib.a ar crv universal_class_lib.a `lorder $(OBJECTS) | tsort` ranlib universal_class_lib.a # This isn't needed for SysV If tsort doesn't complain about cycles in the data, the library will probably load in the correct order. If you can't get this to work, you will have to order the library by hand, or prehaps rearrange your objects in their files. 4) The order of initialisation between object files is *not* defined as part of the language. So none of the above need necessarily work. Static constructors should be able to do IO through streams, and the mechanisms which allow this will probably mean that the other techniques will work as well. It is a great pity that this can't be done *much* better, but Unix (and most other) loaders are just too dumb (there are good reasons for loaders to be dumb, too, unfortunately...). -- Peter Lamb uucp: seismo!mcvax!ethz!prl eunet: prl@ethz.uucp Tel: +411 256 5241 Institute for Integrated Systems ETH-Zentrum, 8092 Zurich