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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With