Why do protocol_* methods do not work with Clang + modern GCC-Runtime on Linux?

clang, objective-c, objective-c-runtime

Solution

In my tests, GCC works well with its included GNU libobjc, but Clang works better with GNUstep libobjc2.

GCC 4.6 w/ included GNU libobjc: PASS

P1
class method first:
the protocol: 0x602120
the protocol's name: MyProtocol
required: YES instance: YES → (nil)
required: YES instance: NO → 0x10eda50
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
instance method follows:
the protocol: 0x602120
the protocol's name: MyProtocol
required: YES instance: YES → 0x10eda40
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
P2
class method first:
the protocol: 0x602120
the protocol's name: MyProtocol
required: YES instance: YES → (nil)
required: YES instance: NO → 0x10eda50
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
instance method follows:
the protocol: 0x602120
the protocol's name: MyProtocol
required: YES instance: YES → 0x10eda40
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
done

GCC 4.6 w/ libobjc2 1.6: FAIL

P1
class method first:
the protocol: 0x602120
the protocol's name: MyProtocol
required: YES instance: YES → (nil)
required: YES instance: NO → 0x6020a0
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
instance method follows:
the protocol: 0x602120
the protocol's name: MyProtocol
required: YES instance: YES → 0x6020b0
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
P2
class method first:
the protocol: (nil)
instance method follows:
the protocol: (nil)
done

Clang 3.1 w/ GCC 4.6 GNU libobjc: FAIL

P1
class method first:
the protocol: 0x602080
the protocol's name: (null)
required: YES instance: YES → (nil)
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
instance method follows:
the protocol: 0x602080
the protocol's name: (null)
required: YES instance: YES → (nil)
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
P2
class method first:
the protocol: (nil)
instance method follows:
the protocol: (nil)
done

Clang 3.1 w/ libobjc2 1.6: PASS

P1
class method first:
the protocol: 0x602080
the protocol's name: MyProtocol
required: YES instance: YES → (nil)
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
instance method follows:
the protocol: 0x602080
the protocol's name: MyProtocol
required: YES instance: YES → (nil)
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
P2
class method first:
the protocol: 0x602080
the protocol's name: MyProtocol
required: YES instance: YES → (nil)
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
instance method follows:
the protocol: 0x602080
the protocol's name: MyProtocol
required: YES instance: YES → (nil)
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
done

Problem

I tried to switch some of my Objective-C projects from GCC to Clang on Linux. I used the GCC 4.6.2 runtime because the Clang compiler does not ship with one. The compiling and linking works, but when using the `protocol_*` methods they do not work. The following example works fine with GCC but not as expected with Clang: ``` #include <objc/runtime.h> #include <stdio.h> @protocol MyProtocol + aClassMethod; - anInstanceMethod; @end void doIt(Protocol *p, SEL sel) { printf("the protocol: %p\n", p); if (!p) return; printf("the protocol's name: %s\n", protocol_getName(p)); struct objc_method_description d = protocol_getMethodDescription(p, sel, YES, YES); printf("required: YES instance: YES → %p\n", d.name); d = protocol_getMethodDescription(p, sel, YES, NO); printf("required: YES instance: NO → %p\n", d.name); d = protocol_getMethodDescription(p, sel, NO, YES); printf("required: NO instance: YES → %p\n", d.name); d = protocol_getMethodDescription(p, sel, NO, NO); printf("required: NO instance: NO → %p\n", d.name); } int main(int argc, char **argv) { Protocol *p1 = @protocol(MyProtocol); printf("P1\n"); printf("class method first:\n"); doIt(p1, @selector(aClassMethod)); printf("instance method follows:\n"); doIt(p1, @selector(anInstanceMethod)); Protocol *p2 = objc_getProtocol("MyProtocol"); printf("P2\n"); printf("class method first:\n"); doIt(p2, @selector(aClassMethod)); printf("instance method follows:\n"); doIt(p2, @selector(anInstanceMethod)); printf("done\n"); return 0; } ``` The expected output of the GCC compiled program: ``` P1 class method first: the protocol: 0x804a06c the protocol's name: MyProtocol required: YES instance: YES → (nil) required: YES instance: NO → 0x804b530 required: NO instance: YES → (nil) required: NO instance: NO → (nil) instance method follows: the protocol: 0x804a06c the protocol's name: MyProtocol required: YES instance: YES → 0x804b528 required: YES instance: NO → (nil) required: NO instance: YES → (nil) required: NO instance: NO → (nil) P2 class method first: the protocol: 0x804a06c the protocol's name: MyProtocol required: YES instance: YES → (nil) required: YES instance: NO → 0x804b530 required: NO instance: YES → (nil) required: NO instance: NO → (nil) instance method follows: the protocol: 0x804a06c the protocol's name: MyProtocol required: YES instance: YES → 0x804b528 required: YES instance: NO → (nil) required: NO instance: YES → (nil) required: NO instance: NO → (nil) done ``` The unexpected output of the Clang compiled program: ``` P1 class method first: the protocol: 0x804a050 the protocol's name: (null) required: YES instance: YES → (nil) required: YES instance: NO → (nil) required: NO instance: YES → (nil) required: NO instance: NO → (nil) instance method follows: the protocol: 0x804a050 the protocol's name: (null) required: YES instance: YES → (nil) required: YES instance: NO → (nil) required: NO instance: YES → (nil) required: NO instance: NO → (nil) P2 class method first: the protocol: (nil) instance method follows: the protocol: (nil) done ``` What's wrong here? Is there some magical initialization code which will not be called when using Clang? [Update] When adding an implementation of the protocol like the following the `objc_getProtocol()` method works but the `protocol_*` methods still do not. ``` @interface MyInstance <MyProtocol> @end @implementation MyInstance + aClassMethod { return nil; } - anInstanceMethod { return nil; } @end ```

Original source