objective-ccocoalinkerldscripting-bridge

How do I let Scripting Bridge generate Objective-C classes at runtime?


I was updating a Scripting Bridge glue file today (for Mail.app), and noticed that the sdp(1) man page reads:

You do not need to create a corresponding implementation file; Scripting Bridge will create the class implementations at runtime.

That sounds cool, but without implementations for the generated classes I get (as expected):

Undefined symbols for architecture x86_64:
  "_OBJC_CLASS_$_MailApplication", referenced from:
      objc-class-ref in DMBugReportWindowController.o
  "_OBJC_CLASS_$_MailAttachment", referenced from:
      objc-class-ref in DMBugReportWindowController.o
[... more of the same ...]
ld: symbol(s) not found for architecture x86_64`

I don't want to suppress all undefined symbols, as that could easily mask legitimate issues, so I just used -U (per the ld(1) man page):

Specified that it is ok for symbol_name to have no definition. With -two_levelnamespace, the resulting symbol will be marked dynamic_lookup which means dyld will search all loaded images.

(I had to use -Xlinker -U -Xlinker _OBJC_CLASS_$_MailApplication for those flags to reach ld, otherwise clang keeps those arguments for itself.)

Evidently making them dynamic_lookup is the wrong thing to do, because this gives a dynamic link error on launch:

dyld: Symbol not found: _OBJC_CLASS_$_MailApplication
  Referenced from: /Users/jonathon/Library/Developer/Xcode/...
  Expected in: flat namespace
 in /Users/jonathon/Library/Developer/Xcode/...

This also happens if I use -force_flat_namespace -undefined suppress (which I don't want to use, as above). The Scripting Bridge Programming Guide seems to imply I'm doing things correctly ("Preparing to Code" section), but doesn't mention this issue.


Solution

  • As the class is dynamically created, you cannot link to it. The class will be registered at runtime but no symbol will be exported and the linker won't be able to find it.

    You need to replace all messages sent to MailApplication and MailAttachment with messages to NSClassFromString(@"MailApplication") and NSClassFromString(@"MailAttachment").

    [MailApplication class] becomes NSClassFromString(@"MailApplication") and [MailAttachment class] becomes NSClassFromString(@"MailAttachment").