Ich versuche, ein NuGet-Paket für eine .Net-Assembly zu erstellen, die Pinvoke für eine native Win32-DLL ausführt. Ich muss sowohl die Assembly als auch die native DLL packen, wobei die Assembly zu den Projektreferenzen hinzugefügt wird (in diesem Teil kein Problem), und die native DLL sollte in das Projektausgabeverzeichnis oder ein anderes relatives Verzeichnis kopiert werden.
Meine Fragen sind:
- Wie packe ich die native DLL, ohne dass Visual Studio versucht, sie in die Referenzliste aufzunehmen?
- Muss ich eine install.ps1 schreiben, um die native DLL zu kopieren? Wenn ja, wie kann ich auf den Paketinhalt zugreifen, um ihn zu kopieren?
nuget
nuget-package
nuget-spec
AlonFStackoverflow
quelle
quelle
Antworten:
Wenn Sie das
Copy
Ziel in der Zieldatei zum Kopieren der erforderlichen Bibliotheken verwenden, werden diese Dateien nicht in andere Projekte kopiert, die auf das Projekt verweisenDllNotFoundException
. Dies kann jedoch mit einer viel einfacheren Zieldatei unter Verwendung einesNone
Elements erfolgen, da MSBuild alleNone
Dateien in referenzierende Projekte kopiert .Fügen Sie die Zieldatei
build
zusammen mit den erforderlichen nativen Bibliotheken zum Verzeichnis des Nuget-Pakets hinzu. Die Zieldatei enthält alledll
Dateien in allen untergeordneten Verzeichnissen desbuild
Verzeichnisses. Wenn Sie also einex86
undx64
-Version einer nativen Bibliothek hinzufügen, die von einerAny CPU
verwalteten Assembly verwendet wird, erhalten Sie eine Verzeichnisstruktur, die der folgenden ähnelt:Das gleiche
x86
undx64
Verzeichnisse werden beim Erstellen im Ausgabeverzeichnis des Projekts erstellt. Wenn Sie keine Unterverzeichnisse benötigen, können die**
und%(RecursiveDir)
entfernt werden und stattdessen die erforderlichen Dateienbuild
direkt in das Verzeichnis aufnehmen. Auf die gleiche Weise können auch andere erforderliche Inhaltsdateien hinzugefügt werden.Die wie
None
in der Zieldatei hinzugefügten Dateien werden beim Öffnen in Visual Studio nicht im Projekt angezeigt. Wenn Sie sich fragen, warum ich denContent
Ordner im nupkg nicht verwende, liegt dies daran, dass es keine Möglichkeit gibt, dasCopyToOutputDirectory
Element ohne Verwendung eines Powershell-Skripts festzulegen (das nur in Visual Studio ausgeführt wird, nicht über die Eingabeaufforderung, auf Build-Servern oder in andere IDEs und wird in project.json / xproj-DNX-Projekten nicht unterstützt. Ich bevorzuge die Verwendung von aLink
für die Dateien, anstatt eine zusätzliche Kopie der Dateien im Projekt zu haben.Update: Obwohl dies auch funktionieren sollte,
Content
anstattNone
dass es einen Fehler in msbuild gibt, werden Dateien nicht mehr als einen Schritt entfernt in Referenzprojekte kopiert (z. B. proj1 -> proj2 -> proj3, proj3 erhält die Dateien nicht aus dem NuGet-Paket von proj1, aber proj2 wird).quelle
'$(MSBuildThisFileDirectory)' != '' And HasTrailingSlash('$(MSBuildThisFileDirectory)')
erforderlich ist? Ich dachte, dass dasMSBuildThisFileDirectory
immer eingestellt ist. Wann wäre das nicht der Fall?**\*.dll
? Das kopiert alle.dll
Dateien in alle Verzeichnisse. Sie können leicht**\*.*
einen ganzen Verzeichnisbaum kopieren.Ich hatte kürzlich das gleiche Problem, als ich versuchte, ein EmguCV NuGet-Paket zu erstellen, das sowohl verwaltete Assemblys als auch nicht verwaltete gemeinsam genutzte Liraries (die ebenfalls in einem
x86
Unterverzeichnis abgelegt werden mussten ) enthielt und nach jedem Build automatisch in das Build-Ausgabeverzeichnis kopiert werden musste .Hier ist eine Lösung, die ich gefunden habe und die nur auf NuGet und MSBuild basiert:
Platzieren Sie die verwalteten Assemblys im
/lib
Verzeichnis des Pakets (offensichtlicher Teil) und die nicht verwalteten gemeinsam genutzten Bibliotheken und zugehörigen Dateien (z. B. .pdb-Pakete) im/build
Unterverzeichnis (wie in den NuGet-Dokumenten beschrieben ).Benennen Sie alle nicht verwalteten
*.dll
Dateiendungen in etwas anderes um, um beispielsweise*.dl_
zu verhindern, dass NuGet darüber stöhnt, dass angebliche Assemblys an einer falschen Stelle platziert wurden ( "Problem: Assembly außerhalb des lib-Ordners" ).Fügen Sie
<PackageName>.targets
im/build
Unterverzeichnis eine benutzerdefinierte Datei mit den folgenden Inhalten hinzu (eine Beschreibung finden Sie unten):Die obige
.targets
Datei wird bei einer Installation des NuGet-Pakets in der Zielprojektdatei eingefügt und ist für das Kopieren der nativen Bibliotheken in das Ausgabeverzeichnis verantwortlich.<AvailableItemName Include="NativeBinary" />
Fügt ein neues Element "Aktion erstellen" für das Projekt hinzu (das auch in der Dropdown-Liste "Aktion erstellen" in Visual Studio verfügbar ist).<NativeBinary Include="...
Fügt die nativen Bibliotheken hinzu, die/build/x86
dem aktuellen Projekt hinzugefügt wurden, und macht sie für das benutzerdefinierte Ziel zugänglich, das diese Dateien in das Ausgabeverzeichnis kopiert.<TargetPath>x86</TargetPath>
Fügt den Dateien benutzerdefinierte Metadaten hinzu und weist das benutzerdefinierte Ziel an, die nativen Dateien in dasx86
Unterverzeichnis des tatsächlichen Ausgabeverzeichnisses zu kopieren .Der
<PrepareForRunDependsOn ...
Block fügt das benutzerdefinierte Ziel der Liste der Ziele hinzu, von denen der Build abhängt. Weitere Informationen finden Sie in der Datei Microsoft.Common.targets .Das benutzerdefinierte Ziel
CopyNativeBinaries
enthält zwei Kopieraufgaben. Der erste ist dafür verantwortlich, alle*.dl_
Dateien in das Ausgabeverzeichnis zu kopieren und ihre Erweiterung wieder auf das Original zu ändern*.dll
. Der zweite kopiert einfach den Rest (zum Beispiel alle*.pdb
Dateien) an denselben Speicherort. Dies könnte durch eine einzelne Kopieraufgabe und ein install.ps1- Skript ersetzt werden, in das alle*.dl_
Dateien*.dll
während der Paketinstallation umbenannt werden mussten.Diese Lösung würde jedoch die nativen Binärdateien immer noch nicht in das Ausgabeverzeichnis eines anderen Projekts kopieren, das auf dasjenige verweist, das ursprünglich das NuGet-Paket enthält. Sie müssen das NuGet-Paket auch in Ihrem "endgültigen" Projekt referenzieren.
quelle
DllNotFoundException
geworfen werden.<NoWarn>NU5100</NoWarn>
zu Ihrer Projektdatei hinzufügenHier ist eine Alternative , die die verwendet ,
.targets
um die native DLL in dem Projekt zu injizieren mit den folgenden Eigenschaften.Build action
=None
Copy to Output Directory
=Copy if newer
Der Hauptvorteil dieser Technik besteht darin, dass die native DLL transitiv in den
bin/
Ordner abhängiger Projekte kopiert wird .Siehe das Layout der
.nuspec
Datei:Hier ist die
.targets
Datei:Dadurch wird das eingefügt,
MyNativeLib.dll
als ob es Teil des ursprünglichen Projekts wäre (aber seltsamerweise ist die Datei in Visual Studio nicht sichtbar).Beachten Sie das
<Link>
Element, das den Namen derbin/
Zieldatei im Ordner festlegt .quelle
Content
zuNone
?Wenn jemand anderes darüber stolpert.
Der
.targets
Dateiname MUSS der NuGet-Paket-ID entsprechenAlles andere wird nicht funktionieren.
Credits gehen an: https://sushihangover.github.io/nuget-and-msbuild-targets/
Ich hätte gründlicher lesen sollen, wie es hier tatsächlich vermerkt ist. Hat ewig gedauert ..
quelle
Es ist ein bisschen spät, aber ich habe genau dafür ein Nuget-Paket erstellt.
Die Idee ist, einen zusätzlichen speziellen Ordner in Ihrem Nuget-Paket zu haben. Ich bin sicher, Sie kennen Lib und Content bereits. Das von mir erstellte Nuget-Paket sucht nach einem Ordner mit dem Namen "Ausgabe" und kopiert alles, was sich dort befindet, in den Ausgabeordner des Projekts.
Sie müssen dem Paket nur eine Nuget-Abhängigkeit hinzufügen. Http://www.nuget.org/packages/Baseclass.Contrib.Nuget.Output/
Ich habe einen Blog-Beitrag darüber geschrieben: http://www.baseclass.ch/blog/Lists/Beitraege/Post.aspx?ID=6&mobile=0
quelle
Es gibt eine reine C # -Lösung, die ich ziemlich einfach finde und mit der ich mich nicht mit NuGet-Einschränkungen beschäftigen muss. Folge diesen Schritten:
Fügen Sie die native Bibliothek in Ihr Projekt ein und setzen Sie die Build Action-Eigenschaft auf
Embedded Resource
.Fügen Sie den folgenden Code in die Klasse ein, in der Sie diese Bibliothek aufrufen.
Rufen Sie diese Methode wie folgt vom statischen Konstruktor auf
UnpackNativeLibrary("win32");
und entpacken Sie die Bibliothek auf die Festplatte, bevor Sie sie benötigen. Natürlich müssen Sie sicherstellen, dass Sie über Schreibberechtigungen für diesen Teil der Festplatte verfügen.quelle
Dies ist eine alte Frage, aber ich habe jetzt das gleiche Problem und habe einen Turnaround gefunden, der etwas schwierig, aber sehr einfach und effektiv ist: Erstellen Sie im Nuget-Standardinhaltsordner die folgende Struktur mit einem Unterordner für jede Konfiguration:
Wenn Sie die Nuspec-Datei packen, erhalten Sie für jede native Bibliothek in den Ordnern Debug und Release die folgende Meldung:
Wir brauchen keine solche "Lösung", weil dies nur unser Ziel ist: Native Bibliotheken werden nicht als NET Assemblies-Referenzen hinzugefügt.
Die Vorteile sind:
Die Nachteile sind:
quelle
Ich kann Ihr genaues Problem nicht lösen, aber ich kann Ihnen einen Vorschlag machen.
Ihre Hauptanforderung lautet: "Und lassen Sie die Referenz nicht automatisch registrieren" .....
Sie müssen sich also mit "Lösungselementen" vertraut machen.
Siehe Referenz hier:
Hinzufügen von Elementen auf Lösungsebene zu einem NuGet-Paket
Sie müssen ein Powershell-Voodoo schreiben, um die Kopie Ihrer nativen DLL in ihre Heimat zu bringen (erneut, weil Sie nicht möchten, dass das Voodoo mit automatischer Referenzreferenz ausgelöst wird).
Hier ist eine ps1-Datei, die ich geschrieben habe ..... um Dateien in einem Referenzordner eines Drittanbieters abzulegen.
Es gibt genug für Sie, um herauszufinden, wie Sie Ihre native DLL in ein "Zuhause" kopieren können ... ohne von vorne anfangen zu müssen.
Wieder ist es kein direkter Treffer, aber es ist besser als nichts.
quelle
Setzen Sie es ist der Inhaltsordner
Der Befehl
nuget pack [projfile].csproj
erledigt dies automatisch für Sie, wenn Sie die Dateien als Inhalt markieren.Bearbeiten Sie dann die Projektdatei wie hier beschrieben und fügen Sie das Element ItemGroup & NativeLibs & None hinzu
arbeitete für mich
quelle