This tech-note describes how to use and package a DLL from within your plugin, e.g. a DLL that is not normally installed on the host machine. (This plugin will use the term DLL generically to refer to windows DLLs, Linux shared objects, and OS X dylibs.)
Note that besides using a DLL that ships with your plugin, you do have a few other options:
- If the library is available in static library form, you can simply link it into your plugin. While this technique makes your plugin's code larger, it also makes distribution significantly simpler.
- If the library ships with the system (or is required for X-Plane to operate), you can just use it and assume it is installed. For example, you can just assume that OpenGL is around, because without it X-Plane won't even start.
- You can require users to install third party DLLs system wide, but we strongly discourage this. A user doesn't need admin privileges to install X-Plane or your plugin, and X-Plane doesn't leave any other files on the file system.
- If you load symbols from a DLL explicitly with the OS specific DLL loader (dlopen/dlsym for OS X/Linux and LoadLibrary/GetProcAddress on Windows) you can load any library from any location, and therefore shipping a DLL just means having it in a known file location. This technique has the advantage of being able to search for a DLL under multiple names and locations and being able to easily cope with its being missing, but it is also more work up-front. (X-Plane uses this technique to link to OpenAL.)
We recommend shipping your plugin in a fat plugin structure (a directory with 3 DLLs, one for each platform) and packaging required DLLs for other operating systems into the fat plugin. This way the fat plugin installation will contain all required DLLs.
We do not recommend putting DLLs into a sub-directory inside your plugin; although it is possible to do this, support for this technique is varied among the OSes and beyond the scope of this tech note.
Using a DLL on Windows
On Windows, X-Plane loads your plugin with the altered search path. This means that DLLs in the same directory as your plugin will load automatically.
We do not recommend altering the DLL search path; this is not necessary and can cause problems for other plugins in the system.
For Linux, you need to do two things to load a shared object that is positioned relative to your plugin.
- Use the -rpath linker option to encode a custom search path into your plugin.
- Use the $ORIGIN "wild-card" token in that search path to represent your plugin's current directory. For example:
NOTE: that syntax applies to invoking the linker command right from the terminal. From a Makefile, use this directive:
For OS X, the technique of using a dylib 'next to' your plugin is similar to Linux, but with two additional wrinkle:
- dylibs on OS X have an install location built into the dylib (e.g. the 'ID name', visible with otool -D). When you link against a library, that's the path that your plugin will look in, regardless of where the dylib is located at link time! (So it's not good enough to link against foo.dylib in your plugin's directroy if foo.dylib contains /usr/lib/foo.dylib as its install path!)
- on OS X -rpath (on your plugin) only applies to dylibs whose install path starts with @rpath, e.g. dylibs that were meant to be relocatable.
So to use a dylib on OS X, you have to compile the dylib with an @rpath/name.dylib id and then you can use -rpath to find it. On OS X, $ORIGIN is replaced with @loader_path. (GNU make and bash users will breath a sigh of relief at not needing to get '$' into your path.)
Thus using a dylib on OS X with your plugin is a two-step process:
- Compile the dylib with
- Compile the plugin with an rpath directive, e.g.
This post contains examples of using these options.
It should also be noted that you can use the command line tool _install_name_tool to change a dylib's ID name, e.g.
install_name_tool -id @rpath/name.dylib my_libs/name.dylib