J’essaie de créer un paquetage NuGet pour un assemblage .Net qui correspond à une DLL native win32. Je dois emballer l’assembly et la DLL native avec l’assembly ajouté aux références du projet (pas de problème à ce stade) et la DLL native doit être copiée dans le répertoire de sortie du projet ou dans un autre répertoire relatif.
Mes questions sont:
L’utilisation de la cible Copy
dans le fichier cible pour copier les bibliothèques requirejses ne copiera pas ces fichiers vers d’autres projets faisant référence au projet, entraînant une DllNotFoundException
. Cela peut être fait avec un fichier cible beaucoup plus simple, en utilisant un élément None
, car MSBuild copiera tous les fichiers None
dans les projets de référence.
%(RecursiveDir)%(FileName)%(Extension) PreserveNewest
Ajoutez le fichier cible au répertoire de génération du package nuget avec les bibliothèques natives requirejses. Le fichier de cibles inclura tous les fichiers dll
dans tous les répertoires enfants du répertoire de build
. Donc, pour append une version x86
et x64
d’une bibliothèque native utilisée par un assembly géré Any CPU
, vous devriez vous retrouver avec une structure de répertoire similaire à celle-ci:
Les mêmes répertoires x86
et x64
seront créés dans le répertoire de sortie du projet lors de sa construction. Si vous n’avez pas besoin de sous-répertoires, vous pouvez supprimer le **
et le %(RecursiveDir)
et inclure directement les fichiers requirejs dans le répertoire de build
. D’autres fichiers de contenu requirejs peuvent également être ajoutés de la même manière.
Les fichiers ajoutés en tant que None
dans le fichier cible ne seront pas affichés dans le projet lorsqu’ils seront ouverts dans Visual Studio. Si vous vous demandez pourquoi je n’utilise pas le dossier Content
dans nupkg, c’est qu’il est impossible de définir l’élément CopyToOutputDirectory
sans utiliser un script powershell (qui ne sera exécuté que dans Visual Studio, pas à partir de l’invite de commande, sur les serveurs de génération). ou dans d’autres IDE, et n’est pas pris en charge dans les projets DNX project.json / xproj ) et je préfère utiliser un Link
vers les fichiers plutôt que d’avoir une copie supplémentaire des fichiers dans le projet.
Mise à jour: Bien que cela devrait également fonctionner avec Content
plutôt qu’avec None
il semble qu’il y ait un bogue dans msbuild pour que les fichiers ne soient pas copiés sur les projets référencés plus d’une étape (par exemple, proj1 -> proj2 -> proj3 les fichiers du package NuGet de proj1 mais proj2 le seront).
J’ai récemment eu le même problème lorsque j’ai essayé de créer un paquet EmguCV NuGet comprenant à la fois des assemblys gérés et des liraries partagés non gérés (qui devaient également être placés dans un sous-répertoire x86
) qui devaient être copiés automatiquement après chaque construire.
Voici une solution que j’ai imaginée, qui repose uniquement sur NuGet et MSBuild:
Placez les assemblys gérés dans le répertoire /lib
du package (partie évidente) et les bibliothèques partagées non gérées et les fichiers associés (par exemple les packages .pdb) dans le sous-répertoire /build
(comme décrit dans les documents NuGet ).
Renommez toutes les terminaisons de fichiers *.dll
non gérées en quelque chose de différent, par exemple *.dl_
pour empêcher NuGet de se plaindre des assemblys présumés placés au mauvais endroit ( “Problème: Assemblage en dehors du dossier lib” ).
Ajoutez un
dans le sous-répertoire /build
avec le contenu suivant (voir ci-dessous pour une description):
x86 $(PrepareForRunDependsOn); CopyNativeBinaries
Le fichier .targets
ci-dessus sera injecté sur une installation du package NuGet dans le fichier de projet cible et est responsable de la copie des bibliothèques natives dans le répertoire de sortie.
ajoute un nouvel élément “Build Action” pour le projet (qui devient également disponible dans la liste déroulante “Build Action” dans Visual Studio).
Voici une alternative qui utilise les .targets
pour injecter la DLL native dans le projet avec les propriétés suivantes.
Build action
= None
Copy to Output Directory
= Copy if newer
Le principal avantage de cette technique est que la DLL native est copiée de manière transitoire dans le dossier bin/
des projets dépendants .
Voir la présentation du fichier .nuspec
:
Voici le fichier .targets
:
MyNativeLib.dll PreserveNewest
Cela insère le MyNativeLib.dll
comme si il faisait partie du projet d’origine (mais curieusement, le fichier n’est pas visible dans Visual Studio).
Notez l’élément qui définit le nom du fichier de destination dans le dossier
bin/
.
C’est un peu tard mais j’ai créé un paquet nuget exaclty pour cela.
L’idée est d’avoir un dossier spécial supplémentaire dans votre package nuget. Je suis sûr que vous connaissez déjà Lib et Content. Le paquet nuget que j’ai créé recherche un dossier nommé Output et copiera tout ce qui s’y trouve dans le dossier de sortie des projets.
La seule chose à faire est d’append une dépendance nuget au package http://www.nuget.org/packages/Baseclass.Consortingb.Nuget.Output/
J’ai écrit un article de blog à ce sujet: http://www.baseclass.ch/blog/Lists/Beitraege/Post.aspx?ID=6&mobile=0
Si quelqu’un trébuche à ce sujet.
Le .targets
fichier .targets
DOIT être égal à l’ID de package NuGet
Tout le rest ne fonctionnera pas.
Crédits à: https://sushihangover.github.io/nuget-and-msbuild-targets/
J’aurais dû lire plus en détail comme cela a été noté ici. M’a pris des âges ..
Ajouter un
.targets
Il y a une solution C # pure que je trouve assez facile à utiliser et je n’ai pas à me soucier des limitations de NuGet. Suivez ces étapes:
Incluez la bibliothèque native dans votre projet et définissez sa propriété Action de Embedded Resource
sur Embedded Resource
.
Collez le code suivant dans la classe où vous invoquez cette bibliothèque.
private static void UnpackNativeLibrary(ssortingng libraryName) { var assembly = Assembly.GetExecutingAssembly(); ssortingng resourceName = $"{assembly.GetName().Name}.{libraryName}.dll"; using (var stream = assembly.GetManifestResourceStream(resourceName)) using (var memoryStream = new MemoryStream(stream.CanSeek ? (int)stream.Length : 0)) { stream.CopyTo(memoryStream); File.WriteAllBytes($"{libraryName}.dll", memoryStream.ToArray()); } }
Appelez cette méthode à partir du constructeur statique comme suit: UnpackNativeLibrary("win32");
et il déballera la bibliothèque sur le disque juste avant que vous en ayez besoin. Bien entendu, vous devez vous assurer que vous disposez des droits en écriture sur cette partie du disque.
C’est une vieille question, mais j’ai le même problème maintenant, et j’ai trouvé un délai un peu délicat mais très simple et efficace: créer dans le dossier de contenu standard de Nuget la structure suivante avec un sous-dossier pour chaque configuration:
/Content /bin /Debug native libraries /Release native libraries
Lorsque vous compressez le fichier nuspec, vous recevrez le message suivant pour chaque bibliothèque native dans les dossiers Debug et Release:
Problème: Assemblage en dehors du dossier lib. Description: L’assembly ‘Content \ Bin \ Debug \ ??????. Dll’ ne se trouve pas dans le dossier ‘lib’ et ne sera donc pas ajouté comme référence lorsque le package est installé dans un projet. Solution: Déplacez-le dans le dossier ‘lib’ s’il doit être référencé.
Nous n’avons pas besoin d’une telle “solution” car ce n’est que notre objective: les bibliothèques natives ne sont pas ajoutées en tant que références aux assemblages NET.
Les avantages sont:
Les inconvénients sont:
Je ne peux pas résoudre votre problème exact, mais je peux vous donner une suggestion.
Votre exigence principale est la suivante: “Et ne pas enregistrer automatiquement la référence” …..
Vous devrez donc vous familiariser avec les “éléments de solution”
Voir la référence ici:
Ajout d’éléments de niveau solution dans un package NuGet
Vous devrez écrire un peu de voodoo PowerShell pour obtenir la copie de votre DLL native dans sa maison (encore une fois, parce que vous ne voulez PAS que le vaudou à référence automatique soit déclenché)
Voici un fichier ps1 que j’ai écrit ….. pour placer des fichiers dans un dossier de références tierces.
Il y a suffisamment de place pour vous permettre de copier votre dll natif dans un certain “home” … sans avoir à recommencer à zéro.
Encore une fois, ce n’est pas un coup direct, mais c’est mieux que rien.
param($installPath, $toolsPath, $package, $project) if ($project -eq $null) { $project = Get-Project } Write-Host "Start Init.ps1" <# The unique identifier for the package. This is the package name that is shown when packages are listed using the Package Manager Console. These are also used when installing a package using the Install-Package command within the Package Manager Console. Package IDs may not contain any spaces or characters that are invalid in an URL. #> $separator = " " $packageNameNoVersion = $package -split $separator | select -First 1 Write-Host "installPath:" "${installPath}" Write-Host "toolsPath:" "${toolsPath}" Write-Host "package:" "${package}" <# Write-Host "project:" "${project}" #> Write-Host "packageNameNoVersion:" "${packageNameNoVersion}" Write-Host " " <# Recursively look for a .sln file starting with the installPath #> $parentFolder = (get-item $installPath) do { $parentFolderFullName = $parentFolder.FullName $latest = Get-ChildItem -Path $parentFolderFullName -File -Filter *.sln | Select-Object -First 1 if ($latest -ne $null) { $latestName = $latest.name Write-Host "${latestName}" } if ($latest -eq $null) { $parentFolder = $parentFolder.parent } } while ($parentFolder -ne $null -and $latest -eq $null) <# End recursive search for .sln file #> if ( $parentFolder -ne $null -and $latest -ne $null ) { <# Create a base directory to store Solution-Level items #> $thirdPartyReferencesDirectory = $parentFolder.FullName + "\ThirdPartyReferences" if ((Test-Path -path $thirdPartyReferencesDirectory)) { Write-Host "--This path already exists: $thirdPartyReferencesDirectory-------------------" } else { Write-Host "--Creating: $thirdPartyReferencesDirectory-------------------" New-Item -ItemType directory -Path $thirdPartyReferencesDirectory } <# Create a sub directory for only this package. This allows a clean remove and recopy. #> $thirdPartyReferencesPackageDirectory = $thirdPartyReferencesDirectory + "\${packageNameNoVersion}" if ((Test-Path -path $thirdPartyReferencesPackageDirectory)) { Write-Host "--Removing: $thirdPartyReferencesPackageDirectory-------------------" Remove-Item $thirdPartyReferencesPackageDirectory -Force -Recurse } if ((Test-Path -path $thirdPartyReferencesPackageDirectory)) { } else { Write-Host "--Creating: $thirdPartyReferencesPackageDirectory-------------------" New-Item -ItemType directory -Path $thirdPartyReferencesPackageDirectory } Write-Host "--Copying all files for package : $packageNameNoVersion-------------------" Copy-Item $installPath\*.* $thirdPartyReferencesPackageDirectory -recurse } else { Write-Host "A current or parent folder with a .sln file could not be located." } Write-Host "End Init.ps1"
Mettez le dossier de contenu
la commande nuget pack [projfile].csproj
fera automatiquement pour vous si vous marquez les fichiers en tant que contenu.
puis éditez le fichier de projet comme mentionné ici en ajoutant l’élément ItemGroup & NativeLibs & None
%(RecursiveDir)%(FileName)%(Extension) PreserveNewest
travaillé pour moi