.NET5.0 단일 파일 릴리스 및 패키징 작업에 대한 심층 분석

선택적 매개 변수
속성 설명
IncludeNativeLibrariesInSingleFile 게시 할 때 종속 네이티브 바이너리 파일을 단일 파일 응용 프로그램으로 패키지화합니다.
IncludeSymbolsInSingleFile은 .pdb 파일을 단일 파일로 압축합니다. 이 옵션은 .NET 3 단일 파일 모드와의 호환성을 위해 제공됩니다. 권장되는 대체 방법은 포함 된 PDB (포함)
IncludeAllContentInSingleFile이 있는 어셈블리를 생성하여 게시 된 모든 파일 (심볼 파일 제외)을 단일 파일로 압축하는 것입니다. 이 옵션은 .NETCore 3.x 버전과의 역 호환성을 위해 제공됩니다
. 구성 파일 설정 매개 변수
외에도 명령 줄 매개 변수 형식을 사용할 수 있으며, 구성 파일 형식으로 게시 매개 변수를 설정하고, 프로젝트 파일을 편집하고, 파일에 구성 노드를 추가하고, 저장할 수도 있습니다. 확인.

net5.0 linux-x64 true true RID에 대한 설명은 https://docs.microsoft.com/en-us/dotnet/core/rid-catalog를 참조하십시오.

이 기사가 게시되기 전의 RID 버전이며 .NET5.0의 새 릴리스가있을 것임을 배제하지 않습니다.

기타 매개 변수
위의 세 가지 선택적 매개 변수 이외에도 문서를 조회하는 과정에서 공무원이 다른 매개 변수의 사용을 언급했다는 사실도 발견했습니다.

true true PreserveNewest true는 ExcludeFromSingleFile 요소로도 설정할 수 있습니다.이 설정은 단일 파일에 포함되지 않을 특정 파일을 지정합니다.

패키징 할 응용 프로그램 작성
일반 릴리스와 단일 파일 릴리스의 차이점을보다 직관적으로 확인하기 위해 특별히 웹 응용 프로그램을 준비하고 두 어셈블리에 대한 종속 참조를 만들었습니다.

프로젝트를 준비하고, 성공적으로 컴파일하고, 게시를 시도하고, PowerShel 콘솔을 열고, 각각 다음 명령을 입력합니다.

dotnet publish -r linux-x64 / p : PublishSingleFile = true
dotnet publish -r win-x64 --self-contained = false / p : PublishSingleFile = true

linux-x64 및 win-x64 아래에는 각각 게시 디렉토리가 있습니다. 플랫폼이 다르기 때문에 참조되는 종속성이 다릅니다. 이것은 우리가 오랫동안 알고 있었던 것입니다. 패키징 전후의 차이점을 살펴 보겠습니다.

위에서 실행 된 두 명령문은 우리를 위해 Linux 및 Windows 플랫폼 용 패키지를 생성합니다. 위 그림에서 볼 수 있듯이 패키징하기 전에 프로젝트의 다양한 참조 종속성이 릴리스 디렉토리에 복사됩니다. 이전 프로그램 릴리스 방법에서는 패키징 후 모든 종속 파일이 실행 파일로로드되며, Linux 플랫폼에서는 PreviewWebApplication으로, Windows 플랫폼에서는 PreviewWebApplication.exe로 표시됩니다. 패키징 효과의 관점에서 마이그레이션이 더 편리해질 것입니다.


프로그램을 실행하는 패커 와 압축을 푼 게시자는 패키징 된 차이점을 실행하는 방법이 많지 않았습니다. Windows 플랫폼에서 PreviewWebApplication.exe를 두 번 클릭하기 만하면 패키저를 실행할 수 있습니다.이 예제는 WebApi를 만드는 것입니다. Razor보기 또는 기타 리소스 파일을 사용하여 프로그램을 만드는 경우 지정된 URL에 액세스하지 못할 수 있습니다.

프로그램이 성공적으로 실행 된 후 패키징 프로그램이 파일을 디스크로 압축 해제하지 않고 직접 실행하기 위해 패키지에서 메모리로 파일을로드 한 것을 발견했습니다. 이는 War 파일과의 근본적인 차이점이며 크게 개선되었습니다.

.exe 파일은 실행할 다른 위치에 별도로 복사 할 수 없습니다. 실행하려면 .exe의 현재 디렉터리를 완전히 복사해야합니다. 여기에는 호스트 감지 문제가 포함되며 아래에서 하나씩 언급합니다.

