Help with plug-in functions

Mikuro

Crotchety UI Nitpicker
I'm designing a program that needs support for simple plugins. These plugins will have one function (maybe two), and that's all. The plugins will need to be able to use the Accelerate framework, and if possible Cocoa as well (not for any GUI stuff, but NSSets make my life easier). Ideally, I'd like performance to be as good as calling a regular C function.

It seems like a simple enough task, but I have no idea where to start. I see things in XCode's New Project window like "static Cocoa library", "dynamic Cocoa library", "generic C++ plugin". I'm not really sure how any of these work.

So, I have three main questions:
What's the best way to make such plugins?
How do I load them at runtime?
How do I access their functions?

Any advice would be greatly appreciated. I don't want to jump in using the first method that I can get working only to realize it was not the right choice.
 
You want to use dynamic linking. I found this which might get you started.
http://developer.apple.com/document...ortingUnix/compiling/chapter_4_section_9.html

I haven't done anything like that but you need some sort of dynamically linked libraries, they can't be statically linked.

I think the easiest way to use the plugins once they are loaded is to have a standard interface that each plugin has to support. You can then be assured that these functions are there. Something like a function to create whatever gui the plugin adds or however you are doing it.

Center stage supports plugins for their media center software so you could download the source code and look at how they do it. It's a fairly complecated piece of software so I haven't really looked at it in a long time.
 
Thanks for the tip. I made a BSD Dynamic Library with one simple function, and can load it at runtime and access the function with no problem. However, when I try to load more than one plugin at the same time, things fall apart. It seems like only the first one works. I guess there's a symbol conflict, but I have no idea how to solve it. Here's exactly what I've done:

I made two versions of my dylib: both have a single function called testFunction, which takes an int and returns an int. One adds one to the int passed and returns the result. The other subtracts one. Here's the code I use to access them:
Code:
	void *plugin,*plugin2;
	int (*function)(int);
	int (*function2)(int);
	
	plugin=dlopen("/myLibs/add1.dylib", RTLD_NOW | RTLD_LOCAL);
	function=dlsym(plugin,"testFunction");
	plugin2=dlopen("/myLibs/subtract1.dylib", RTLD_NOW | RTLD_LOCAL);
	function2=dlsym(plugin2,"testFunction");
	
	NSLog(@"%d, %d",function(2),function2(2));
	NSLog(@"%d, %d",plugin,plugin2);
	
	dlclose(plugin);
	dlclose(plugin2);
The problem is, plugin and plugin2 have the same value, as do function and function2. Whichever one I load first is used twice. Why? What can I do about it?

I downloaded the source of CenterStage, but I'm lost. Searches in XCode and Spotlight reveal nothing related to dlopen or dlsym, or any reference to dylibs. Am I using the wrong loading method?
 
Well, a little more digging through Apple's docs has revealed the cause of the problem, if not the solution. To quote:

Note: Name conflicts between dynamic shared libraries are not discovered at compile time, link time, or runtime. The dlsym function uses string matching to find symbols. If two libraries use the same name for a function, the first one that matches the symbol name given to dlsym is returned.
and
To ensure that your library’s clients always have access to the symbols your library exports, the symbols must have unique names in a process’s namespace. One way is for applications to use two-level namespaces. Another is to add prefixes to every exported symbol.

I'm still trying to figure out how to use two-level namespaces. I'm trying to redo my loading code using NSLookupSymbolInImage and related functions, but haven't hammered it out yet.
 
Well, NSLookupSymbolInImage solved nothing. And from what I can tell, two-level namespacing is on by default since 10.1, so I don't think that's the problem.

I found a message on Apple's discussion groups by someone who had the same problem and then posted their solution. Apparently dynamic libaries just don't work that way, and you need to use bundles instead. I've redone everything to use bundles made with XCode's "CFBundle" template, and all is sunshine and roses now. Here's the code:
Code:
	void *plugin,*plugin2;
	int (*function)(int);
	int (*function2)(int);
	
	plugin=dlopen("/myBundles/add1.bundle/Contents/MacOS/CF Bundle Test", RTLD_NOW | RTLD_LOCAL);
	function=dlsym(plugin,"testFunction");
	plugin2=dlopen("/myBundles/subtract1.bundle/Contents/MacOS/CF Bundle Test", RTLD_NOW | RTLD_LOCAL);
	function2=dlsym(plugin2,"testFunction");
	
	NSLog(@"%d, %d",plugin,plugin2); //different values now
	NSLog(@"%d, %d",function(2),function2(2)); //finally returns "3, 1"!
	
	dlclose(plugin);
	dlclose(plugin2);

Whew! Now I just need to benchmark it to be sure there's not some crazy performance overhead.

If there is indeed a way to get dylibs to use two-level namespaces, I'd still like to hear it.
 
Back
Top