Mono AOT compilation - how to get the .so file? - c#

I am using Mono on Mac, installed with Unity.
The http://www.mono-project.com/Mono:Runtime:Documentation:AOT page states that mono compiler with aot option should generate .so file.
What I get is a dylib file.
My goal is to generate so file from the managed c# dll file.
Here is the command and output (in terminal):
Gerleis-Mac:CrazInvaders gerleim$ /Applications/Unity/MonoDevelop.app/Contents/Frameworks/Mono.framework/Versions/2.10.2/bin/mono --aot -O=all iOSBuild/Data/Managed/Assembly-CSharp.dll
Mono Ahead of Time compiler - compiling assembly /Users/gerleim/Desktop/CrazInvaders/iOSBuild/Data/Managed/Assembly-CSharp.dll
Code: 2217337 Info: 87704 Ex Info: 56841 Unwind Info: 80 Class Info: 4663 PLT: 5477 GOT Info: 364454 GOT: 35852 Offsets: 109275
Executing the native assembler: as -arch i386 -W -o /var/folders/b4/4tgynrr570zd5qdng_4ljs9m0000gn/T/mono_aot_uGBs4E.o /var/folders/b4/4tgynrr570zd5qdng_4ljs9m0000gn/T/mono_aot_uGBs4E
Executing the native linker: gcc -m32 -dynamiclib -o /Users/gerleim/Desktop/CrazInvaders/iOSBuild/Data/Managed/Assembly-CSharp.dll.dylib.tmp /var/folders/b4/4tgynrr570zd5qdng_4ljs9m0000gn/T/mono_aot_uGBs4E.o
Compiled 12759 out of 12761 methods (99%)
2 methods have other problems (0%)
Methods without GOT slots: 8190 (64%)
Direct calls: 716 (20%)
JIT time: 1427 ms, Generation time: 1045 ms, Assembly+Link time: 1712 ms.
I guess there are problems with the parameters of the assembler and linker, but I don't have options to change those (see http://mono.wikia.com/wiki/Man_mono)
(When built from the Unity IDE, Unity uses mono and aot and generates .s files for XCode/iOS.)

.sos are Linux binaries, so you'd have to compile ahead-of-time on a Linux. When you do this on OS X instead, you get a .dylib because that's an OS X library binary. Even if you had a Linux binary on your Mac, it'd be useless to you.

Related

C# command line compiler is not accepting Range [duplicate]

