initial commit
This commit is contained in:
23
.gitignore
vendored
Normal file
23
.gitignore
vendored
Normal 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
6
.gitmodules
vendored
Normal 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
1
.vscode/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
settings.json
|
||||||
18
.vscode/c_cpp_properties.json
vendored
Normal file
18
.vscode/c_cpp_properties.json
vendored
Normal 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
29
.vscode/launch.json
vendored
Normal 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
32
.vscode/tasks.json
vendored
Normal 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
48
README.md
Normal 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
2
dependencies/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/include/
|
||||||
|
/precompiled/
|
||||||
30
dependencies/precompiled.config
vendored
Normal file
30
dependencies/precompiled.config
vendored
Normal 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
1
dependencies/tlibc
vendored
Submodule
Submodule dependencies/tlibc added at 649c2c0968
19
dependencies/tlibc.config
vendored
Normal file
19
dependencies/tlibc.config
vendored
Normal 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
1
dependencies/tlibtoml
vendored
Submodule
Submodule dependencies/tlibtoml added at 22a3a4cfe5
30
dependencies/tlibtoml.config
vendored
Normal file
30
dependencies/tlibtoml.config
vendored
Normal 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
25
mono-apphost.toml
Normal 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
209
project.config
Normal 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
|
||||||
11
project.config.user.default
Normal file
11
project.config.user.default
Normal 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
198
src/main.c
Normal 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;
|
||||||
|
}
|
||||||
69
tasks/download_mono_from_nuget.sh
Normal file
69
tasks/download_mono_from_nuget.sh
Normal 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
29
valgrind_ignore.supp
Normal 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
|
||||||
|
...
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user