initial commit

This commit is contained in:
2026-06-08 01:14:26 +05:00
commit 30724de4d8
19 changed files with 781 additions and 0 deletions

23
.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
# build results
bin/
obj/
# IDE files
.vs/
.vshistory/
.editorconfig
*.user
*.vcxproj.filters
# other files
.old*/
old/
tmp/
temp/
*.tmp
*.temp
logs/
log/
*.log
/mono/
/dotnet-runtime/

6
.gitmodules vendored Normal file
View File

@@ -0,0 +1,6 @@
[submodule "dependencies/tlibc"]
path = dependencies/tlibc
url = https://timerix.ddns.net/git/Timerix/tlibc.git
[submodule "dependencies/tlibtoml"]
path = dependencies/tlibtoml
url = https://timerix.ddns.net/git/Timerix/tlibtoml.git

1
.vscode/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
settings.json

18
.vscode/c_cpp_properties.json vendored Normal file
View File

@@ -0,0 +1,18 @@
{
"configurations": [
{
"name": "all",
"defines": [
],
"includePath": [
"dependencies/include",
"dependencies/tlibc/include",
"dependencies/tlibtoml/include",
"${default}",
],
"cStandard": "c99",
"cppStandard": "c++11",
}
],
"version": 4
}

29
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "gdb_debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/mono-apphost",
"windows": { "program": "${workspaceFolder}/bin/mono-apphost.exe" },
"preLaunchTask": "build_exec_dbg",
"stopAtEntry": false,
"cwd": "${workspaceFolder}/bin",
"externalConsole": false,
"internalConsoleOptions": "neverOpen",
"MIMode": "gdb",
"miDebuggerPath": "gdb",
"setupCommands": [
{
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
]
}

32
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,32 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build_exec_dbg",
"detail": "build project with debug symbols",
"type": "cppbuild",
"command": "bash",
"args": [
"-c",
"cbuild build_exec_dbg"
],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": ["$gcc"],
"group": {
"kind": "build"
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": true,
"panel": "shared",
"showReuseMessage": false,
"clear": true
}
}
]
}

48
README.md Normal file
View File

