2016-01-05 18 views
11

Làm cách nào để gói một thư viện Nền tảng Universal Windows được viết bằng C# chỉ cung cấp các bản dựng phụ thuộc vào kiến ​​trúc? Vì mục đích minh hoạ, giả sử rằng tôi có một số mã kiến ​​trúc cụ thể được biên dịch theo điều kiện cho mỗi kiến ​​trúc (sử dụng #if ARM và tương đương).Làm thế nào để đóng gói một thư viện .NET đa kiến ​​trúc nhắm vào nền tảng Windows phổ thông?

Để rõ ràng, không có bản dựng AnyCPU nào tồn tại cho thư viện của tôi - chỉ x86, x64 và ARM.

Tình huống tương tự và có khả năng phổ biến hơn là nơi tôi có sự phụ thuộc vào thư viện bên ngoài chỉ được cung cấp dưới dạng bản dựng kiến ​​trúc cụ thể (ví dụ: Win2D). Để giữ cho bối cảnh đơn giản, chúng ta hãy giả sử không có phụ thuộc và chỉ có mã của riêng tôi là có liên quan - giải pháp cũng nên giảm theo cùng một cách.

Đây là một loạt các câu hỏi và câu trả lời mà tài liệu phát hiện của tôi về chủ đề hiện đại NuGet gói authoring, tập trung đặc biệt vào những thay đổi được giới thiệu với NuGet 3. Bạn cũng có thể quan tâm đến một số câu hỏi liên quan:

Trả lời

10

Câu trả lời này xây dựng dựa trên principles of .NET Framework library packagingprinciples of Universal Windows Platform library packaging. Đọc các câu trả lời được liên kết trước để hiểu rõ hơn những điều sau đây.

Tôi sẽ giả định rằng tất cả các bản dựng kiến ​​trúc cụ thể của bạn đều lộ ra cùng một bề mặt API, chỉ với việc triển khai các API đó khác nhau.

Biến chứng chính với kịch bản này là xây dựng chuỗi công cụ yêu cầu một hội đồng AnyCPU để giải quyết tham chiếu biên dịch, ngay cả khi hội đồng này không bao giờ được sử dụng khi chạy. Vì kịch bản của bạn không có đầu ra xây dựng AnyCPU, chúng tôi cần tìm giải pháp thay thế. Khái niệm áp dụng ở đây là các assembly tham chiếu - Các assembly AnyCPU chỉ được sử dụng tại thời gian biên dịch để xác nhận tham chiếu. Do đó, để xuất bản thư viện của bạn, bạn sẽ cần tạo một assembly tham chiếu và đóng gói các tài sản như được trình bày bên dưới.

Để đơn giản, tôi sẽ giả định rằng thư viện của bạn không phụ thuộc vào các gói NuGet khác. Đây không phải là trường hợp trong thực tế nhưng quản lý phụ thuộc đã được bao phủ bởi các câu trả lời khác được liên kết ở trên và do đó bị bỏ qua khỏi câu trả lời này.

Cấu trúc mong muốn của gói NuGet là như sau:

+---ref 
| \---uap10.0 
|  | MultiArchitectureUwpLibrary.dll 
|  | MultiArchitectureUwpLibrary.pri 
|  | MultiArchitectureUwpLibrary.XML 
|  | 
|  \---MultiArchitectureUwpLibrary 
|    ArchitectureControl.xaml 
|    MultiArchitectureUwpLibrary.xr.xml 
| 
+---runtimes 
| +---win10-arm 
| | \---lib 
| |  \---uap10.0 
| |    MultiArchitectureUwpLibrary.dll 
| |    MultiArchitectureUwpLibrary.pdb 
| | 
| +---win10-x64 
| | \---lib 
| |  \---uap10.0 
| |    MultiArchitectureUwpLibrary.dll 
| |    MultiArchitectureUwpLibrary.pdb 
| | 
| \---win10-x86 
|  \---lib 
|   \---uap10.0 
|     MultiArchitectureUwpLibrary.dll 
|     MultiArchitectureUwpLibrary.pdb 

Nếu bạn đã quen thân với những câu trả lời liên quan trên, các file tất cả nên được biết đến với bạn rồi, mặc dù cấu trúc thư mục là khá bất thường trong trường hợp này. Thư mục ref chứa tham chiếu, tài liệu XML và các tệp tài nguyên, trong khi các tài sản kiến ​​trúc cụ thể được cấu trúc theo thư mục runtimes.

Hầu hết trong số này là khá đơn giản và có thể được thực hiện bằng cách sử dụng một tập tin nuspec tạo dựa trên mẫu sau:

<?xml version="1.0"?> 
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> 
    <metadata minClientVersion="3.2"> 
     <id>Example.MultiArchitectureUwpLibrary</id> 
     <version>1.0.0</version> 
     <authors>Firstname Lastname</authors> 
     <description>Example of library that is published as a set of architecture-specific assmeblies for the UWP platform.</description> 
    </metadata> 
    <files> 
     <!-- Architecture-independent reference library for use at compile-time; generated by the PowerShell script. --> 
     <file src="..\bin\Reference\Release\MultiArchitectureUwpLibrary.dll" target="ref\uap10.0" /> 

     <!-- XML documentation file goes together with the reference library. --> 
     <file src="..\bin\x86\Release\MultiArchitectureUwpLibrary.xml" target="ref\uap10.0" /> 

     <!-- Resource files go together with the reference library. --> 
     <file src="..\bin\x86\Release\MultiArchitectureUwpLibrary.pri" target="ref\uap10.0" /> 
     <file src="..\bin\x86\Release\MultiArchitectureUwpLibrary\*" target="ref\uap10.0\MultiArchitectureUwpLibrary" /> 

     <!-- The architecture-specific files go in architecture-specific directories. --> 
     <file src="..\bin\x86\Release\MultiArchitectureUwpLibrary.dll" target="runtimes\win10-x86\lib\uap10.0" /> 
     <file src="..\bin\x86\Release\MultiArchitectureUwpLibrary.pdb" target="runtimes\win10-x86\lib\uap10.0" /> 

     <file src="..\bin\x64\Release\MultiArchitectureUwpLibrary.dll" target="runtimes\win10-x64\lib\uap10.0" /> 
     <file src="..\bin\x64\Release\MultiArchitectureUwpLibrary.pdb" target="runtimes\win10-x64\lib\uap10.0" /> 

     <file src="..\bin\arm\Release\MultiArchitectureUwpLibrary.dll" target="runtimes\win10-arm\lib\uap10.0" /> 
     <file src="..\bin\arm\Release\MultiArchitectureUwpLibrary.pdb" target="runtimes\win10-arm\lib\uap10.0" /> 
    </files> 
