Sat 03 Sep 2011 02:47:22 AM UTC, comment #1:
This problem appears to be a bit more complicated than +bundleForClass not working.
The cause is +[NSBundle intialize] not finding the NSFramework_EtoileUI class, which doesn't exist at the time it was called. NSBundle builds a list of frameworks when its +intialize method is called, by searching the runtime for classes that begin with "NSFramework_". These classes are placeholders, generated by gnustep-make, that indicate that a shared library is in fact a framework, and like bundles, can contain resources to be loaded.
In this case, EtoileUI was accidentally triggering the +[NSBundle intialize] method before NSFramework_EtoileUI had been loaded. It does this by calling GNUstep classes (such as NSString and NSSet) from a +load method in a category on NSView. +load methods are implemented by creating constructor functions i.e. _attribute_((constructor)) that are called when a shared library is loaded. This is a problem because these constructor functions also seem to be used to register classes with the runtime when a shared library is loaded.
+load is not supposed to be used for anything other than very simple, C-based intialisation, because as documented here [1], +load is not guaranteed to be called at a time when other classes are ready. By doing this, NSBundle initializes before all other classes are loaded and builds an incomplete framework list.
The correct solution is not use +load for anything other than calling classes in the same file, but this still means that NSBundle is vulnerable to being initialised to early and building incomplete framework meta-data. NSBundle cannot easily convert its initialisation to a +load method either, which would prevent the issue from occurring.
[1] http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/What-you-can-and-what-you-cannot-do-in-_002bload.html#What-you-can-and-what-you-cannot-do-in-_002bload
|