Этот ответ основан на принципах упаковки библиотеки .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>
<!-- 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, мы можем просто взять любую из них и указать компилятору использовать ее в качестве эталонной сборки. 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.
person
Sander
schedule
05.01.2016