How to make categories in a library work?

Question

Sometimes, categories in a library do not seem to make it to the final executable. Why?

Answer

Actually, all there is to it is understanding the semantics of linking. Most (if not all) linkers operate as follows: Given the objects and libraries on the command line, proceed from left to right. If an object is encountered, add it to the output, resolving symbols if possible, noting yet unresolved symbols if needed. If a library is encountered, extract from it any object file which provides some of the yet unresolved symbols. If an object does not help this cause, the object file is not loaded.

On nextstep, with NeXT's Objective-C, the linker has a flag, -ObjC telling it to load any object encountered in a library, even if it does not help resolving, if it merely defines an Objective-C class or category. Problem solved.

On other systems, with GNU's Objective-C, where the linker is blissfully unaware of Objective-C, such an option does not exist. It is, however, fairly easy to obtain Objective-C semantics on these machines.

Every class definition in an Objective-C source file causes the definition of a global symbol in the output file. For a class Foo, the symbol __objc_class_name_Foo is defined. Similarly, for the category Too of the class Foo, the symbol __objc_category_name_Foo_Too is defined.

Now, if a class method is invoked of the Bar class, an undefined reference is added to the object file to, in this case, __objc_class_name_Bar. Such a reference is also output for the superclass of a class being defined. Thus, basically, classes are resolved just as effectively as functions normally are. There are, however, two problems:

  1. Classes which are never sent a class method and which are not the superclass of any other class being loaded, are not included in the linker output. This is not normally a problem, until you want to do dynamic loading: any dynamically loaded code should better not reference the non-included class.
  2. Categories are never referenced in the compiler generated reference graph. This implies they will not normally be included, if the linker sees no other reason to include the object file containing the category.
The solution to the problem of linking with Objective-C semantics now becomes very trivial: Enter some external references to an object file of which you know it will be included, for instance because it contains the top class of your library's class hierarchy, or because it contains the function called from a number of other object files one of which you're sure of will be included.

For example, to force inclusion of the Foo (Too) category mentioned above, one could add the following function to an object file known to always be included:

void
mylib_get_objc_linking (void *x)
{
  extern int __objc_category_name_Foo_Too;

  if (!x)
    return;

  mylib_get_objc_linking (&__objc_category_name_Foo_Too);
}
The return statement is needed in case the function is actually called, which in turn might be needed if there is not a `the single always-referenced object file'. If the function actually is called, the x argument should be 0, obviously. The if can not be omitted, to prevent the compiler from thinking to be smart and deleting the invocations following the unconditional return.

I know nothing about Stepstone's Objective-C, so I can't even tell if this problems exists on that platform.


This question pops up every now and then in comp.lang.objective-c. The answer does not change. Mail your comments on this page to tiggr@ics.ele.tue.nl.
Up: Infrequently Asked Questions concerning Objective-C
Previous: Class variables
Copyright (C) 1995, 1996 Pieter J. Schoenmakers. All rights reserved.
tiggr@ics.ele.tue.nl, Sat Jun 8 1996