2016-01-05 14 views
11

アーキテクチャ依存のビルドのみを提供するC#で書かれたUniversal Windows Platformライブラリをどのようにパッケージ化しますか?説明のために、各アーキテクチャ(条件付きで#if ARMと同等のものを使用)でコンパイルされたアーキテクチャ固有のコードがいくつかあるとしましょう。ユニバーサルWindowsプラットフォームをターゲットとするマルチアーキテクチャの.NETライブラリをパッケージ化する方法は?

私のライブラリにはAnyCPUビルドはありません。x86、x64、ARMのみです。

同等の可能性が高い状況は、アーキテクチャ固有のビルド(例:Win2D)としてのみ提供される外部ライブラリに依存する状況です。コンテキストを単純に保つために、依存関係はなく、自分自身のコードだけが含まれていると仮定しましょう。どちらの方法でもソリューションが同じになるはずです。

これは、あなたはまた、いくつかの関連質問に興味がある可能性がありNuGet 3で導入された変更に特に焦点を当て、現代のNuGetパッケージのオーサリングのトピックに私の調査結果を文書質問と回答のシリーズです:

答えて

10

この回答はprinciples of .NET Framework library packagingprinciples of Universal Windows Platform library packaging上に構築されています。リンクされた答えを最初に読んで、以下をよりよく理解してください。

アーキテクチャ固有のすべてのビルドが、同じAPIサーフェスを公開していて、それらのAPIの実装のみが異なると仮定します。

このシナリオの主な問題は、ビルドツールチェーンには、このアセンブリが実行時に使用されない場合でも、コンパイル時参照解決のためにAnyCPUアセンブリが必要です。シナリオにAnyCPUビルドの出力がないため、回避策を見つける必要があります。ここで適用される概念は、参照アセンブリのものです - 参照検証のためにコンパイル時にのみ使用されるAnyCPUアセンブリ。したがって、ライブラリを公開するには、以下のように参照アセンブリを作成し、アセットをパッケージ化する必要があります。

簡単にするために、あなたのライブラリは他のNuGetパッケージに依存しないものとします。これは実際には当てはまりそうではありませんが、依存関係管理は既に上記の他の回答によってカバーされているため、この回答は省略されています。次のように

NuGetパッケージの所望の構造は、次のとおりです。

+---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 

あなたは上記のリンクの答えを自分で慣れている場合は、ディレクトリ構造はかなり珍しいですが、ファイルはすべて、すでにあなたに知られている必要がありますこの場合。 refディレクトリには、参照アセンブリ、XMLドキュメント、およびリソースファイルが格納され、アーキテクチャ固有のアセットはruntimesディレクトリの下に構造化されています。この最も

は非常に簡単ですし、次のテンプレートに基づいて作成nuspecファイルを使用することによって達成することができます。

<?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> 

不足している部分は、当然のことながら、参照アセンブリです。ありがたいことに、これは簡単に解決できます。参照アセンブリは、ランタイムアセンブリに含まれるものと同じクラスおよびメソッドを定義するAnyCPUアセンブリです。その主な目的は、コンパイラがすべてのメソッド呼び出しが実際に実行時に存在するメソッドを参照していることをコンパイラが検証できるように、コンパイラに参照を渡すことです。参照アセンブリ内の実際のコード(存在する場合)は何のためにも使用されません。

アーキテクチャー固有のビルドはすべて同じAPIサーフェスを公開しているので、それらのいずれか1つを取り出し、参照アセンブリとして使用するようコンパイラーに指示するだけです。 Windows SDKには、CorFlags.exeという名前のユーティリティが含まれています。このユーティリティを使用すると、x86アセンブリをAnyCPUアセンブリに変換し、これを可能にすることができます。

以下は、ライブラリをパッケージ化する前に必要な参照アセンブリを作成するパッケージ作成スクリプトです。 Windows SDKが標準の場所にインストールされていることを前提としています。ロジックの詳細を理解するには、インラインコメントを参照してください。

# 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" 
} 

解決策で使用されている規則に合わせてスクリプトのパスを調整する必要がある場合があります。

このスクリプトを実行すると、ライブラリがアーキテクチャ固有のすべてのバリアントで使用できるNuGetパッケージが作成されます。 NuGetパッケージを作成する前に、すべてののリリース構成を使用してソリューションを構築することを忘れないでください。

サンプルライブラリと関連パッケージファイルはavailable on GitHubです。この答えに対応するソリューションはMultiArchitectureUwpLibraryです。

+0

これをテストする場合は、必ずバージョンを変更してください。私はそれをテストし、最初はうまくいきませんでした。なぜなら、パッケージをインストールすることはできないということです。 – lokimidgard

関連する問題