zoukankan      html  css  js  c++  java
  • 2019-10-4-C#-极限压缩-dotnet-core-控制台发布文件

    title author date CreateTime categories
    C# 极限压缩 dotnet core 控制台发布文件
    lindexi
    2019-10-04 14:59:36 +0800
    2019-10-04 14:51:48 +0800
    dotnet C#

    每次发布 dotnet core 应用都会觉得发布文件太大,而如果使用极限压缩,用 CoreRT 能让发布的控制台文件到 5KB 左右,不需要带框架就能在其他设备运行

    这是微软 MichalStrehovsky 大佬,也就是 CoreRT 项目开发者给的方法

    在开始写代码之前,需要定义一些基础的类,因为不包含任何运行环境,所以基础的 object 这些都需要重新定义,这里的代码放在 github 我也在本文最后贴出代码

    现在输出控制台的代码不是原先的 Console.WriteLine 而是通过底层方法

    unsafe class Program
    {
        [DllImport("api-ms-win-core-processenvironment-l1-1-0")]
        static extern IntPtr GetStdHandle(int nStdHandle);
    
        [DllImport("api-ms-win-core-console-l1-1-0")]
        static extern IntPtr WriteConsoleW(IntPtr hConsole, void* lpBuffer, int charsToWrite, out int charsWritten, void* reserved);
    
        static int Main()
        {
            string hello = "Hello world!";
            fixed (char* c = hello)
            {
                int charsWritten;
                WriteConsoleW(GetStdHandle(-11), c, hello.Length, out charsWritten, null);
            }
    
            return 42;
        }
    }

    最难的是如何编译这个文件

    编译需要先使用 csc 编译为 IL 代码,然后通过 ilcompiler 编译为obj文件,然后通过 link 编译为运行文件

    从开始菜单找到 x64 Native Tools Command Prompt for VS 2019 然后进入上面代码所在文件夹,执行下面代码编译

    csc /debug:embedded /noconfig /nostdlib /runtimemetadataversion:v4.0.30319 zerosharp.cs /out:zerosharp.ilexe /langversion:latest /unsafe

    编译完成可以看到 zerosharp.ilexe 文件,然后通过 ilcompiler 将这个文件编译为 zerosharp.map 和 zerosharp.obj 文件

    在自己的 NuGet 缓存文件里面找到 runtime.win-x64.microsoft.dotnet.ilcompiler 库,可以在资源管理器地址输入下面代码找到缓存文件

    %appdata%.......nugetpackagesruntime.win-x64.microsoft.dotnet.ilcompiler

    找到里面的最新版本,在文件夹里面的 tools 文件夹可以找到 ilc.exe 文件,如在我电脑的的文件是

    c:Userslindexi.nugetpackagesruntime.win-x64.microsoft.dotnet.ilcompiler1.0.0-alpha-27606-05toolsilc.exe

    记下这个路径,接下来将使用这个工具编译

    >c:Userslindexi.nugetpackagesruntime.win-x64.microsoft.dotnet.ilcompiler1.0.0-alpha-27606-05toolsilc.exe zerosharp.ilexe -o zerosharp.obj --systemmodule zerosharp --map zerosharp.map -O

    然后用 link 连接

    link /subsystem:console zerosharp.obj /entry:__managed__Main kernel32.lib /merge:.modules=.pdata /incremental:no

    执行上面代码就可以编译 zerosharp.exe 文件,这个文件只有5KB可以将这个程序放在其他设备运行

    下面是所有代码

    using System;
    using System.Runtime.InteropServices;
    
    #region A couple very basic things
    namespace System
    {
        public class Object { IntPtr m_pEEType; }
        public struct Void { }
        public struct Boolean { }
        public struct Char { }
        public struct SByte { }
        public struct Byte { }
        public struct Int16 { }
        public struct UInt16 { }
        public struct Int32 { }
        public struct UInt32 { }
        public struct Int64 { }
        public struct UInt64 { }
        public struct IntPtr { }
        public struct UIntPtr { }
        public struct Single { }
        public struct Double { }
        public abstract class ValueType { }
        public abstract class Enum : ValueType { }
        public struct Nullable<T> where T : struct { }
        
        public sealed class String { public readonly int Length; }
        public abstract class Array { }
        public abstract class Delegate { }
        public abstract class MulticastDelegate : Delegate { }
    
        public struct RuntimeTypeHandle { }
        public struct RuntimeMethodHandle { }
        public struct RuntimeFieldHandle { }
    
        public class Attribute { }
    
        namespace Runtime.CompilerServices
        {
            public class RuntimeHelpers
            {
                public static unsafe int OffsetToStringData => sizeof(IntPtr) + sizeof(int);
            }
        }
    }
    namespace System.Runtime.InteropServices
    {
        public sealed class DllImportAttribute : Attribute
        {
            public DllImportAttribute(string dllName) { }
        }
    }
    #endregion
    
    #region Things needed by ILC
    namespace System
    {
        namespace Runtime
        {
            internal sealed class RuntimeExportAttribute : Attribute
            {
                public RuntimeExportAttribute(string entry) { }
            }
        }
    
        class Array<T> : Array { }
    }
    
    namespace Internal.Runtime.CompilerHelpers
    {
        using System.Runtime;
    
        class StartupCodeHelpers
        {
            [RuntimeExport("RhpReversePInvoke2")]
            static void RhpReversePInvoke2() { }
            [RuntimeExport("RhpReversePInvokeReturn2")]
            static void RhpReversePInvokeReturn2() { }
            [System.Runtime.RuntimeExport("__fail_fast")]
            static void FailFast() { while (true) ; }
            [System.Runtime.RuntimeExport("RhpPInvoke")]
            static void RphPinvoke() { }
            [System.Runtime.RuntimeExport("RhpPInvokeReturn")]
            static void RphPinvokeReturn() { }
        }
    }
    #endregion
    
    unsafe class Program
    {
        [DllImport("api-ms-win-core-processenvironment-l1-1-0")]
        static extern IntPtr GetStdHandle(int nStdHandle);
    
        [DllImport("api-ms-win-core-console-l1-1-0")]
        static extern IntPtr WriteConsoleW(IntPtr hConsole, void* lpBuffer, int charsToWrite, out int charsWritten, void* reserved);
    
        static int Main()
        {
            string hello = "Hello world!";
            fixed (char* c = hello)
            {
                int charsWritten;
                WriteConsoleW(GetStdHandle(-11), c, hello.Length, out charsWritten, null);
            }
    
            return 42;
        }
    }
  • 相关阅读:
    如何导出视图中的数据
    swift中的流程控制
    PostgreSQL导出sql脚本文件
    Java分享笔记:使用缓冲流复制文件
    Java分享笔记:FileOutputStream流的write方法
    Java分享笔记:FileInputStream流的 read()方法 和 read(byte[] b)方法
    Java分享笔记:File类中常用方法的介绍
    Java分享笔记:使用entrySet方法获取Map集合中的元素
    Java分享笔记:使用keySet方法获取Map集合中的元素
    Java分享笔记:Map集合(接口)的基本方法程序演示
  • 原文地址:https://www.cnblogs.com/lindexi/p/12085806.html
Copyright © 2011-2022 走看看