net编译过程(了解.NetNative编译器)
net编译过程(了解.NetNative编译器)在reproNativew项目的cpp文件看到这一段代码比较有意思:链接obj目标文件 和cpp文件编译成原生程序ILCompiler的解决方案文件 在这个目录下src/coreclr/tools/aot/ilc.sln 打开解决方案后:然后启动ILCompiler项目 会将obj文件生成到 工作目录加命令行参数所在的目录.找到reproNative项目 在该项目属性中 找到链接器→输入: F:\GitCode\runtimelab-feature-NativeAOT\samples\HelloWorld\obj\Debug\net6.0\win-x64\native\HelloWorld.obj
起因在.Net6中 Native程序生成的过程 说到*.ilc.rsp这个文件 其实rsp格式文件很早都在.Net中使用了 最早知道这个格式文件是在<<CLR Via C#>>这本书 我觉得这是我看C#最认真的一本书了.继续说*.ilc.rsp文件这个是谁使用? 是ILCompiler(简写ilc)编译器使用 这个编译器将.Net (exe/dll)编译为obj目标文件.
ILCompiler源码地址:https://github.com/dotnet/runtimelab.git 在Github上看到好像在.Net 7中要将ILCompiler合到.Net Runtime中.
准备工作ILCompiler源码在runtimelab下 runtimelab是包含CoreCLR和BCL库.所以要执行根目录下的build.cmd/build.sh
//Windows下执行 这里和执行编译Runtime源码不太一样 增加了nativeaot.packages参数
build.cmd nativeaot libs nativeaot.packages -rc Debug -lc Debug
//Linux下执行
build.sh nativeaot libs nativeaot.packages -rc Debug -lc Debug
编译前 还是需要一个.Net版本 这里就不说了 具体可以看 如何编译.Net 6 Runtime源码 编译完成后 是有ILCompiler的nupkg包 可以在源码根目录下 去这个路径artifacts/packages/Debug/Shipping/
ILCompiler的解决方案文件 在这个目录下src/coreclr/tools/aot/ilc.sln 打开解决方案后:
- 设置ILCompiler为启动项目
- 设置工作目录 F:\GitCode\runtimelab-feature-NativeAOT\samples\HelloWorld
- 设置命令行参数 以@开头. 如@obj/Debug/net6.0/win-x64/native/HelloWorld.ilc.rsp
然后启动ILCompiler项目 会将obj文件生成到 工作目录加命令行参数所在的目录.
生成Native程序找到reproNative项目 在该项目属性中 找到链接器→输入: F:\GitCode\runtimelab-feature-NativeAOT\samples\HelloWorld\obj\Debug\net6.0\win-x64\native\HelloWorld.obj
链接obj目标文件 和cpp文件编译成原生程序
在reproNativew项目的cpp文件看到这一段代码比较有意思:
#if defined(_MSC_VER)
#pragma section(".modules$A" read)
#pragma section(".modules$Z" read)
extern "C" __declspec(allocate(".modules$A")) void * __modules_a[];
extern "C" __declspec(allocate(".modules$Z")) void * __modules_z[];
__declspec(allocate(".modules$A")) void * __modules_a[] = { nullptr };
__declspec(allocate(".modules$Z")) void * __modules_z[] = { nullptr };
//
// Each obj file compiled from managed code has a .modules$I section containing a pointer to its ReadyToRun
// data (which points at eager class constructors frozen strings etc).
//
// The #pragma ... /merge directive folds the book-end sections and all .modules$I sections from all input
// obj files into .rdata in alphabetical order.
//
#pragma comment(linker "/merge:.modules=.rdata")
//
// Unboxing stubs need to be merged folded and sorted. They are delimited by two special sections (.unbox$A
// and .unbox$Z). All unboxing stubs are in .unbox$M sections.
//
#pragma comment(linker "/merge:.unbox=.text")
char _bookend_a;
char _bookend_z;
//
// Generate bookends for the managed code section.
// We give them unique bodies to prevent folding.
//
#pragma code_seg(".managedcode$A")
void* __managedcode_a() { return &_bookend_a; }
#pragma code_seg(".managedcode$Z")
void* __managedcode_z() { return &_bookend_z; }
#pragma code_seg()
//
// Generate bookends for the unboxing stub section.
// We give them unique bodies to prevent folding.
//
#pragma code_seg(".unbox$A")
void* __unbox_a() { return &_bookend_a; }
#pragma code_seg(".unbox$Z")
void* __unbox_z() { return &_bookend_z; }
#pragma code_seg()
这一段代码 应该就是将obj的module放到节(这是可执行程序的知识 后面会在PE中说这个).
下面看main方法代码:
#if defined(_WIN32)
int __cdecl wmain(int argc wchar_t* argv[])
#else
int main(int argc char* argv[])
#endif
{
#ifdef ENSURE_PRIMARY_STACK_SIZE
// TODO: https://github.com/dotnet/runtimelab/issues/791
EnsureStackSize(1536 * 1024);
#endif
int initval = InitializeRuntime(); //初始化runtime
if (initval != 0)
return initval;
int retval = __managed__Main(argc argv); //调用.net的main方法
RhpShutdown();
return retval;
}
后面就可以看为什么没法在C程序调用.Net Native生成的静态库了.
个人能力有限 如果您发现有什么不对 请私信我
如果您觉得对您有用的话 可以点个赞或者加个关注 欢迎大家一起进行技术交流