I'm trying to solve Can Xcode tell me if I forget to include a category implementation in my target?, and I came up with the following solution:
NSObject+Foo.h
extern int volatile canary;
void canaryCage() {
canary = 0;
}
NSObject+Foo.m
int canary = 0;
Now, if I #import "NSObject+Foo.h"
in a source file, I'll get a linker error if that NSObject+Foo.m
wasn't also included in my target.
However, every time I #import "NSObject+Foo.h"
I generate a duplicate _canaryCage
symbol. I can't use __COUNTER__
because I only #import "NSObject+Foo.h"
in implementation files. I need canaryCage
to be unique across my whole symbol table.
I need something like:
#define CONCAT(x, y) x##y
#define CONCAT2(x, y) CONCAT(x, y)
extern int volatile canary;
void CONCAT2(canaryCage, __RANDOM__)() {
canary = 0;
}
This way, if I have source files like:
Bar.m
#import "NSObject+Foo.h"
Baz.m
#import "NSObject+Foo.h"
I'll get symbols like _canaryCage9572098740753234521
and _canaryCage549569815492345
, which won't conflict. I also don't want to enable --allow-multiple-definition
in ld
because I want other duplicate symbol definitions to cause an error. I don't want to use canaryCage
for anything but a marker that I forgot to link a source file whose header I #import
ed.
This answer was close, but it resulted in canaryCage
being optimized away because it was dead code.
Solution:
NSObject+Foo.h
extern int canary;
__attribute__((constructor)) static void canaryCage() {
canary = 0;
}
NSObject+Foo.m
int canary = 0;
Unfortunately, this adds some overhead every time the category is imported, but the overhead is very minimal. If anyone knows a way to prevent canaryCage
from being stripped, I'll happily mark their answer as correct.