크로스 플랫폼 패키징 파일
위의 예를 통해 패키징 프로그램은 항상 다른 플랫폼에 대해 독립적 인 패키징 프로그램을 생성한다는 것을 배웠습니다. 여기에 관련된 개념, 즉 도구 인터페이스 표준 (TIS)이 있습니다.

ELF (Executable and Linking Format)
COFF (Common Object File Format)는 1983 년에 도입되었으며 원래 AT & T의 UNIX 시스템에서 사용되었습니다. 다음과 같은 COFF의 다양한 제한으로 인해 최대 섹션 수, 섹션 이름, 포함 된 소스 파일의 길이가 제한되며 기호 디버깅 정보가 실제 언어를 지원할 수 없습니다. 마지막으로 SVR4 (System V Release 4)가 출시 된 후 AT & T는 COFF를 ELF로 대체했습니다.

Tool Interface Standards Committee
는위원회의 사양 문서에 대한 설명을 인용합니다. 실행 파일과 링크 형식은 원래 API (Application Binary Interface)의 일부로 UNIX System Development and Release Laboratory (USL)에서 개발했습니다. TIS (Tool Interface Standards Committee)는 진화하는 ELF 표준을 이식 가능한 개체 파일로 선택했습니다. 이 표준은 다양한 운영 체제의 32 비트 Intel 아키텍처 환경 형식에 적용됩니다. ELF 표준은 개발자에게 여러 운영 환경에 걸친 바이너리 인터페이스 정의 세트를 제공하는 것을 목표로합니다. 이렇게하면 서로 다른 인터페이스 구현의 수가 줄어들어 코드를 다시 작성하고 컴파일 할 필요성이 줄어 듭니다.

ELF 파일 구조는 다음 세 가지 유형으로 나뉩니다.

이름 설명 설명
재배치 가능 파일에는 다른 개체 파일과 연결하여 실행 파일 또는 공유 개체 파일을 만드는 데 적합한 코드와 데이터가 포함되어 있습니다.
실행 파일에는 실행에 적합한 프로그램이 포함되어 있으며
공유 객체 파일에는 두 가지 컨텍스트에서 연결하기에 적합한 코드와 데이터가 포함되어 있습니다. 첫째, 링크 편집기는이를 삭제하고 다시 공유하여 다른 개체 파일을 만들 수있는 다른 개체 파일과 함께 처리 할 수 ​​있습니다. 둘째, 동적 링커는이를 실행 파일 및 기타 공유 개체와 결합하여 프로세스 이미지를 만듭니다.
PE (Portable Executable)는
Windows 캠프에 있습니다. Microsoft는이 COFF 표준을 기반으로 PE 파일 표준을 혁신하고 개발했습니다.

PE 형식
이 사양은 Windows 운영 체제 제품군의 실행 파일 (이미지) 및 개체 파일의 구조를 설명합니다. 이러한 파일을 PE (Portable Executable) 및 COFF (Common Object File Format) 파일이라고합니다.

위의 두 가지 사양에서 LinuX와 Windows에는 자체 파일 형식 사양이 있으며이 사양은 파일 구조 나 구문 분석 방법에 관계없이 어느 정도 호환되지 않습니다. 그래서 .NET5.0에서 패키저는 다른 플랫폼에 대해 독립적 인 패키저를 구현해야합니다. 패키저의 구현은 런타임의 Microsoft.NET.HostModel 라이브러리에 있습니다.

ELF 및 PE 파일 구조를 이해하면 패키저 코드를 읽고 이해할 수 있습니다.

Microsoft.NET.HostModel
github에서 .NET 5.0의 소스 코드를 다운로드하고
다음 디렉토리로 이동할 수 있습니다.

runtime / src / installer / managed / Microsoft.NET.HostModel

소스 코드는 너무 많지 않으며 주로 계층 적 관계를 이해하기 위해 직접 읽을 수 있습니다.

패키지 프로그램은 주로 AppHost, Bundler, ComHost의 세 가지 주요 부분을 포함합니다.

모듈 설명
AppHost는 단일 파일 호스트가 시작될 때 파일 검색에 사용됩니다. 또한 백업을 위해 App.dll에서 AppHost로 프로그램 리소스를 복사합니다. HostFxr 및 HostPolicy를 통해 정적으로 연결되었으며 검색 논리가 HostPolicy (C ++로 작성)로 전송되었습니다.
Bundler packager의 특정 구현은 주로 AppHost에 응용 프로그램과 해당 종속성을 포함시킨 다음 지정된 디렉터리
ComHost에 단일 실행 파일을 게시하여 포함 된 CLSIDMap 파일이 포함 된 ComHost를 만들어 CLSID를 .NET 클래스에 매핑하는 것입니다.
Bundle / Manifest.cs 파일의 선두에 "단일 파일 프로그램"의 파일 구조 정의가 있습니다.

