jmah
jmah

Reputation: 2214

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.

Upvotes: 4

Views: 705

Answers (2)

qqqchen
qqqchen

Reputation: 1

I encountered a similar problem when bridging to Keynote in Objective-C. I can build without linking errors as long as I don't use [ClassName class] as in the comment lines below:

for (KeynoteIWorkItem* item in selection) {
    // if ([item isKindOfClass:[KeynoteShape class]) {
        KeynoteShape *shape = (KeynoteShape *)item;
    //}
}

Upvotes: 0

Nicolas Bachschmidt
Nicolas Bachschmidt

Reputation: 6505

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").

Upvotes: 5

Related Questions