A Linux toolchain I'm managing contains a legacy .Net application. This is fine on Ubuntu, where an official Mono runtime environment to run .Net applications is available. But I would like to run my toolchain also on other Linux distributions (e.g. RHEL/Rocky Linux) without official Mono support. And I'd rather keep the list of runtime dependencies as small as possible, i.e. I neither want to depend on 3rd party Mono builds nor on Docker.
Theoretically, my scenario is well supported: Mono's mkbundle
is able to package any .Net application into a platform-specific binary that does not rely on an installed Mono runtime. However, it does introduce a dependency on a libmono-native.so
(this is a dynamic dependency, so it doesn't show up in the output of ldd
) that I haven't been able to fulfill.
test.cs
using System;
public class HelloWorld
{
public static void Main(string[] args)
{
Console.WriteLine ("Hello Mono World");
}
}
I compiled it to a .Net executable via csc hello.cs
to a test.exe
. This executable runs fine with Mono, but - obviously - not without a Mono runtime.
mkbundle --cross mono-6.6.0-ubuntu-18.04-x64 -o test test.exe
This creates a native test
ELF binary (I pretty much just selected an arbitrary x64 cross-compilation target, since neither RHEL/Rocky Linux nor any newer Ubuntu targets are available). This test
runs on Ubuntu (I tested "Jammy" 22.04) when a Mono runtime is installed, but fails with a System.DllNotFoundException: /libmono-native.so
on systems without an Mono runtime.
So, I tried to embed that library as well via mkbundle --cross mono-6.6.0-ubuntu-18.04-x64 --library /usr/lib/libmono-native.so -o test test.exe
, but this fails on all tested systems (both Ubuntu and Rocky Linux) with
Error loading shared library: /tmp/mono-bundle-SSDDWc/libmono-native.so /tmp/mono-bundle-SSDDWc/libmono-native.so: cannot open shared object file: No such file or directory
mkbundle --static -L /usr/lib/mono/4.8-api -o test test.exe
This likewise creates a test
ELF binary, but executing it crashes with a SEGFAULT already on the Ubuntu host system. gdb
output:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0 0x0000000000000000 in ?? ()
#1 0x000055555556c314 in mono_mkbundle_init () at temp.c:147
#2 0x000055555556c652 in main (argc=1, argv=0x7fffffffddd8) at temp.c:224
Am I doing something wrong, or is my approach simply not possible?
There are two completely independent generations of implementations of the .NET framework:
Mono receives little development support these days, and it's possible that building native applications is broken in Mono and won't be fixed. However, .Net Core essentially supersedes it and is available in the official package repositories of many Linux distributions (e.g. dotnet-sdk-7.0
for Ubuntu).
With .NET Core, native application for the host platform can be built
by executing dotnet publish --configuration=release --self-contained
from the application's source code root folder (the one that contains the Visual Studio Solution1). Binaries for different platforms can be generated by appending the -r <platform>
parameter. The native application can be packaged as a single executable (instead of as a set of libraries and executables) by adding the
<PublishSingleFile>true</PublishSingleFile>
configuration line to the corresponding .csproj
/.vbproj
project file. Optionally, this single executable can be trimmed to reduce its size by also adding the
<PublishTrimmed>true</PublishTrimmed>
configuration line - but this only works for a subset of .NET language features.