In old .NET we used to be able to run the csc compiler to compile a single .cs file or several files.
With .NET Core we have dotnet build that insists on having a proper project file. Is there a stand-alone command line compiler that would allow to compile source code files without having a project (and listing referenced dependencies on the same command line)?
On Linux, when I have the old csc and the new .NET Core installed, I get these timings:
[root#li1742-80 test]# time dotnet build
Microsoft (R) Build Engine version 15.3.409.57025 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
test -> /root/test/bin/Debug/netcoreapp2.0/test.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:03.94
real 0m7.027s
user 0m5.714s
sys 0m0.838s
[root#li1742-80 test]# time csc Program.cs
Microsoft (R) Visual C# Compiler version 2.3.0.61801 (3722bb71)
Copyright (C) Microsoft Corporation. All rights reserved.
real 0m0.613s
user 0m0.522s
sys 0m0.071s
[root#li1742-80 test]#
Note 7 seconds with .NET Core versus several hundred milliseconds with the old csc for the same file, Program.cs.
I'd like to be able to compile as fast with .NET Core as I used to be able with csc.
Yes, it is possible to compile a single file with csc or vbc compilers in .NET Core.
To invoke the Roslyn compiler directly it is necessary to use the command line driver csc.{exe|dll} and since Roslyn in contrast to the old csc.exe does not reference mscorlib.dll implicitly it is necessary to pass a reference to the required dependencies, i.e. System.Runtime and System.Private.CoreLib libraries and any other required references. The following listing shows how to compile the following Hello, World! program.
using System;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
}
Using WSL with Ubuntu 16.04 (Xenial Xerus) and dotnet-sdk-2.0.0 installed:
time dotnet /usr/share/dotnet/sdk/2.0.0/Roslyn/csc.exe -r:/usr/share/dotnet/shared/Microsoft.NETCore.App/2.0.0/System.Private.CoreLib.dll -r:/usr/share/dotnet/shared/Microsoft.NETCore.App/2.0.0/System.Console.dll -r:/usr/share/dotnet/shared/Microsoft.NETCore.App/2.0.0/System.Runtime.dll HelloWorld.cs
Microsoft (R) Visual C# Compiler version 2.3.2.61921 (ad0efbb6)
Copyright (C) Microsoft Corporation. All rights reserved.
real 0m0.890s
user 0m0.641s
sys 0m0.250s
ls -li
total 4
4785074604720852 -rw-rw-rw- 1 developer developer 178 Dec 7 15:07 HelloWorld.cs
11821949022487213 -rw-rw-rw- 1 developer developer 4096 Dec 7 15:13 HelloWorld.exe
The required dependencies, which are passed to the compiler, are different on different platforms, i.e. on Windows it is enough to pass System.Runtime.dll and System.Console.dll while on Ubuntu 16.04 it is necessary to pass in addition System.Private.CoreLib.dll. Different SDK versions will have Roslyn and command line drivers located in different places - the SDK layout changes between versions - and the newest 2.2.2 SDK ships with csc.dll and vbc.dll instead of csc.exe and vbc.exe. Therefore, before using this method it is necessary to check your SDK layout.
Detailed explanation
The Roslyn compiler was designed in a bit different way than the previously used csc.exe and vbc.exe compilers. First of all, Roslyn is written in C# and VB.NET and is a managed .NET application. On Windows it used mainly as a common service running in a server process VBCSCompiler.exe (.dll). However, Roslyn ships with managed command line drivers, csc.exe and vbc.exe (the latest .NET SDK versions ship with csc.dll and vbc.dll) which can be used to compile source files directly from the command line. Anyway, it is exactly what the build system in .NET does, invoking Roslyn via the command line. Running a simple dotnet csc.exe -help command will print usage information which will guide in using the compiler directly from the command line (see the last listing).
The major difference between old native compilers and Roslyn is due to the fact that the latter is a managed application is a startup time. Roslyn, even after being compiled to R2R native assemblies (Ready To Run), would need to start by loading the whole .NET framework, initializing it and then loading Roslyn assemblies and starting the compilation process. It is always a bit slower than running the native compiler, however, as can be seen from above timings, not that much slower.
There was a new documentation article added to the corefx repository describing Advanced scenario - Build and run application code with csc/vbc and CoreRun. Anyone interested can use it as a guideline how to work at the low level of .NET Core.
Microsoft (R) Visual C# Compiler version 2.3.2.61921 (ad0efbb6)
Copyright (C) Microsoft Corporation. All rights reserved.
Visual C# Compiler Options
- OUTPUT FILES -
/out:<file> Specify output file name (default: base name of
file with main class or first file)
/target:exe Build a console executable (default) (Short
form: /t:exe)
/target:winexe Build a Windows executable (Short form:
/t:winexe)
/target:library Build a library (Short form: /t:library)
/target:module Build a module that can be added to another
assembly (Short form: /t:module)
/target:appcontainerexe Build an Appcontainer executable (Short form:
/t:appcontainerexe)
/target:winmdobj Build a Windows Runtime intermediate file that
is consumed by WinMDExp (Short form: /t:winmdobj)
/doc:<file> XML Documentation file to generate
/refout:<file> Reference assembly output to generate
/platform:<string> Limit which platforms this code can run on: x86,
Itanium, x64, arm, anycpu32bitpreferred, or
anycpu. The default is anycpu.
- INPUT FILES -
/recurse:<wildcard> Include all files in the current directory and
subdirectories according to the wildcard
specifications
/reference:<alias>=<file> Reference metadata from the specified assembly
file using the given alias (Short form: /r)
/reference:<file list> Reference metadata from the specified assembly
files (Short form: /r)
/addmodule:<file list> Link the specified modules into this assembly
/link:<file list> Embed metadata from the specified interop
assembly files (Short form: /l)
/analyzer:<file list> Run the analyzers from this assembly
(Short form: /a)
/additionalfile:<file list> Additional files that don't directly affect code
generation but may be used by analyzers for producing
errors or warnings.
/embed Embed all source files in the PDB.
/embed:<file list> Embed specific files in the PDB
- RESOURCES -
/win32res:<file> Specify a Win32 resource file (.res)
/win32icon:<file> Use this icon for the output
/win32manifest:<file> Specify a Win32 manifest file (.xml)
/nowin32manifest Do not include the default Win32 manifest
/resource:<resinfo> Embed the specified resource (Short form: /res)
/linkresource:<resinfo> Link the specified resource to this assembly
(Short form: /linkres) Where the resinfo format
is <file>[,<string name>[,public|private]]
- CODE GENERATION -
/debug[+|-] Emit debugging information
/debug:{full|pdbonly|portable|embedded}
Specify debugging type ('full' is default,
'portable' is a cross-platform format,
'embedded' is a cross-platform format embedded into
the target .dll or .exe)
/optimize[+|-] Enable optimizations (Short form: /o)
/deterministic Produce a deterministic assembly
(including module version GUID and timestamp)
/refonly Produce a reference assembly in place of the main output
/instrument:TestCoverage Produce an assembly instrumented to collect
coverage information
/sourcelink:<file> Source link info to embed into PDB.
- ERRORS AND WARNINGS -
/warnaserror[+|-] Report all warnings as errors
/warnaserror[+|-]:<warn list> Report specific warnings as errors
/warn:<n> Set warning level (0-4) (Short form: /w)
/nowarn:<warn list> Disable specific warning messages
/ruleset:<file> Specify a ruleset file that disables specific
diagnostics.
/errorlog:<file> Specify a file to log all compiler and analyzer
diagnostics.
/reportanalyzer Report additional analyzer information, such as
execution time.
- LANGUAGE -
/checked[+|-] Generate overflow checks
/unsafe[+|-] Allow 'unsafe' code
/define:<symbol list> Define conditional compilation symbol(s) (Short
form: /d)
/langversion:<string> Specify language version mode: ISO-1, ISO-2, 3,
4, 5, 6, 7, 7.1, Default, or Latest
- SECURITY -
/delaysign[+|-] Delay-sign the assembly using only the public
portion of the strong name key
/publicsign[+|-] Public-sign the assembly using only the public
portion of the strong name key
/keyfile:<file> Specify a strong name key file
/keycontainer:<string> Specify a strong name key container
/highentropyva[+|-] Enable high-entropy ASLR
- MISCELLANEOUS -
#<file> Read response file for more options
/help Display this usage message (Short form: /?)
/nologo Suppress compiler copyright message
/noconfig Do not auto include CSC.RSP file
/parallel[+|-] Concurrent build.
/version Display the compiler version number and exit.
- ADVANCED -
/baseaddress:<address> Base address for the library to be built
/checksumalgorithm:<alg> Specify algorithm for calculating source file
checksum stored in PDB. Supported values are:
SHA1 (default) or SHA256.
/codepage:<n> Specify the codepage to use when opening source
files
/utf8output Output compiler messages in UTF-8 encoding
/main:<type> Specify the type that contains the entry point
(ignore all other possible entry points) (Short
form: /m)
/fullpaths Compiler generates fully qualified paths
/filealign:<n> Specify the alignment used for output file
sections
/pathmap:<K1>=<V1>,<K2>=<V2>,...
Specify a mapping for source path names output by
the compiler.
/pdb:<file> Specify debug information file name (default:
output file name with .pdb extension)
/errorendlocation Output line and column of the end location of
each error
/preferreduilang Specify the preferred output language name.
/nostdlib[+|-] Do not reference standard library (mscorlib.dll)
/subsystemversion:<string> Specify subsystem version of this assembly
/lib:<file list> Specify additional directories to search in for
references
/errorreport:<string> Specify how to handle internal compiler errors:
prompt, send, queue, or none. The default is
queue.
/appconfig:<file> Specify an application configuration file
containing assembly binding settings
/moduleassemblyname:<string> Name of the assembly which this module will be
a part of
/modulename:<string> Specify the name of the source module
The accepted answer refers to using System.Private.CoreLib.dll which is a runtime assembly and is not recommended. From C# compiler developer's comments:
Attempting to use runtime assemblies as compile references is not
supported and frequently breaks do to the structure of the runtime
assemblies
Instead, reference assemblies should be used. Reference assemblies are fetched from NuGet during dotnet build and a full csc invocation can be seen when running the dotnet CLI with increased verbosity (dotnet build --verbosity normal). One might see references to assemblies like System.Runtime.dll and System.Console.dll from microsoft.netcore.app NuGet package.
However, for a simple single file Hello, World! compilation, one can reference netstandard.dll which for .NET Core 2.2 exists under <installation-directory>/sdk/2.2.203/ref/netstandard.dll.
Note that in order to run the resulting executable with dotnet HelloWorld.exe a corresponding HelloWorld.runtimeconfig.json has to be created, containing the targeting .NET Core runtime version. We will simplify it by creating a common runtimeconfig for console (NETCoreApp) apps, and an accompanying alias csc_run.
Add the following in your ~/.profile:
#!/usr/bin/env sh
# IMPORTANT: make sure dotnet is present in PATH before the next lines
# prepare csc alias
DOTNETDIR=$(dirname $(dirname $(dotnet --info | grep "Base Path" | cut -d' ' -f 6)))
CSCPATH=$(find $DOTNETDIR -name csc.dll -print | sort | tail -n1)
NETSTANDARDPATH=$(find $DOTNETDIR -path *sdk/*/ref/netstandard.dll ! -path *NuGetFallback* -print | sort | tail -n1)
alias csc='dotnet $CSCPATH /r:$NETSTANDARDPATH '
# prepare csc_run alias
if [ ! -w "$DOTNETDIR" ]; then
mkdir -p $HOME/.dotnet
DOTNETDIR=$HOME/.dotnet
fi
DOTNETCSCRUNTIMECONFIG=$DOTNETDIR/csc-console-apps.runtimeconfig.json
alias csc_run='dotnet exec --runtimeconfig $DOTNETCSCRUNTIMECONFIG '
if [ ! -f $DOTNETCSCRUNTIMECONFIG ]; then
DOTNETRUNTIMEVERSION=$(dotnet --list-runtimes |
grep Microsoft\.NETCore\.App | tail -1 | cut -d' ' -f2)
cat << EOF > $DOTNETCSCRUNTIMECONFIG
{
"runtimeOptions": {
"framework": {
"name": "Microsoft.NETCore.App",
"version": "$DOTNETRUNTIMEVERSION"
}
}
}
EOF
fi
Exit and start shell to reload profile (or source it . ~/.profile if you don't want to leave the current session).
Usage:
cat << EOF > ./Program.cs
class Program
{
static void Main() => System.Console.WriteLine("Hello World!");
}
EOF
csc -out:hwapp.exe Program.cs
csc_run hwapp.exe
# Hello World!
The compiler can be directly invoked using
$ /usr/local/share/dotnet/sdk/2.0.0/Roslyn/RunCsc.sh
However, this particular command may not be very helpful without a supporting project infrastructure because you'd need to pass in all .NET Core or .NET Standard reference assemblies in manually, which is normally handled by the SDK and NuGet. You'll get errors like this:
$ /usr/local/share/dotnet/sdk/2.0.0/Roslyn/RunCsc.sh Program.cs
Microsoft (R) Visual C# Compiler version 2.3.2.61921 (ad0efbb6)
Copyright (C) Microsoft Corporation. All rights reserved.
Program.cs(1,7): error CS0246: The type or namespace name 'System' could not be found (are you missing a using directive or an assembly reference?)
Program.cs(5,11): error CS0518: Predefined type 'System.Object' is not defined or imported
Program.cs(7,26): error CS0518: Predefined type 'System.String' is not defined or imported
Program.cs(7,16): error CS0518: Predefined type 'System.Void' is not defined or imported
This is the scripts:
#!/bin/bash
#dotnethome=`dirname "$0"`
dotnethome=`dirname \`which dotnet\``
sdkver=$(dotnet --version)
fwkver=$(dotnet --list-runtimes | grep Microsoft.NETCore.App | awk '{printf("%s", $2)}')
dotnetlib=$dotnethome/shared/Microsoft.NETCore.App/$fwkver
if [ "$#" -lt 1 ]; then
dotnet $dotnethome/sdk/$sdkver/Roslyn/bincore/csc.dll -help
echo dotnethome=$dotnethome
echo sdkver=$sdkver
echo fwkver=$fwkver
echo dotnetlib=$dotnetlib
exit 1
fi
progfile=$1
prog="${progfile%.*}"
echo -r:$dotnetlib/netstandard.dll > /tmp/$prog.rsp
echo -r:$dotnetlib/System.dll >> /tmp/$prog.rsp
echo -r:$dotnetlib/Microsoft.CSharp.dll >> /tmp/$prog.rsp
for f in $dotnetlib/System.*.dll; do
echo -r:$f >> /tmp/$prog.rsp
done
dotnet $dotnethome/sdk/$sdkver/Roslyn/bincore/csc.dll -out:$prog.dll -nologo #/tmp/$prog.rsp $*
if [ $? -eq 0 ]; then
if test -f "$prog.dll"; then
if ! test -f "$prog.runtime.config"; then
echo "{
\"runtimeOptions\": {
\"framework\": {
\"name\": \"Microsoft.NETCore.App\",
\"version\": \"$fwkver\"
}
}
}" > "$prog.runtimeconfig.json"
fi
fi
fi
echo /tmp/$prog.rsp:
cat /tmp/$prog.rsp
rm /tmp/$prog.rsp
In short, it's not supported without a predefined project.
But #Andrew's comment shows that it's still possible if you are ready to list every single dependency including implicit system ones in command line options.
From error CS0518: Predefined type 'System.Object' is not defined or imported #12393:
At the moment, we have no plan to make it easy to use csc.exe in this
manner. The guidance is to use the dotnet CLI tooling for the time
being. Even if some modification where to be made here, it would be on
the framework to provide unified and/or simplified reference
assemblies for the compiler. The compiler will never have more
complicated type or assembly resolution than it does now (by design).
See also the closed Make it possible to invoke the compiler directly #7689.

Decompilation and Protection of Mkbundled CLI Image of .NET Executable

I have complied a .net executable(GTK Based UI) using mkbundle by statically including mono runtime using
mkbundle --static hello.exe -o --deps hello
I got a CLI Image.Is this CLI Image Native Code like a Complied C Program?Can it be disassembled easily like any other normal .NET Executable? If yes is there a way to make decompilation Hard? Is Obfuscation before mkbundling an option? and Can i do AOT(Ahead of Time) Compilation? Please throw some light on this.

GCC - How to statically link a static mono bundle

I have a .NET application that I want to port to an embedded ARM7 based Linux system. The target is a locked down system running Busybox and I have no write access to the /lib directory (which b.t.w. is empty).I do however have write access to a separate mount point with enough space for my application.
My idea is to compile a static application on a device with the same architecture and copy the binary to the target device. I am using a Beaglebone black for compilation.
How can I compile my .NET application into a 100% statically linked binary?
I am aware of the licensing restrictions of Mono (I have a commercial license).
To keep it simple, my application looks like this.
/// hello.cs
using System;
internal class Program
{
private static void Main()
{
Console.WriteLine("hello");
}
}
Step 1: Compile cs code
$ mcs hello.cs
Step 2: Bundle compiled binary with Mono and output to c code
$ mkbundle -c -o hello.c -oo bundles.o --deps hello.exe --static
OS is: Linux
Note that statically linking the LGPL Mono runtime has more licensing restrictions than
dynamically linking.
See http://www.mono-project.com/Licensing for details on licensing.
Sources: 1 Auto-dependencies: True
embedding: /root/csharp/hello.exe
embedding: /usr/local/lib/mono/4.5/mscorlib.dll
Compiling:
as -o bundles.o temp.s
Step 3: Compile resulting c code
cc -o hello -Wall `pkg-config --cflags mono-2` hello.c bundles.o `pkg-
config --libs-only-L mono-2` -Wl,-Bstatic -lmono-2.0 ./Lib2/libm.a ./Lib2/librt.a ./Lib2/libdl.a
./Lib2/libpthread.a ./Lib2/libgcc.a ./Lib2/libc.a -Wl,-Bdynamic ./Lib2/ld-linux-armhf.so.3
***** Warning message receieved (example):
/media/mono-3.10.0/mono/io-layer/sockets.c:992: warning: Using 'gethostbyname' in statically
linked applications requires at runtime the shared libraries from the glibc version used for
linking
Step 4: Check dependencies
$ ldd hello
/lib/ld-linux-armhf.so.3 (0xb6f92000)
libgcc_s.so.1 => /lib/arm-linux-gnueabihf/libgcc_s.so.1 (0xb6f5e000)
libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6e7f000)
At this point, the application works on my development system but not on the target system. I am guessing due to missing libraries as the error message I get is File not found.. How can I link the remaining libraries statically?
As an experiment, I've tested a similar approach with a native C application
/// hello.c
#include <stdio.h>
int main()
{
printf("hello\n");
return 0;
}
Step 1: Compile with dynamic links
$ cc hello.c -o hello
Step 2: Check dependencies
$ ldd hello
libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6e26000)
/lib/ld-linux-armhf.so.3 (0xb6f14000)
As expected, this application does not work on the target system.
Step 3: Compile with static links
$ cc hello.c -o hello -static
Step 4: Check dependencies
$ ldd hello
not a dynamic executable
This application works on my target system.
I am a total newbie on Linux systems in general and have spent many hours trying to find a solution. What worries me a bit is that I'm not even sure if it's solvable :). Any help would be highly appreciated!
Note: If it's impossible to link all libraries statically (for any reason), a solution where these are placed in the same folder as the main application would be totally acceptable. In such a scenario, how would I relink the libraries to ./?

Mono native binary bundle fails to load libc in newer Linux kernels

I'm attempting to build a C# Mono application as a native binary so it can be run on Linux systems without any dependencies (Such as Mono).
To ensure some backwards compatibility I am using Ubuntu 12.04 to build the native binary. I had to build Mono 3.x from source as Ubuntu 12.04 only has packages for Mono 2. I documented that process here, if you're interested.
I am using mkbundle to bundle the Mono runtime and its dependencies:
mkbundle -c -o WFTOLauncherNative.c -oo bundles.o --static --deps WFTOLauncher.exe Open.NAT.dll
I am using the cc compiler like so:
cc -o WFTOLauncherNative.exe WFTOLauncherNative.c bundles.o -l:libmono-2.0.a -l:libgdiplus.a -lc -lpthread -lrt -lm -ldl -I /usr/local/include/mono-2.0/
This works on the system I built it on (Ubuntu 12.04). However on Ubuntu 14.04 with no Mono installation I get the following error:
Unhandled Exception:
System.TypeInitializationException: An exception was thrown by the type initializer for System.Windows.Forms.XplatUI ---> System.DllNotFoundException: libc
ldd of the application:
scott#ubuntu:/media/strichnet/WFTOLauncher/bin/Release/LinuxNative$ ldd WFTOLauncherNative.exe
linux-vdso.so.1 => (0x00007fffd0ffe000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa6c794a000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa6c7d27000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa6c772c000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fa6c7523000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa6c721d000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa6c7019000)
My hunch so far is Mono is at fault here - I think it relies on the Mono DllMap configs to map from libc to libc.so.6, but its failing. There is a similar question on SO and the answer here looks promising, but as my goal is to create an independent native assembly its not a solution I can accept.
I have copied the default Mono 3 config file from /etc/mono/config to the binary directory and renamed it to WFTOLauncher.exe.config and WFTOLauncherNative.exe.config (Just in case). This has not helped.
Full Mono debug trace here: https://gist.github.com/strich/e71b23421cdbe941b4f4
The root cause of the problem was that Mono was looking for libc.so where the OS only had libc.so.6. Mono needs a DllMap config file to understand how to translate this.
The solution to the problem was to add the default Mono3 DllMap config file to the same directory as my binary. Sadly it appears that Mono doesn't cache the DllMap globally for the process, so I had to make multiple duplicate copies of the config file under the different names of the various modules that were being called. For example:
Mono.Posix.dll.config
System.Drawing.dll.config
System.Windows.Forms.dll.config

How to make "mkbundle --deps" option working with mono 3.2.3

I am trying to bundle the application with mono 3.2.3 to a stand-alone executable. To do so, I am following this guideline. After declarating variables:
mono_version="3.2.3"
export MONO=/cygdrive/c/progra~2/Mono-$mono_version
machineconfig=$PROGRAMFILES\\Mono-$mono_version\\etc\\mono\\4.5\\machine.config
export PATH=$PATH:$MONO/bin
export PKG_CONFIG_PATH=$MONO/lib/pkgconfig
export CC="i686-pc-mingw32-gcc -U _WIN32"
mkbundle --deps command cannot localize referenced assemblies:
Unhandled Exception:
System.IO.FileNotFoundException: Could not load file or assembly 'gtk-sharp' or
one of its dependencies. The system cannot find the file specified.
File name: 'gtk-sharp'
performing exactly the same operation with mono 2.10.9:
mono_version="2.10.9"
export MONO=/cygdrive/c/progra~2/Mono-$mono_version
machineconfig=$PROGRAMFILES\\Mono-$mono_version\\etc\\mono\\4.0\\machine.config
export PATH=$PATH:$MONO/bin
export PKG_CONFIG_PATH=$MONO/lib/pkgconfig
export CC="i686-pc-mingw32-gcc -U _WIN32"
mkbundle --deps --machine-config "$machineconfig" -c UI.exe
gives positive result:
OS is: Windows
WARNING:
Check that the machine.config file you are bundling
doesn't contain sensitive information specific to this machine.
Sources: 3 Auto-dependencies: True
embedding: C:\users\piotr\desktop\authoringtool\UI\bin\debug\UI.exe
config from: C:\users\piotr\desktop\authoringtool\UI\bin\debug\UI.exe.config
embedding: C:\PROGRA~2\MONO-2~1.9\lib\mono\gac\gtk-sharp\2.12.0.0__35e10195dab3c99f\gtk-sharp.dll
embedding: C:\PROGRA~2\MONO-2~1.9\lib\mono\gac\glib-sharp\2.12.0.0__35e10195dab3c99f\glib-sharp.dll
.
.
.
embedding: C:\PROGRA~2\MONO-2~1.9\lib\mono\4.0\Mono.Posix.dll
Machine config from: C:\Program Files (x86)\Mono-2.10.9\etc\mono\4.0\machine.config
Compiling:
as -o temp.o temp.s
Does anyone know the reason of such behavior? I'm using 64-bit version of windows 7 and the Cygwin I found on the official website. The code was compiled and tested on Xamarin Studio 4.2 and Visual Studio 2010.
Howto for mkbundle on cygwin + mingw
Tested with mono 4.0.3
In mono 4.0.3, mkbundle works but it can be tricky to make it work.
First, check your setup:
Install Mono/GTK# in a path that doesn't contains spaces (ie not Program Files then)
Setup a MinGw/Cygwin working compile chain (as the one for
compiling mono on windows).
Define the mandatory environment variables for mkbundle:
mingw compiler location should be in the Windows PATH (used by cmd)
pkg-config should also be in the Windows PATH
Use the following cygwin script (it can be adapted to run on cmd)
# M_PREFIX refers to Mono installation
# For more information, search for prefix installation in Mono documentation
M_PREFIX='/cygdrive/c/Mono'
export DYLD_FALLBACK_LIBRARY_PATH=${M_PREFIX}/lib:${DYLD_FALLBACK_LIBRARY_PATH}
export LD_LIBRARY_PATH=${M_PREFIX}/lib:${M_PREFIX}/lib/mono/4.5:${LD_LIBRARY_PATH}
export C_INCLUDE_PATH=${M_PREFIX}/include:${C_INCLUDE_PATH}
export ACLOCAL_PATH=${M_PREFIX}/share/aclocal:${ACLOCAL_PATH}
export PKG_CONFIG_PATH=${M_PREFIX}/lib/pkgconfig:${PKG_CONFIG_PATH}
# Here we added the system32 to make cmd available to mkbundle
# /usr/bin is the default location for mingw
export PATH=${M_PREFIX}/bin:/cygdrive/c/Windows/system32:/usr/bin:${PATH}
export CC="i686-pc-mingw32-gcc -U _WIN32"
Then you can run:
mkbundle --deps --keeptemp my.exe my.dll -o bundled.exe
Notes:
- Copy mono-2.0.dll in the application directory as it should be distributed along the bundled exe
cp ${M_PREFIX}/bin/mono-2.0.dll .
if -z is used, zlib1.dll should be copied as well. (note that gcc invocation change also). You may need more dll depending on your usage of framework features (not exhaustive list : libglib*.dll, libgmodule*.dll, libgthread*.dll, iconv.dll, intl.dll)
-c is used to generate only stub.
You must specify all exe and dll that are needed for the bundle.
--keeptemp will keep temp.c and temp.s which could come in handy if mkbundle fail on gcc invocation.
If you want to invoke gcc by hand (and it may be needed):
i686-pc-mingw32-gcc -U _WIN32 -g -o output.exe -Wall temp.c $(pkg-config --cflags --libs mono-2) temp.o
For Console Applications
To make console application work you must remove -mwindows from the gcc command. To do that, you must invoke pkg-config --cflags --libs mono-2 and remove the -mwindows.
You should obtain something like that afterwards:
i686-pc-mingw32-gcc -g -o output.exe -Wall temp.c -mms-bitfields -IC:/Mono/include/mono-2.0 -mms-bitfields -LC:/Mono/lib -lmono-2.0 -lws2_32 -lpsapi -lole32 -lwinmm -loleaut32 -l advapi32 -lversion temp.s
Anyone can improve mkbundle
mkbundle is an open sourced C# console application (on mono github)
so it can be easily modified and recompiled depending on your needs.
Reading the code could also be helpful to understand how it works underneath.
cmd usage as the different commands used by mkbundle are hard coded so it would benefit from some parametrization enhancement.

Categories