这篇答案基于.NET Framework库打包原则和通用Windows平台库打包原则。请先阅读相关链接以更好地理解以下内容。
我假设你的所有特定架构构建都公开相同的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 文档和资源文件,而架构特定的资产则结构化在运行时目录下。
大部分内容都很简单,可以通过使用基于以下模板创建的 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>
<file src="..\bin\Reference\Release\MultiArchitectureUwpLibrary.dll" target="ref\uap10.0" />
<file src="..\bin\x86\Release\MultiArchitectureUwpLibrary.xml" target="ref\uap10.0" />
<file src="..\bin\x86\Release\MultiArchitectureUwpLibrary.pri" target="ref\uap10.0" />
<file src="..\bin\x86\Release\MultiArchitectureUwpLibrary\*" target="ref\uap10.0\MultiArchitectureUwpLibrary" />
<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表面,因此我们可以简单地选择其中任何一个,并指示编译器使用它作为参考程序集。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包之前,请记得使用发布配置为
所有架构构建您的解决方案。
一个示例库和相关的打包文件可在
GitHub上获取。对应于此答案的解决方案是MultiArchitectureUwpLibrary。