79578262

Date: 2025-04-16 23:32:25
Score: 0.5
Natty:
Report link

Ok... Still no answer. Fortunately I can now provide it for those who's looking for it. First I'll try to tell step by step what you need, and in the end I'll answer all the questions I asked.

Ready working example of embedding on Windows, Linux and Android

I created a repository where I solved some problems with embedding on some platforms, and provided a template project to create a Mono-embedded app where you can write cross-platform C++ and C# code and build it for all the mentioned platforms. You can take a look at it here: NativeMonoEmbedded-App.

How the runtime loads everything and what you should provide for it

Mono CLR

First you should link against the runtime native library (AKA the runtime, Mono CLR, the libcoreclr (even though this is Mono)). It's basically the runtime itself containing the known GC, JIT and other things. You also need Mono API include headers to communicate with the runtime.

You may find different names for this library:

Framework libraries

Framework libraries (or runtime libraries) are kind of Standard Library of .NET, but in this context it's typically called FCL, BCL or something other like this. Basically it contains all declarations and the implementation of the standard library.

It consists from:

  1. System.Private.CoreLib.dll - the internal implementation of the core library which contains native code unlike other framework libs.
  2. System.*.dll, Microsoft.*.dll, WindowsBase.dll, mscorlib.dll and netstandard.dll and others - framework libraries containing managed code. It contains public API interface as well as some implementation details.
  3. Additional native libraries - required by framework libraries.
CoreLib (System.Private.CoreLib.dll)

When you try to initialize the runtime by one of examples you can find on the internet, the runtime will first try to find the CoreLib. It's the main part of framework libs. It definitely contains native code, so should not be shared between multiple platforms/architectures.

If it's missing, the runtime will print something like this to the console:

* Assertion at D:\a\_work\1\s\src\mono\mono\metadata\assembly.c:2718, condition `corlib' not met

So you need to place it either near the executable (as all other framework libs), or you should set assemblies path via mono_set_assemblies_path() or the MONO_PATH env variable to tell the runtime where to look for ANY assemblies (including yours). If you have several paths, you separate them with path separators (OS specific: ; - on Windows, : - Linux, Android).

Other framework libs

Besides the System.Private.CoreLib.dll, there's other managed framework libs. It's DLLs like System.Runtime.dll, System.Console.dll, mscorlib.dll, netstandard.dll, Microsoft.CSharp.dll. Not all of these may be actually required and loaded. It depends on the dependency chain and on what functionality you use.

There's also native libs that's required by framework libs. For Windows it may be msquic.dll, System.IO.Compression.Native.dll, Microsoft.DiaSymReader.Native.amd64.dll. On Linux it's libSystem.Native.so, libSystem.IO.Compression.Native.so, libSystem.Globalization.Native.so, libSystem.Net.Security.Native.so and so on. On Android it's almost the same as on Linux but you may also find JARs like: libSystem.Security.Cryptography.Native.Android.jar.

Such native libs must placed in the folder with all managed framework libs, or near the executable. BUT on Android native libs can be also in the libs APK folder.

Mono components

Completely optional components that's available on Linux and Android, but not Windows.

One added .NET library I used was not working on Android if I didn't add libmono-component-marshal-ilgen.so which might have performed some IL-code generation. So sometimes you may need one of those components.

Next is your code

Everything required by the runtime is ready. Now place your managed and native libs. You can again place them near the executable, or in the folder added to assemblies path. Native libs you use through P/Invoke are searched near the executable, and also near the assembly containing the P/Invoke method declaration.

Though when you load libraries using NativeLibrary.Load(), LoadLibrary() or dlopen(), other rules apply. Then you need to place it near the executable, or modify search paths with AddDllDirectory(), or RPATH on Linux.

Learn the structure

I advise you to look at NuGet packages named Microsoft.NETCore.App.Runtime.Mono.*. They contain necesarry built runtime files for all platforms and architectures. From there you can learn what may be needed.

Download archives and look into it. In the runtimes/[arch]/lib/net[version]/ folder you'll find all managed framework libs, they should contain only managed code. Beside the *.DLLs, there's also Microsoft.NETCore.App.deps.json and Microsoft.NETCore.App.runtimeconfig.json. You don't need them.

runtimes/[arch]/native/ contains native code. Here you find the runtime native lib, the CoreLib, and other important native libs required by the framework libs. Although there can be also hostfxr and hostpolicy native libraries, but you don't need them (this is needed for CoreCLR hosting). There's also the include folder with the Mono API.

Let's now answer my questions

As I undertstand those components are optional.

Yes.


So what is required?

The runtime native lib (libcoreclr.so), the CoreLib, and the other framework libs (managed and native).


I need to place the libcoreclr.so and System.Private.CoreLib.dll near the executable?

Yes, but it depends. Typically if you statically link the coreclr.dll (or libcoreclr.so), you place all native libs near the executable. On Windows you could also use AddDllDirectory(), and on Linux you could set RPATH to add shared lib search paths, so then you can place coreclr.dll/libcoreclr.so in other places. BUT you of course can dynamically load shared libs and then get pointers to necessary functions, which also allows you to place the runtime lib elsewhere.

System.Private.CoreLib.dll can be anywhere. It always searched near the executable. But more paths can be added to search for.


Or there's more files I need to find somewhere in the build artifacts folder?

Yes. Just corelib is not enough. As I said you need other framework libs like System.Runtime.dll, System.Console.dll and so on.


Also another question: so the modern Mono is just a slimmer version of the CoreCLR, but communication between my native executable and the runtime happens via Mono API? Is this understanding correct?

Yes, Mono is kind of slimmer version of CoreCLR. There's separate code for the Mono runtime which is essentially works almost like the old Mono (with its JIT and GC). Though the frameworks libs are shared between both runtimes (some specific overrides may be also present for both). And yes, your understanding is mostly correct.


Also another question: there's no static library of the CoreCLR, I have to link it dynamically? There's really no way to statically link it?

I still don't know, maybe there should be a compilation option for this. Anyway I decided to use shared libs.

Reasons:
  • Blacklisted phrase (1): another question
  • Blacklisted phrase (0.5): I need
  • Whitelisted phrase (-2): I solved
  • Contains signature (1):
  • Long answer (-1):
  • Has code block (-0.5):
  • Contains question mark (0.5):
  • Self-answer (0.5):
  • Low reputation (0.5):
Posted by: purepelmen