I'm using mkbundle and trying to create an embedded version of a little program IdaTester that uses Isis2. That system in turn uses features from Mono that depend on MonoPosixHelper
My problem is that mkbundle doesn't recognize the dependency and I end up with an executable that still needs to dynamically link against ~/bin/lib/libMonoPosixHelper.so, causing problems when I move this executable to a system where I don't have Mono installed. In effect, the bundle is missing one of the things it should be statically linked against.
My executable does work, but only if I make sure to run it only on machines that have the dynamic library in the "right place". This defeats the purpose of an embedded executable... I was hoping to be able to hand people this program as a kind of server they could put anywhere and launch as a binary, and obviously if they need to install the library for this to work, the server isn't exactly standalone!
I see how to force mkbundle to include any dll files the program depends upon, but MonoPosixHelper doesn't exist as a dll; this is a Linux-only library and exists only as a shared library. Does anyone know of a way to "force" the bundle to embed it statically?
In case this helps, my little compile script is as follows:
mcs -debug+ IdaTester.cs Isis.cs -r:System.dll -r:Microsoft.CSharp.dll -r:Mono.Posix.dll
mkbundle --static -o IdaTester IdaTester.exe --deps
I then run IdaTester; this works on platforms where the libMonoPosixHelper library can be found, but will fail at runtime when trying to dynamically load that library if running on a platform where libMonoPosixHelper hasn't been installed...
One needs to distribute libMonoPosixHelper.so with the application and change the dll map to make this work.
Background on the problem - Library is Loaded at Runtime
libMonoPosixHelper is not statically linked but searched for and loaded as a P/Invoke call, such as the example below:
[DllImport ("MonoPosixHelper")]
static extern int zipClose (ZipHandle handle, string globalComment);
That is, it is only requested at runtime, not compile time, and so cannot be linked in ahead of time.
Fixing it - Distributing libMonoPosixHelper.so
Four steps are required.
To perform each:
1. Copy libMonoPosixHelper to the directory you will be distributing the program with.
libMonoPosixHelper is usually located in the lib folder, simply copy it to the folder you will be making a tarball out of.
cp $MONO_ROOT/lib/libMonoPosixHelper.so ~/MY_PROGRAM/
2. Update the DllMap config file to avoid a hard coded location.
This is the critical bit to avoid the hard coded paths issue. We need to embed a config file with mkbundle that does not specify the path. To do this, first find the mono config file, and also copy that to the local directory
cp $MONO_ROOT/etc/mono/config ~/MY_PROGRAM/config
Now we need to alter this file to remove the specific path for the dll, open it with your favorite editor and change the paths to avoid the specific prefix:
<dllmap dll="MonoPosixHelper" target="MACHINE_SPECIFIC/lib/libMonoPosixHelper.dylib" os="!windows" />
to
<dllmap dll="MonoPosixHelper" target="libMonoPosixHelper.dylib" os="!windows" />
3. Embed the config file with mkbundle
Add the following option to your mkbundle command to embed the newly edited config file:
--config MY_PROGRAM/config
4. Add the path with libMonoPosixHelper.so to the LD_LIBRARY_PATH on the install machine.
Now you can zip up your mkbundled executable, libMonoPosixHelper.so and any other files for distribution. When unzipped and run on a machine, dlopen will now look for libMonoPosixHelper.so just like any other dll. So simply add whatever directory contains your distributed version of libMonoPosixHelper to their LD_LIBRARY_PATH environmental variable
As far as I can tell, the best option available to me is either to build a non-shared Mono library containing the same methods as are currently found in MonoPosixHelper.so, or to provide a copy of MonoPosixHelper.so as a component to be installed in the same folder as my server. Neither seems ideal: the former forces me to "reach into" the Mono distribution, which creates a longer term maintenance issue, while the latter forces me into a more complex distribution and installation mode. But it seems that once one generates a shared library, you simply can't statically link against that version of the library; the Linux loader just doesn't treat such a thing as a library in the way it handles more standard libraries.
In contrast, if I do generate a standard library from the same .o files, the loader will be happy to statically link against it, and because mxbundle ultimately runs cc and hence uses the standard ld, that option would work for me. So I guess that's the answer to my question.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With