c# - Extracción automática de archivos DLL nativos y administrados que se extraen del paquete Nuget
asp.net-core nuget-package (1)
Trataré de explicar todo el dolor y las soluciones por las que he pasado lo más detallado posible.
En mi ejemplo, uso archivos de texto simples
AAA86.txt
,
AAA64.txt
y
AAAany.txt
lugar de archivos DLL nativos para simplemente demostrar el proceso de extracción.
Lo primero que debe saber:
si intenta mezclar la arquitectura
native
NuGet con una carpeta
lib
contiene algunas bibliotecas administradas,
NO FUNCIONARÁ
En ese caso, las DLL administradas se copiarán en el directorio de salida de su proyecto, pero NO en las nativas.
Gracias a Jon Skeet que me señaló en la buena dirección, aconsejándome que eche un vistazo al
paquete Grpc.Core
.
El truco es crear un archivo de
targets
que manejará la extracción de DLL.
Su archivo de objetivos debe contener algo como esto
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Condition=" ''$(Platform)'' == ''x64'' ">
<Content Include="$(MSBuildThisFileDirectory)../../runtimes/win-x64/native/AAA64.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>AAA64.txt</Link>
</Content>
</ItemGroup>
<ItemGroup Condition=" ''$(Platform)'' == ''x86'' OR ''$(Platform)'' == ''AnyCPU'' ">
<Content Include="$(MSBuildThisFileDirectory)../../runtimes/win-x86/native/AAA86.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>AAA86.txt</Link>
</Content>
</ItemGroup>
</Project>
Ahora hay algunas otras cosas que debes saber:
1)
Visual Studio
no se preocupa
en absoluto por la configuración que elija, siempre usará un RID ficticio.
(En mi caso, siempre termino con una carpeta
win7-x64
aunque estoy en Windows 10 ...)
2)
La
configuración de la plataforma
en su
project.json
también es totalmente inútil
{
"buildOptions": {
"platform": "x64"
}
}
3)
En la
configuración de tiempos de ejecución
si establece solo
win
y / o
win-x64
"runtimes": {
"win": {},
"win-x64": {}
}
Visual Studio en su lugar usará
win7-x64
.
Pero si agrega
win10-x64
mientras está en una máquina con Windows 10, entonces se usará
4) Si compila su aplicación con un RID genérico como este
dotnet build -c debug -r win
Luego, su archivo de
targets
recibirá la arquitectura de su máquina (x64 en mi caso) en lugar de
AnyCPU
como esperaba
5)
Si solo tiene bibliotecas nativas sin ninguna administrada, la extracción funcionará sin un archivo de destino si sigue los
runtimes/RID/native
la arquitectura
runtimes/RID/native
6)
Con SOLO bibliotecas nativas en mi paquete, el RID elegido siempre se construirá con
win-x64
con Visual Studio, como le dije, la carpeta de tiempo de ejecución siempre creada es
win7-x64
, sin importar la configuración que seleccione.
Si solo tuviera un RID de una sola
win
en mi paquete, se seleccionará con éxito.
Esto me está volviendo loco durante varios meses y todavía no puedo lograrlo. Mis bibliotecas administradas se extraen del paquete Nuget pero no las nativas.
Tenemos un montón de bibliotecas administradas y nativas proporcionadas por otra compañía.
Tenemos versiones
x86
y
x64
de ellos.
Para usarlos en un proyecto ASP.NET Core, tengo que crear un paquete Nuget.
Mi arquitectura es:
- una biblioteca de clase ASP.NET Core que cambié para apuntar solo a .NET Framework completo. Este proyecto hace referencia a mi paquete Nuget
- un sitio web ASP.NET Core también dirigido a .NET Framework completo y haciendo referencia a la biblioteca de clases
Por supuesto, al final, necesito que mis bibliotecas nativas se extraigan a la carpeta de tiempo de ejecución adecuada del sitio web (por ejemplo:
/bin/Debug/net461/win7-x64
).
Por el momento mi solución fue:
-
para poner las bibliotecas nativas dentro de la carpeta de
build
-
cree un archivo de
targets
que los$(OutputPath)
(que ni siquiera es la carpeta de tiempo de ejecución) -
agregar algunos comandos de
xproj
alxproj
de mi sitio web para obtener el archivo de destino en mi carpeta$(USERPROFILE)/.nuget/packages/
y ejecutarlo -
copie
a mano
las DLL nativas ahora extraídas en la carpeta
bin
alruntime
Intenté copiarlos directamente a la carpeta de tiempo de ejecución usando alguna configuración en
project.json
(sinceramente, no recuerdo todas las cosas que intenté para esta parte), pero esto siempre fallaba.
Además, aunque especifiqué
SkipUnchangedFiles="true"
en mi archivo de objetivos, esto simplemente se ignora y mis archivos DLL se copian en mi carpeta bin durante cada compilación.
Este es un proceso pesado solo para lograr una extracción de DLL, ahora realmente quiero deshacerme de todo eso MsBuild y obtener una solución mucho más simple.
Sé que con las versiones más nuevas de Nuget, ahora es capaz de extraerlas de forma nativa sin la ayuda de agregar comandos personalizados MsBuild.
Como está escrito
here
, los proyectos de C # ni siquiera necesitan un archivo de
targets
A continuación, los proyectos de C ++ y JavaScript que pueden consumir su paquete NuGet necesitan un archivo .targets para identificar el ensamblaje necesario y los archivos winmd. (Los proyectos de C # y Visual Basic hacen esto automáticamente).
Mantuve una pestaña abierta en mi navegador durante varios meses (
enlace original
) y me di cuenta de que este recurso se ha eliminado recientemente del sitio web de Nuget.
Explicaba cómo usar la carpeta de
runtimes
para extraer automáticamente las DLL nativas.
Sin embargo, nunca he podido obtener un resultado exitoso como se explicó.
Ahora esta página ha sido eliminada y reemplazada por
esta
con tan pocas explicaciones y sin hablar de esta carpeta de
runtimes
.
Supongo que debería usar la carpeta de
runtimes
para las DLL nativas y la
lib
para las administradas, pero no estoy 100% seguro de eso.
(¿también debería usar la carpeta de
build
?)
He intentado varias cosas (no puedo recordar el número de intentos, como dije varios meses de dolor de cabeza ...) como
esta arquitectura
(no entiendo cuál es el punto de tener carpetas de
build/native
y nativas en
runtimes
)
También intenté usar la estructura de versión de .NET Framework como se describe here para mis bibliotecas administradas.
This parece ser también parte de la solución.
El compilador ignora la arquitectura al crear una referencia de ensamblaje. Es un concepto de tiempo de carga. El cargador preferirá una referencia específica de arquitectura si existe.
Un truco que puede usar para producir un ensamblaje AnyCPU es usar corflags para eliminar la arquitectura de su ensamblaje x86. Por ejemplo: corflags / 32BITREQ- MySDK.dll. Corflags es parte del SDK de .NET y se puede encontrar en el símbolo del sistema del desarrollador de VS.
Eso es lo que hice, convirtiendo las DLL x86 y x64 a
AnyCPU
(no sé si hace algo para las DLL x64 pero no obtuve errores) y luego probé varias arquitecturas diferentes en mi paquete Nuget pero aún no funciona.
El tiempo de ejecución predeterminado sin ninguna entrada en project.json es
win7-x64
, por lo que decidí especificarlo explícitamente por si acaso
"runtimes": {
"win7-x64": {}
},
Así que este es el identificador de tiempo de ejecución que estoy usando para todos mis intentos en mi paquete Nuget. Sin embargo, no me importa la versión de Windows. De hecho, preferiría tener win-x86 o win-x64 pero parece ser un valor no válido de acuerdo con esta página
RID de Windows
Windows 7 / Windows Server 2008 R2
- win7-x64
- win7-x86
Windows 8 / Windows Server 2012
- win8-x64
- win8-x86
- win8-arm
Windows 8.1 / Windows Server 2012 R2
- win81-x64
- win81-x86
- win81-arm
Windows 10 / Windows Server 2016
- win10-x64
- win10-x86
- win10-arm
- win10-arm64
Sin embargo, esta fuente de Github está describiendo más RID, ¿cuál es la fuente correcta?
Como puede ver, hay tantos misterios aquí, principalmente debido a la falta de documentación o incluso a contradicciones entre diferentes documentos.
Si al menos pudiera tener un ejemplo de trabajo, podría realizar mis pruebas para responder otras preguntas, como probar RID
win-x64
genérico o ver si puedo incluir una vez que mis bibliotecas administradas sean cuales sean las versiones de .NET Framework.
Preste atención a mi contexto especial: tengo un proyecto ASP.NET Core dirigido a .NET Framework completo
Gracias por sus respuestas, estoy desesperado por hacer que esto funcione.