@@ -0,0 +1,48 @@
# mono-apphost
You created a C# program targeting dotnet6 or newer but users don't want to download and install 200 MB runtime from microsoft website? Here is the solution - portable and small (30 MB) runtime.
Original mono project was discontinued, but fortunately microsoft has their own [fork of mono runtime](https://github.com/dotnet/runtime/tree/main/src/mono) in dotnet runtime repository. It is still used in mobile development and wasm, so they continue to update it.
## Building
1. Clone the repository with submodules
```sh
git clone --recurse-submodules --depth 1 https://timerix.ddns.net/git/Timerix/mono-apphost.git
```
2. Install [cbuild v2.3](https://timerix.ddns.net/git/Timerix/cbuild/releases/)
```sh
ln -s SDL2_HEADERS_DIRECTORY_ABSOLUTE_PATH -T dependencies/include/SDL2
```
3. Download and extract mono runtime nuget package
- default version
```sh
cbuild download_mono_from_nuget
```
- or some specific version ([list of versions](https://www.nuget.org/packages/Microsoft.NETCore.App.Runtime.Mono.linux-x64/#versions-body-tab))
```sh
cbuild download_mono_from_nuget=x.y.z
```
- or build your own .nupkg from [dotnet source code](https://github.com/dotnet/runtime/tree/main/src/mono)
```sh
git clone --depth 1 -b v10.0.8 https://github.com/dotnet/runtime dotnet-runtime
cd dotnet-runtime
./build.sh mono+libs+packs.product --runtimeFlavor Mono --usemonoruntime --configuration Release --verbosity normal /p:DisableCrossgen=true
```
- find `Microsoft.NETCore.App.Runtime.*.nupkg` in `artifacts/packages/Release/Shipping/`.
- copy `runtimes/*/native/include/mono-2.0/mono` to `./dependencies/include/`
- copy shared library files from `runtimes/*native/` to `./dependencies/precompiled/` except `System.Private.CoreLib.dll`, it must be in `./dependencies/precompiled/mono-libs`
- copy C# standard library from `runtimes/*/lib/net10.0/` to `./dependencies/precompiled/mono-libs`
4. Compile the program
```sh
cbuild build_exec_dbg
```
5. Create program config
- copy `./mono-apphost.toml` to `./bin`
- change `main_assembly_path`
6. Copy files from `./bin/` to your C# program build dir

2
dependencies/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/include/
/precompiled/

30
dependencies/precompiled.config vendored Normal file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/env bash
DEP_WORKING_DIR="dependencies/precompiled/$OS-$ARCH"
mkdir -p "dependencies/precompiled"
mkdir -p "$DEP_WORKING_DIR"
DEP_PRE_BUILD_COMMAND=''
DEP_BUILD_COMMAND=''
DEP_POST_BUILD_COMMAND=''
DEP_CLEAN_COMMAND=''
# won't be copied to project $OUTDIR
DEP_STATIC_OUT_FILES=$(find "$DEP_WORKING_DIR" -name '*.a' | sed "s,$DEP_WORKING_DIR/,,")
mkdir -p "$DEP_WORKING_DIR/mono-libs"
mono_libs=$(find "$DEP_WORKING_DIR/mono-libs" -type f | sed "s,$DEP_WORKING_DIR/,,")
# will be copied tp project $OUTDIR
PRESERVE_OUT_DIRECTORY_STRUCTURE=true
case $OS in
WINDOWS)
DEP_DYNAMIC_OUT_FILES=$(find "$DEP_WORKING_DIR" -maxdepth 1 -name '*.dll' | sed "s,$DEP_WORKING_DIR/,,")
DEP_OTHER_OUT_FILES="$mono_libs"
;;
LINUX)
DEP_DYNAMIC_OUT_FILES=$(find "$DEP_WORKING_DIR" -name '*.so' | sed "s,$DEP_WORKING_DIR/,,")
DEP_OTHER_OUT_FILES="$mono_libs"
;;
*)
error "operating system $OS has no configuration variants"
;;
esac

1
dependencies/tlibc vendored Submodule

Submodule dependencies/tlibc added at 649c2c0968

19
dependencies/tlibc.config vendored Normal file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env bash
# This is a dependency config.
# You can copy it to another project to add tlibc dependency.
DEP_WORKING_DIR="$DEPENDENCIES_DIR/tlibc"
if [[ "$TASK" = *_dbg ]]; then
dep_build_target="build_static_lib_dbg"
else
dep_build_target="build_static_lib"
fi
DEP_PRE_BUILD_COMMAND=""
DEP_BUILD_COMMAND="cbuild $dep_build_target"
DEP_POST_BUILD_COMMAND=""
DEP_CLEAN_COMMAND="cbuild clean"
DEP_DYNAMIC_OUT_FILES=""
DEP_STATIC_OUT_FILES="bin/tlibc.a"
DEP_OTHER_OUT_FILES=""
PRESERVE_OUT_DIRECTORY_STRUCTURE=false

1
dependencies/tlibtoml vendored Submodule

Submodule dependencies/tlibtoml added at 22a3a4cfe5

30
dependencies/tlibtoml.config vendored Normal file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/env bash
# This is a dependency config.
# You can copy it to another project to add tlibtoml dependency.
DEP_WORKING_DIR="$DEPENDENCIES_DIR/tlibtoml"
user_config_path="project.config.user"
absolute_dep_dir=$(realpath "$DEPENDENCIES_DIR")
function setup_user_config(){
# Set variable `DEPENDENCIES_DIR`` in `tlibtoml/project.config.user`
# to the directory where `tlibc`` is installed
file_copy_default_if_not_present "$user_config_path" "$user_config_path.default"
replace_var_value_in_script "$user_config_path" "DEPENDENCIES_DIR" "$absolute_dep_dir"
}
if [[ "$TASK" = *_dbg ]]; then
dep_build_target="build_static_lib_dbg"
else
dep_build_target="build_static_lib"
fi
DEP_PRE_BUILD_COMMAND="setup_user_config"
DEP_BUILD_COMMAND="cbuild $dep_build_target"
DEP_POST_BUILD_COMMAND=""
DEP_CLEAN_COMMAND="cbuild clean"
DEP_DYNAMIC_OUT_FILES=""
DEP_STATIC_OUT_FILES="bin/tlibtoml.a"
DEP_OTHER_OUT_FILES=""
PRESERVE_OUT_DIRECTORY_STRUCTURE=false

25
mono-apphost.toml Normal file
View File

@@ -0,0 +1,25 @@
main_assembly_path="Program.dll"
mono_libs_dir="mono-libs"
# error, critical, warning, message, info, debug (default=error)
trace_level=""
# trace_mask values (use ',' as separator):
# all (default)
# asm, type, dll, gc, cfg, aot, security,
# threadpool
# io-threadpool
# io-selector
# io-layer
# io-layer-process
# io-layer-socket
# io-layer-file
# io-layer-console
# io-layer-pipe
# io-layer-event
# io-layer-semaphore
# io-layer-mutex
# io-layer-handle
# w32handle, tailcall, profiler, tiered
# qcall, metadata-update, diagnostics
trace_mask=""

209
project.config Normal file
View File

@@ -0,0 +1,209 @@
#!/usr/bin/env bash
CBUILD_VERSION=2.3.5
PROJECT="mono-apphost"
CMP_C="gcc"
CMP_CPP="g++"
STD_C="c99"
STD_CPP="c++11"
WARN_COMMON="-Wall -Wextra
-Wduplicated-branches
-Wduplicated-cond
-Wformat=2
-Wmissing-include-dirs
-Wshadow
-Werror=return-type
-Werror=pointer-arith
-Werror=init-self
-Wno-unused-parameter"
WARN_C="$WARN_COMMON
-Werror=incompatible-pointer-types"
WARN_CPP="$WARN_COMMON"
SRC_C="$(find src -name '*.c')"
SRC_CPP="$(find src -name '*.cpp')"
# Directory with dependency configs.
# See cbuild/example_dependency_configs
DEPENDENCY_CONFIGS_DIR='dependencies'
# List of dependency config files in DEPENDENCY_CONFIGS_DIR separated by space.
ENABLED_DEPENDENCIES='tlibc tlibtoml precompiled'
# OBJDIR structure:
# ├── objects/ - Compiled object files. Cleans on each call of build task
# ├── static_libs/ - Symbolic links to static libraries used by linker. Cleans on each call of build task.
# ├── static_libs/ - Symbolic links to dynamic libraries used by linker. Cleans on each call of build task.
# └── profile/ - gcc *.gcda profiling info files
OBJDIR="obj"
OUTDIR="bin"
STATIC_LIB_FILE="$PROJECT.a"
# header include directories
INCLUDE="-I$DEPENDENCIES_DIR/include
-I$DEPENDENCIES_DIR/tlibc/include
-I$DEPENDENCIES_DIR/tlibtoml/include"
DEFINES=""
# OS-specific options
case "$OS" in
WINDOWS)
EXEC_FILE="$PROJECT.exe"
SHARED_LIB_FILE="$PROJECT.dll"
LINKER_LIBS="-static -luuid"
INCLUDE="$INCLUDE "
DEFINES="$DEFINES "
;;
LINUX)
EXEC_FILE="$PROJECT"
SHARED_LIB_FILE="$PROJECT.so"
LINKER_LIBS=""
INCLUDE="$INCLUDE "
DEFINES="$DEFINES "
;;
*)
error "operating system $OS has no configuration variants"
;;
esac
# TASKS
case "$TASK" in
# creates executable using profiling info if it exists
build_exec)
# -flto applies more optimizations across object files
# -flto=auto is needed to multithreaded copilation
# -fuse-linker-plugin is required to use static libs with lto
# -fprofile-use enables compiler to use profiling info files to optimize executable
# -fprofile-prefix-path sets path where profiling info about objects are be saved
# -fdata-sections -ffunction-sections -Wl,--gc-sections removes unused code
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-use
-fprofile-prefix-path=$(realpath $OBJDIR)/objects
-fdata-sections -ffunction-sections -Wl,--gc-sections $DEFINES"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT=""
TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
POST_TASK_SCRIPT="@cbuild/default_tasks/strip_exec.sh"
;;
# creates executable with debug info and no optimizations
build_exec_dbg)
C_ARGS="-O0 -g3 $DEFINES"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT=""
TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
POST_TASK_SCRIPT=""
;;
# creates shared library
build_shared_lib)
C_ARGS="-O2 -fpic -flto -shared $DEFINES"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS -Wl,-soname,$SHARED_LIB_FILE"
TASK_SCRIPT="@cbuild/default_tasks/build_shared_lib.sh"
;;
# creates shared library with debug symbols and no optimizations
build_shared_lib_dbg)
C_ARGS="-O0 -g3 -fpic -shared $DEFINES"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS -Wl,-soname,$SHARED_LIB_FILE"
TASK_SCRIPT="@cbuild/default_tasks/build_shared_lib.sh"
;;
# creates static library
build_static_lib)
C_ARGS="-O2 -fpic -fdata-sections -ffunction-sections $DEFINES"
CPP_ARGS="$C_ARGS"
TASK_SCRIPT="@cbuild/default_tasks/build_static_lib.sh"
;;
# creates static library with debug symbols and no optimizations
build_static_lib_dbg)
C_ARGS="-O0 -g3 $DEFINES"
CPP_ARGS="$C_ARGS"
TASK_SCRIPT="@cbuild/default_tasks/build_static_lib.sh"
;;
# executes $EXEC_FILE
exec)
TASK_SCRIPT="@cbuild/default_tasks/exec.sh"
;;
# executes $EXEC_FILE with valgrind memory checker
valgrind)
VALGRIND_ARGS="-s --read-var-info=yes --track-origins=yes
--fullpath-after=$(pwd)/ --leak-check=full --show-leak-kinds=all
--suppressions=../valgrind_ignore.supp"
TASK_SCRIPT="@cbuild/default_tasks/valgrind.sh"
;;
# generates profiling info
profile)
OUTDIR="$OUTDIR/profile"
# -flto applies more optimizations across object files
# -flto=auto is needed to multithreaded copilation
# -fuse-linker-plugin is required to use static libs with lto
# -pg adds code to executable, that generates file containing function call info (gmon.out)
# -fprofile-generate generates executable with profiling code
# -fprofile-prefix-path sets path where profiling info about objects will be saved
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-generate
-fprofile-prefix-path=$(realpath $OBJDIR)/objects $DEFINES"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
TASK_SCRIPT="@cbuild/default_tasks/profile.sh"
;;
# compiles program with -pg and runs it with gprof
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
# requires graphviz (https://www.graphviz.org/download/source/)
gprof)
OUTDIR="$OUTDIR/gprof"
# arguments that emit some call counter code and disable optimizations to see function names
# https://github.com/msys2/MINGW-packages/issues/8503#issuecomment-1365475205
C_ARGS="-O0 -g -pg -no-pie -fno-omit-frame-pointer
-fno-inline-functions -fno-inline-functions-called-once
-fno-optimize-sibling-calls -fopenmp $DEFINES"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
TASK_SCRIPT="@cbuild/default_tasks/gprof.sh"
;;
# compiles program and runs it with callgrind (part of valgrind)
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
# requires graphviz (https://www.graphviz.org/download/source/)
# P.S. detailed results can be viewed in KCacheGrind
callgrind)
OUTDIR="$OUTDIR/callgrind"
# -pg adds code to executable, that generates file containing function call info (gmon.out)
C_ARGS="-O2 -flto=auto -fuse-linker-plugin $DEFINES"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
TASK_SCRIPT="@cbuild/default_tasks/callgrind.sh"
;;
# compiles executable with sanitizers and executes it to find errors and warnings
sanitize)
OUTDIR="$OUTDIR/sanitize"
C_ARGS="-O0 -g3 -fsanitize=undefined,address $DEFINES"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
TASK_SCRIPT="@cbuild/default_tasks/exec.sh"
;;
# rebuilds specified dependencies
# EXAMPLE: `cbuild rebuild_dependencies=libexample1,fonts`
# 'all' can be specified to rebuild all dependencies
rebuild_dependencies)
TASK_SCRIPT="@cbuild/default_tasks/rebuild_dependencies.sh"
;;
# Downloads mono runtime package from nuget.
# Extracts libs to dependencies/precompiled/$OS-$ARCH
# Extracts headers to dependencies/include/mono
# download_mono_from_nuget=VERSION
download_mono_from_nuget)
TASK_SCRIPT=tasks/download_mono_from_nuget.sh
;;
# deletes generated files
clean)
TASK_SCRIPT="@cbuild/default_tasks/clean.sh"
;;
# nothing to do
"" | no_task)
;;
# unknown task
*)
error "task <$PROJECT/$TASK> not found"
;;
esac

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env bash
# Project user config is ignored by git.
# Here you can add variables that users might want to change
# on their local machine, without commiting to the repository.
# Directory where you install dependencies.
# Do not confuse with DEPENDENCY_CONFIGS_DIR
# Example:
# libexample source code is at `../libexample`, and dependency config
# that specifies how to build this lib is at `dependencies/libexample.config`
DEPENDENCIES_DIR="dependencies"