</package> 

Các mảnh mất tích, tất nhiên, là lắp ráp tham khảo. Rất may, điều này khá đơn giản để giải quyết - một assembly tham chiếu là một assembly AnyCPU định nghĩa cùng các lớp và các phương thức mà các assembly runtime chứa. Mục đích chính của nó là cung cấp cho trình biên dịch một tham chiếu để làm việc với, do đó trình biên dịch có thể xác minh rằng tất cả các cuộc gọi phương thức đều thực sự tham chiếu các phương thức sẽ tồn tại khi chạy. Mã thực tế trong assembly tham chiếu (nếu có) không được sử dụng cho bất cứ thứ gì.

Vì tất cả các bản dựng kiến ​​trúc cụ thể của bạn đều lộ ra cùng một bề mặt API, chúng ta có thể chỉ cần lấy một trong số chúng và hướng dẫn trình biên dịch sử dụng nó làm bộ tham chiếu. Windows SDK chứa một tiện ích có tên CorFlags.exe có thể được sử dụng để chuyển đổi một assembly x86 thành một assembly AnyCPU, làm cho điều này trở thành có thể.

Dưới đây là tập lệnh tạo gói tạo bảng tham chiếu bắt buộc trước khi đóng gói thư viện. Nó giả định Windows SDK được cài đặt ở vị trí tiêu chuẩn. Để hiểu chi tiết về logic, hãy xem các bình luận nội tuyến.

# Any assembly matching this filter will be transformed into an AnyCPU assembly. 
$referenceDllFilter = "MultiArchitectureUwpLibrary.dll" 

$programfilesx86 = "${Env:ProgramFiles(x86)}" 
$corflags = Join-Path $programfilesx86 "Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6 Tools\x64\CorFlags.exe" 

If (!(Test-Path $corflags)) 
{ 
    Throw "Unable to find CorFlags.exe" 
} 

$solutionRoot = Resolve-Path ..\.. 
$topLevelDirectories = Get-ChildItem $solutionRoot -Directory 
$binDirectories = $topLevelDirectories | %{ Get-ChildItem $_.FullName -Directory -Filter "bin" } 

# Create reference assemblies, because otherwise the NuGet packages cannot be used. 
# This creates them for all outputs that match the filter, in all output directories of all projects. 
# It's a bit overkill but who cares - the process is very fast and keeps the script simple. 
Foreach ($bin in $binDirectories) 
{ 
    $x86 = Join-Path $bin.FullName "x86" 
    $any = Join-Path $bin.FullName "Reference" 

    If (!(Test-Path $x86)) 
    { 
     Write-Host "Skipping reference assembly generation for $($bin.FullName) because it has no x86 directory." 
     continue; 
    } 

    if (Test-Path $any) 
    { 
     Remove-Item -Recurse $any 
    } 

    New-Item $any -ItemType Directory 
    New-Item "$any\Release" -ItemType Directory 

    $dlls = Get-ChildItem "$x86\Release" -File -Filter $referenceDllFilter 

    Foreach ($dll in $dlls) 
    { 
     Copy-Item $dll.FullName "$any\Release" 
    } 

    $dlls = Get-ChildItem "$any\Release" -File -Filter $referenceDllFilter 

    Foreach ($dll in $dlls) 
    { 
     Write-Host "Converting to AnyCPU: $dll" 

     & $corflags /32bitreq- $($dll.FullName) 
    } 
} 

# Delete any existing output. 
Remove-Item *.nupkg 

# Create new packages for any nuspec files that exist in this directory. 
Foreach ($nuspec in $(Get-Item *.nuspec)) 
{ 
    .\NuGet.exe pack "$nuspec" 
} 

Bạn có thể cần điều chỉnh đường dẫn trong tập lệnh để khớp với các quy ước được sử dụng trong giải pháp của bạn.

Chạy tập lệnh này để tạo gói NuGet cho phép thư viện của bạn được sử dụng trong tất cả các biến thể kiến ​​trúc cụ thể của nó! Hãy nhớ xây dựng giải pháp của bạn bằng cách sử dụng cấu hình Phát hành cho tất cả các cấu trúc trước khi tạo gói NuGet.

Thư viện mẫu và các tệp bao bì có liên quan là available on GitHub. Giải pháp tương ứng với câu trả lời này là MultiArchitectureUwpLibrary.

+0

Nếu bạn kiểm tra điều này, hãy đảm bảo thay đổi phiên bản. Tôi đã thử nghiệm nó và nó đầu tiên đã không làm việc. Bởi vì nuget seams vào cache nên nó không thể cài đặt gói. – lokimidgard

Các vấn đề liên quan