起因
文章在19年写,因为最近在学习.Net CoreCLR源码,觉得Mono的设计还是很先进的, .Net 5单文件发布,应该是吸收Mono的思想,所以才把这篇文章迁移过来,Mono这几年也是一直在改进.
Mono是支持将C#程序集嵌入到C语言生成的可执行程序中.这里借用mono官方文档的图片.具体参考mono文档:
//文档地址
https://www.mono-project.com/docs/advanced/embedding/
生成Mono Runtime
上图有Mono Runtime,具体是什么呢?
先用MingW编译mono.这里直接使用mono官网下载的,不是从github上下载的(最近使用github比较慢),两个还是有些区别的.最好是使用github 当下来.
下载mono-6.0.0.313.tar.xz,进行解压.最好在msys2中进行解压.在MingW中进行编译.这里采用64位的MingW,进入解压后的mono目录.
./autogen.sh --prefix=/e/opensource/mymono/ --host=x86_64-w64-mingw32 --disable-boehm
没有报错的话,就能看到下图:
执行make和make install 进行编译和安装.上次编译并没有安装--prefix指定的目录,执行一半.我们想要的是编译成功的.
make && make install
MingW默认执行是MingW64/bin目录下的可执行程序.到这里只是.Net Framework的类库没有编译完成,Mono的Runtime(运行时)在这已经编译成功了.
生成好的文件在mono/mini/.libs/下.
分别为libmonosgen-2.0.a(静态库)和libmonosgen-2.0.dll(动态库),这里主要使用的是静态库.
准备好,链接Mono Runtime环境
因为上次编译没有完成.还是需要下载一个mono Windows平台的安装,然后提取链接需要的头文件.
因为省事,直接把mono-2.0下mono目录,拷贝到MingW的include目录中.将静态库放到MingW/lib中.
链接代码
#include
#include
#include
//mono所需头文件
#include
#include
int main(int argc, char* argv[])
{
//设置c#依赖库目录为lib 配置从etc目录读取
mono_set_dirs("lib", "etc");
//指定.Net 版本为4.0
MonoDomain* domain = domain = mono_jit_init_version("myapp", "v4.0.30319");
//这里固定加载c#程序名称为hello.exe
MonoAssembly* assembly = mono_domain_assembly_open(domain, "hello.exe");
if (!assembly)
{
printf("open assembly failed!\n");
exit(0);
}
//执行c#程序集
int retval = mono_jit_exec(domain, assembly, argc, argv);
//释放mono运行时资源
mono_jit_cleanup(domain);
return retval;
}
#编译pack 链接所需静态库
gcc -g -o pack.exe pack.c -lmonosgen-2.0 -lmswsock -lws2_32 -lpsapi -lole32 -lwinmm -loleaut32 -ladvapi32 -lversion -lbcrypt -lz
今年看Mono 把zlib移入到源码中,上边链接-lz,在后面的版本不需要了.
生成好的pack.exe.
生成的目标可执行程序,还是有些大的.使用strip清除调试符号.
#使用strip 去除程序不需要符号信息
strip pack.exe
去掉调试符号的程序大小,是下图pack.exe的大小,这个文件的大小,我们是可以接受的,如果还嫌文件大,可以用UPX进行压缩
因为还没有将c#程序嵌入c Native程序,这里需要mscorlib.dll文件.
在pack.exe目录,按lib/mono/4.5目录路径,创建目录,并将mscorlib.dll拷贝过来.
在.Net 5/6中是没有mscorlib.dll,改为
System.Private.CoreLib.dll, Mono中目前还需要
本文暂时没有评论,来添加一个吧(●'◡'●)