198
src/main.c Normal file
View File

@@ -0,0 +1,198 @@
#include "tlibc/tlibc.h"
#include "tlibc/filesystem.h"
#include "tlibtoml.h"
#include <mono/jit/jit.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/class.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/object.h>
#include <mono/utils/mono-logger.h>
static const cstr APPHOST_CONFIG_PATH = "mono-apphost.toml";
static const cstr DOMAIN_NAME = "mono-apphost";
typedef struct ApphostConfig {
char* main_assembly_path;
char* mono_libs_dir;
// error, critical, warning, message, info, debug (default=error)
NULLABLE(char*) trace_level;
// see dotnet-runtime/src/mono/mono/utils/mono-logger.c
NULLABLE(char*) trace_mask;
//TODO: bool use_llvm
} ApphostConfig;
void ApphostConfig_free(ApphostConfig* conf){
if(!conf)
return;
free(conf->main_assembly_path);
free(conf->mono_libs_dir);
free(conf->trace_level);
free(conf->trace_mask);
free(conf);
}
Result(ApphostConfig*) ApphostConfig_load_filename(cstr _conf_path_raw){
Deferral(32);
ApphostConfig* conf = (ApphostConfig*)malloc(sizeof(ApphostConfig));
zeroStruct(conf);
bool success = false;
Defer(if(!success) ApphostConfig_free(conf));
str conf_path = str_copy(str_from_cstr(_conf_path_raw));
Defer(str_destroy(conf_path));
path_fix_separators(&conf_path);
try(TomlTable* config_top, p, toml_load_filename(conf_path.data));
Defer(TomlTable_free(config_top));
// main_assembly_path
try(str* main_assembly_path, p, TomlTable_get_str(config_top, STR("main_assembly_path")));
if(main_assembly_path->len == 0){
Return RESULT_ERROR_LITERAL("main_assembly_path: value is empty string")
}
path_fix_separators(main_assembly_path);
if(!file_exists(main_assembly_path->data)){
char* err = sprintf_malloc(
"main_assembly_path: file '%s' doesn't exist",
main_assembly_path->data);
return RESULT_ERROR_HEAP(err);
}
conf->main_assembly_path = str_copy(*main_assembly_path).data;
// mono_libs_dir
try(str* mono_libs_dir, p, TomlTable_get_str(config_top, STR("mono_libs_dir")));
if(mono_libs_dir->len == 0){
Return RESULT_ERROR_LITERAL("mono_libs_dir: value is empty string");
}
path_fix_separators(mono_libs_dir);
if(!dir_exists(mono_libs_dir->data)){
char* err = sprintf_malloc(
"mono_libs_dir: directory '%s' doesn't exist",
mono_libs_dir->data);
Return RESULT_ERROR_HEAP(err);
}
char* corelib_dll_path = strcat_malloc(mono_libs_dir->data, path_seps, "System.Private.CoreLib.dll");
Defer(free(corelib_dll_path));
char* corelib_dll_so_path = strcat_malloc(corelib_dll_path, ".so");
Defer(free(corelib_dll_so_path));
if(!file_exists(corelib_dll_path) && !file_exists(corelib_dll_so_path)){
char* err = sprintf_malloc(
"mono_libs_dir: can't find System.Private.CoreLib.dll in '%s'",
mono_libs_dir->data);
Return RESULT_ERROR_HEAP(err);
}
conf->mono_libs_dir = str_copy(*mono_libs_dir).data;
// trace_level
NULLABLE(TomlValue*) trace_level = TomlTable_tryGet(config_top, STR("trace_level"));
if(trace_level){
if(trace_level->s->len != 0)
conf->trace_level = str_copy(*trace_level->s).data;
}
// trace_mask
NULLABLE(TomlValue*) trace_mask = TomlTable_tryGet(config_top, STR("trace_mask"));
if(trace_mask){
if(trace_mask->s->len != 0)
conf->trace_mask = str_copy(*trace_mask->s).data;
}
success = true;
Return RESULT_VALUE(p, conf);
}
void trace_print_handler(const char *message, mono_bool is_stdout){
FILE* stream = is_stdout ? stdout : stderr;
fprintf(stream, "[MonoPrint]: %s\n", message);
}
void trace_log_handler(const char *log_domain, const char *log_level, const char *message,
mono_bool fatal, void *user_data)
{
FILE* stream = stderr;
fprintf(stream, "[%s/%s]: %s\n", log_domain, log_level, message);
}
Result(MonoDomain*) init_runtime(ApphostConfig* conf){
Deferral(16);
// configure logging
mono_trace_set_print_handler(trace_print_handler);
mono_trace_set_log_handler(trace_log_handler, NULL);
if(conf->trace_level)
mono_trace_set_level_string(conf->trace_level);
if(conf->trace_mask)
mono_trace_set_mask_string(conf->trace_mask);
// set dll search path
mono_set_assemblies_path(conf->mono_libs_dir);
// code for compatibility with old mono
mono_set_dirs(conf->mono_libs_dir, conf->mono_libs_dir);
char* mono_config_xml_path = strcat_malloc(conf->mono_libs_dir, path_seps, "config.xml");
Defer(free(mono_config_xml_path));
mono_config_parse(mono_config_xml_path);
// init mono runtime and create domain
MonoDomain* domain = mono_jit_init(DOMAIN_NAME);
if(domain == NULL){
Return RESULT_ERROR_LITERAL("can't initialize mono jit domain");
}
Return RESULT_VALUE(p, domain);
}
Result(MonoAssembly*) load_assembly(MonoDomain* domain, cstr name){
Deferral(1);
MonoAssembly* assembly = mono_domain_assembly_open(domain, name);
if(assembly == NULL){
char* err = sprintf_malloc("can't load assembly '%s'", name);
Return RESULT_ERROR_HEAP(err);
}
Return RESULT_VALUE(p, assembly);
}
Result(i32) try_main(i32 argc, cstr* argv){
Deferral(8);
try(ApphostConfig* conf, p, ApphostConfig_load_filename(APPHOST_CONFIG_PATH));
Defer(ApphostConfig_free(conf));
try(MonoDomain* domain, p, init_runtime(conf))
// mono_jit_cleanup sometimes leads to segfault.
// I guess nobody really tested this thing.
Defer(mono_jit_cleanup(domain));
try(MonoAssembly* assembly, p, load_assembly(domain, conf->main_assembly_path))
i32 ret = mono_jit_exec(domain, assembly, argc, (char**)(argv));
Return RESULT_VALUE(i, ret);
}
i32 main(i32 argc, cstr* argv){
Deferral(4);
try_fatal_void(tlibc_init());
Defer(tlibc_deinit());
try_fatal_void(tlibtoml_init());
Defer(tlibtoml_deinit());
try_fatal(i32 ret, i, try_main(argc, argv));
if(ret != 0){
printfe("program exited with non-zero code: %i\n", ret);
}
Return ret;
}

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env bash
package_version="$TASK_ARGS"
if [ -z "$package_version" ]; then
package_version="8.0.15"
myprint "${YELLOW}You can choose package version manually: cbuild get_mono_files_from=x.y.z"
fi
myprint "${BLUE}package_version: ${CYAN}$package_version"
case "$OS" in
LINUX)
package_platform="linux-$ARCH"
;;
WINDOWS)
package_platform="win-$ARCH"
;;
esac
package_name="Microsoft.NETCore.App.Runtime.Mono.$package_platform"
package_dir="$package_name.$package_version"
package_file="$package_name.$package_version.nupkg"
package_url="https://www.nuget.org/api/v2/package/$package_name/$package_version"
mkdir -p "$OBJDIR/downloads"
myprint "${BLUE}downloading nuget package: ${WHITE}$package_name ${BLUE}to $OBJDIR/downloads"
cd "$OBJDIR/downloads"
wget -q $package_url -O $package_file
clean_dir $package_dir
cd $package_dir
myprint "${BLUE}extracting nuget package"
unzip -oq "../$package_file"
# copy headers
myprint "${BLUE}copying headers"
mkdir -p "../../../dependencies/include"
delete_dir "../../../dependencies/include/mono"
cp -r "runtimes/$package_platform/native/include/mono-2.0/mono" "../../../dependencies/include/"
precompiled_dir="../../../dependencies/precompiled/$OS-$ARCH"
mkdir -p "$precompiled_dir"
clean_dir "$precompiled_dir/mono-libs"
# copy mono native libraries
myprint "${BLUE}copying mono native libraries"
shared_libs=$(find "runtimes/$package_platform/native" -maxdepth 1 \( -not -name "System.Private.CoreLib.dll" -a \( -name '*.so*' -o -name '*.dll' \) \) -type f)
if [ -z "$shared_libs" ]; then
error "can't find mono shared libraries"
fi
for l in $shared_libs ; do
cp -v "$l" "$precompiled_dir"
done
# copy mono c# libraries
myprint "${BLUE}copying mono managed libraries"
managed_libraries="runtimes/$package_platform/native/System.Private.CoreLib.dll"
_subdirs=(runtimes/$package_platform/lib/*)
_managed_lib_dir="${_subdirs[0]}"
for l in $(find $_managed_lib_dir -type f); do
managed_libraries+=" $l"
done
for l in $managed_libraries; do
cp -v "$l" "$precompiled_dir/mono-libs"
done
myprint "${GREEN}mono files have been copied successfully!"
cd ../../..
clean_dir "$OBJDIR/downloads"

29
valgrind_ignore.supp Normal file
View File

@@ -0,0 +1,29 @@
{
coreclr_all_leaks
Memcheck:Leak
match-leak-kinds: all
...
obj:*libcoreclr.so*
}
{
coreclr_cond
Memcheck:Cond
...
obj:*libcoreclr.so*
}
{
libsystem_all_leaks
Memcheck:Leak
match-leak-kinds: all
...
obj:*libSystem.*.so*
}
{
dlopen_leak
Memcheck:Leak
match-leak-kinds: reachable
...
fun:_dl_open
...
}