147 votes

Ajouter les fichiers natifs du package NuGet au répertoire de sortie du projet

Je suis en train de créer un package NuGet pour une assembly .Net qui appelle une dll native Win32. Je dois packager à la fois l'assembly et la dll native avec l'assembly ajouté aux références du projet (pas de problème à ce niveau) 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 :

  1. Comment puis-je packager la dll native sans que Visual Studio essaie de l'ajouter à la liste des références ?
  2. Dois-je écrire un install.ps1 pour copier la dll native ? Si oui, comment puis-je accéder au contenu du package pour la copier ?

154voto

kjbartel Points 453

En utilisant la cible Copy dans le fichier des cibles pour copier les bibliothèques requises, ces fichiers ne seront pas copiés vers d'autres projets qui font référence au projet, ce qui entraîne une DllNotFoundException. Cela peut être fait avec un fichier cibles beaucoup plus simple cependant, en utilisant un élément None, car MSBuild copiera tous les fichiers None vers les projets de référence.

      %(RecursiveDir)%(FileName)%(Extension)
      PreserveNewest

Ajoutez le fichier des cibles au répertoire build du paquet nuget avec les bibliothèques natives requises. Le fichier des cibles inclura tous les fichiers dll dans tous les sous-répertoires du répertoire build. Ainsi, pour ajouter une version x86 et x64 d'une bibliothèque native utilisée par un assembly managé Any CPU, vous obtiendrez une structure de répertoire similaire à la suivante :

  • build
    • x86
      • NativeLib.dll
      • NativeLibDependency.dll
    • x64
      • NativeLib.dll
      • NativeLibDependency.dll
    • MyNugetPackageID.targets
  • lib
    • net40
      • ManagedAssembly.dll

Les mêmes répertoires x86 et x64 seront créés dans le répertoire de sortie du projet lorsqu'il est construit. Si vous n'avez pas besoin de sous-répertoires, alors les ** et %(RecursiveDir) peuvent être supprimés et incluez plutôt les fichiers requis directement dans le répertoire build. D'autres fichiers de contenu requis peuvent également être ajoutés de la même manière.

Les fichiers ajoutés en tant que None dans le fichier des cibles ne seront pas affichés dans le projet lorsqu'il est ouvert dans Visual Studio. Si vous vous demandez pourquoi je n'utilise pas le dossier Content dans le nupkg, c'est parce qu'il n'y a aucun moyen de définir l'élément CopyToOutputDirectory sans utiliser un script powershell (qui ne sera exécuté que dans Visual Studio, pas depuis l'invite de commandes, sur des serveurs de build 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 que None, il semble qu'il y ait un bug dans msbuild, donc les fichiers ne seront pas copiés vers les projets de référence à plus d'un niveau (par ex. proj1 -> proj2 -> proj3, proj3 ne recevra pas les fichiers du paquet NuGet de proj1 mais proj2 le fera).

33voto

Benoit Blanchon Points 2252

Voici une alternative qui utilise le .targets pour injecter le DLL natif dans le projet avec les propriétés suivantes.

  • Action de génération = Aucun
  • Copier dans le répertoire de sortie = Copier si plus récent

Le principal avantage de cette technique est que le DLL natif est copié dans le dossier bin/ des projets dépendants de manière transitive.

Consultez la disposition du fichier .nuspec:

Capture d'écran de NuGet Package Explorer

Voici le fichier .targets:

            MyNativeLib.dll
            PreserveNewest

Cela insère le MyNativeLib.dll comme s'il faisait partie du projet d'origine (mais curieusement le fichier n'est pas visible dans Visual Studio).

Remarquez l'élément qui définit le nom du fichier de destination dans le dossier bin/.

30voto

buygrush Points 196

J'ai récemment rencontré le même problème lorsque j'ai essayé de construire un package NuGet EmguCV incluant à la fois des assemblies gérées et des bibliothèques partagées non gérées (qui devaient également être placées dans un sous-répertoire x86) devant être copiés automatiquement dans le répertoire de sortie de la construction après chaque construction.

Voici la solution à laquelle je suis parvenu, qui repose uniquement sur NuGet et MSBuild :

  1. Placez les assemblies gérées 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 des fichiers .pdb) dans le sous-répertoire /build (comme décrit dans la documentation de NuGet).

  2. Renommez toutes les fins de fichiers non gérés *.dll en quelque chose de différent, par exemple *.dl_ pour empêcher NuGet de se plaindre d'assemblages prétendument placés au mauvais endroit ("Problème : Assemblage en dehors du répertoire lib.").

  3. Ajoutez un fichier .targets personnalisé dans le sous-répertoire /build avec un contenu similaire à ce qui suit (voir ci-dessous pour une description) :

      x86
    
      $(PrepareForRunDependsOn);
      CopyNativeBinaries

Le fichier .targets ci-dessus sera injecté lors de l'installation du package NuGet dans le fichier projet cible et est responsable de copier les bibliothèques natives dans le répertoire de sortie.

  • ajoute un nouvel élément "Action de construction" pour le projet (qui est également disponible dans le menu déroulant "Action de construction" dans Visual Studio).

  • Microsoft.Common.targets pour plus de détails.

* La cible personnalisée, `CopyNativeBinaries`, contient deux tâches de copie. La première est responsable de copier tous les fichiers **`*.dl_`** dans le répertoire de sortie tout en changeant leur extension en **`*.dll`** d'origine. La deuxième copie simplement le reste (par exemple tous les fichiers **`*.pdb`**) au même emplacement. Cela pourrait être remplacé par une seule tâche de copie et un script [install.ps1](http://docs.nuget.org/docs/creating-packages/creating-and-publishing-a-package#Automatically_Running_PowerShell_Scripts_During_Package_Installation_and_Removal) qui devrait renommer tous les fichiers **`*.dl_`** en **`*.dll`** lors de l'installation du package.

`

Cependant, cette solution ne copierait toujours pas les bibliothèques natives dans le répertoire de sortie d'un autre projet faisant référence à celui qui inclut initialement le package NuGet. Vous devez toujours référencer le package NuGet dans votre projet "final" également.

`

25voto

DirtyLittleHelper Points 251

Si quelqu'un d'autre tombe dessus.

Le nom de fichier .targets DOIT être égal à l'identifiant du package NuGet

Autrement ça ne fonctionnera pas.

Crédits à : https://sushihangover.github.io/nuget-and-msbuild-targets/

J'aurais dû lire plus attentivement car c'est effectivement noté ici. Ça m'a pris des siècles..

Ajoutez un .targets personnalisé

13voto

Daniel Romero Points 71

Il est un peu tard, mais j'ai créé un package NuGet exactement 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 package 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 que vous avez à faire est d'ajouter une dépendance NuGet au package http://www.nuget.org/packages/Baseclass.Contrib.Nuget.Output/

J'ai écrit un article de blog à ce sujet : http://www.baseclass.ch/blog/Lists/Beitraege/Post.aspx?ID=6&mobile=0

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X