BundleManifest는 번들 파일의 내용에 대한 설명입니다.
이 클래스는 번들 매니페스트의 생성 및 소비를 처리합니다.

다음은 번들 레이아웃에 대한 설명입니다.


AppHost

------------ 포함 된 파일 ---------------------
앱,
구성 파일, 종속성 및
가능한 경우를 포함한 포함 된 파일 런타임.

------------ 번들 헤더 -------------
MajorVersion
MinorVersion
NumEmbeddedFiles
ExtractionID
DepsJson 위치 [버전 2+]
오프셋
크기
RuntimeConfigJson 위치 [버전 2+]
오프셋
크기
플래그 [버전 2+]

            • 매니페스트 항목
              -----------일련의 FileEntries (각 포함 된 파일에 대해)
              [파일 유형, 이름, 오프셋, 크기 정보]

위의 파일 구조에서 단일 파일 프로그램의 구조가 다음 세 부분으로 나뉘어져 있음을 분명히 알 수 있습니다.

정의 설명 설명
임베디드 파일은 주로 .deps.json, runtimeconfig.json 및 기타 파일과 같은 구성 파일 및 설명 파일이며
번들 헤더는 전체 파일의 구조 정보, 유형, 저장 위치, 세그먼트, 테이블 등을 설명합니다. 정보
매니페스트 항목 실제 패키징 된 파일 목록, 각 파일은 세그먼트로 작성되고, 실행 파일은 16byte-prev 파일 끝 위치로 구분되며, 일반 파일은 이전 파일 끝 위치에 따라 직접 작성됩니다.
파일 헤더 정보를 볼
있습니다 . 일부 도구를 사용하여 패키지 파일을 볼 수 있습니다. Linux에서는 readelf / objdump와 같은 프로그램을 사용하여 PreviewWebApplication 파일의 정보를 얻을 수 있습니다. Windows에서는 PE 도구와 같은 도구를 사용할 수 있습니다.

Linux readelf 읽기 파일 헤더 정보

그림에서 Type : DYN (공유 객체 파일) 표준 공유 객체 파일로 ELF 헤더 정보의 내용이 더 이상 확장되지 않고 관심있는 학생들이 스스로 관련 내용을 배울 수 있습니다.

Windows의 PE 도구는 파일 헤더 정보를 읽습니다.

패키지 프로그램에는 319 (Linux) 및 Windows (359) 파일이 포함되어 있습니다. Windows 버전은 패키징 전 84.3MB, 패키징 후 69.8MB입니다. 가장 중요한 것은 런타임시 번들에서 직접 압축을 풀 필요가 없다는 것입니다. 파일을 실행하십시오.

파일의 세 번째 부분, 즉 "매니페스트 항목"쓰기 코드는 Bundle \ Bundler.cs \ AddToBundle에 있습니다.

long AddToBundle (Stream bundle, Stream file, FileType type)
{ if (type == FileType.Assembly) { long misalignment = (bundle.Position % AssemblyAlignment); if (misalignment! = 0) { long padding = AssemblyAlignment-misalignment; bundle .Position + = padding; } } file.Position = 0; long startOffset = bundle.Position; file.CopyTo (bundle); return startOffset; } 멤버 메서드에서 GenerateBundle (IReadOnlyList fileSpecs) 반복적으로 AddToBundle 메서드를 호출하여 엔터티를 완료합니다. 매니페스트 파일 작성.














// 코드 세그먼트

public string GenerateBundle (IReadOnlyList fileSpecs)
{ foreach (fileSpecs의 var fileSpec) { string relativePath = fileSpec.BundleRelativePath; using (FileStream file = File.OpenRead (fileSpec.SourcePath)) { FileType targetType = Target.TargetSpecificFileType (type); long startOffset = AddToBundle (번들, 파일, targetType); FileEntry 항목 = BundleManifest.AddEntry (targetType, relativePath, startOffset, file.Length); Tracer.Log ($“Embed : {entry}”); } }












// 번들 매니페스트 작성
headerOffset = BundleManifest.Write (writer);

}
흡수 재료 : www.goodsmaterial.com

추천

출처blog.csdn.net/weixin_45032957/article/details/108484978