I\'ve got an objective-c \"tool\" (console) program that dynamically loads objective-c bundle\'s at runtime. Some of the bundle files share classes from the same framework s
If you developer of plugin bundle you can pass -undefined dynamic_lookup as other linker flags and remove all libraries from plugin which duplicates in both (in main binary and in plugin)
Have you tried only adding the headers (@interface
s) of the shared classes to the bundles (so that the compiler knows about the API), but not the code files (@implementation
s)?
Since you're linking a bundle, the linker (ld
) shouldn't complain that it cannot find the implementations of the given classes -- it will delegate this task to the dynamic linker (dyld
) which kicks in once you load the bundle in your main program. dyld
should then establish the required references between bundle and program automagically.
If they are different implementations, use a unique prefix.
If they're the same implementation and just exported by more than one image, reconfigure your targets so it's exported by only one.
Specifically:
Is there a way that the bundle's could be changed so they don't both compile/link the same classes?
Stuff those shared classes in a separate framework, and do not compile them as part of the bundle -- just link the bundle to the framework of shared stuff.
I have been in this boat before and it's not a good boat to be in. I spent a long time investing in the best possibly way to avoid runtime class name clashes. The solution was:
Create a pre-build script that parses all @interface
declarations in header files, and reaps all of the class names. This script generates a new header that contains something like the following:
#define MyClass MyClass_Target
#define MyOtherClass MyOtherClass_Target
#define MyThirdClass MyThirdClass_Target
(obviously the _Target
suffix is set by a build parameter that your pre-build script is able to see and use).
The script could be a Perl or Python script that just scans every *.h
file extracting the word after @interface
.
Configure the build to automatically include the generated header file so you don't have to manually include the generated header in each source file.
If your bundles have nibs, it adds an extra step of complexity but it can still be done. Create another script that replaces the existing “Nib Compiler”. This program basically performs the same class-renaming but for nibs (it's easy enough because the nib files are XML). I can't remember where to set it, but there's a place in Xcode that allows you to choose how Nib files are “compiled”. Your nib compiler script is basically a wrapper that renames the classes in the nibs and then invokes the real nib compiler (which you can find out how it is invoked by looking at the build log).
Yes, and it works surprisingly well, even in debugging situations. When you hit a breakpoint, Xcode displays the name of the class with its target suffix so you know which bundle you are in, despite the source code showing something different. “Fix & Continue” still worked as far as I can remember.
Also, because the class-renaming is done just before compile time, it doesn't affect things like source code versioning, interactions with Interface Builder, etc.
Dynamically generated class names won't work, e.g. Class
objects returned from NSClassFromString
, unless the code is made aware of the necessary suffix.
Such a complicated set up requires a bit of maintenance. Once I had it up and running it was working well for our needs, but every now and then it needed a tweak to keep it running smoothly.