【问题标题】:Where to place dlls for unmanaged libraries?在哪里放置非托管库的 dll?
【发布时间】:2012-04-29 05:13:11
【问题描述】:

我正在尝试为依赖 ghostscript 的库创建 Nuget 包,因此引用 gsdll32.dll - 一个非托管库。我不能只包含一个标准的 dll 引用。我在哪里把它放在 nuget 目录结构中?

【问题讨论】:

    标签: dll dependencies unmanaged nuget


    【解决方案1】:

    将build 文件夹添加到包中,例如,如果包的ID 为MyPackage,则将名为MyPackage.targets 的MSBuild 目标文件添加到此文件夹中。 .targets 文件与.nuspec 文件具有相同的名称,这一点很重要。在.nuspec 文件中,您必须有这样的部分:

    <files>
        <file src="lib\*.*" target="lib" />
        <file src="build\MyPackage.targets" target="build" />
    </files>
    

    这将在项目文件中添加一个指向 .targets 文件的 MSBuild 元素。

    此外,要仅注册托管 dll,请添加如下部分:

    <references>
        <reference file="MyManaged.dll" />
    </references>
    

    .targets 文件应如下所示:

    <?xml version="1.0" encoding="utf-8"?> 
    <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
      <Target Name="CopyMyPackageFiles" AfterTargets="AfterBuild"> 
        <ItemGroup> 
          <MyPackageFiles Include="$(MSBuildThisFileDirectory)..\lib\*.*"/> 
        </ItemGroup> 
        <Copy SourceFiles="@(MyPackageFiles)" DestinationFolder="$(OutputPath)" > 
        </Copy> 
      </Target> 
    </Project>
    

    现在,所有文件 - 包括非托管文件 - 将在构建后复制到项目输出文件夹(例如 \bin\debug)。

    【讨论】:

    • 我很欣赏这个 Lars - 你能把它编辑成你的答案吗?指向博客的链接往往会停止工作。
    • 你成就了我的一天(期间)。
    • @Jérôme 有点晚了,但我认为你的问题仍然值得回答。 .target 文件有一个轻微的(而且绝对不明显)陷阱:名称必须与包名称相同。当它像这样时,目标会在安装包时自动添加到 .csproj 文件中。您可以检查您的 是否在接近末尾的某个位置引用您的目标。只有这样它才会起作用。不涉及其他魔法。
    • 您可以避免硬编码精确路径,如下所示:&lt;MyPackageFiles Include="$(MSBuildThisFileDirectory)..\myfile.dll
    • @ElliotWoods 在 .nuspec 文件中 (docs.microsoft.com/en-us/nuget/reference/nuspec)。 .targets 文件需要根据您放置本机文件的位置进行自定义。在示例中,它们被放置在名为 lib 的文件夹中
    【解决方案2】:

    上述参考可以工作,但它实际上会修改您的构建后事件以推送文件,如果您遇到我们遇到的情况,这实际上可能无法解决您的问题。

    我们遇到的问题是一个依赖 DLL 无法注册,但必须与另一个需要由 nuget 注册的 DLL 并存 所以它需要存在于 lib 目录中但不能注册.

    nuspec 引用现在允许您指定 lib 目录中的哪些 DLL 现在在 Visual Studio 项目中显式注册,您只需添加到 metadata 显示一个明确的 references 列表(如果这不存在,nuget 的默认行为是尝试在 lib 下注册所有内容)。

    这是我的意思的示例 nuspec 文件:

    <?xml version="1.0" encoding="utf-8"?>
    <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
        <metadata>
            <id>SomePackageID</id>
            <version>1.0.1</version>
            <title>Some Package Title</title>
            <authors>Some Authors</authors>
            <requireLicenseAcceptance>false</requireLicenseAcceptance>
            <description>Blah blah blah.</description>
            <references>
                <reference file="ceTe.DynamicPDF.Rasterizer.20.x86.dll" />          
            </references>
        </metadata>
        <files>
            <file src="\\SomeNetworkLocation\ceTe.DynamicPDF.Rasterizer.20.x86.dll" target="lib\ceTe.DynamicPDF.Rasterizer.20.x86.dll" />
            <file src="\\SomeNetworkLocation\DPDFRast.x86.dll" target="lib\DPDFRast.x86.dll" />
        </files>
    </package>
    

    如您所见,ceTe.DynamicPDF.Rasterizer.20.x86.dll 需要注册,但 DPDFRast.x86.dll 只需要存在于该目录中以支持其他 DLL 并且不会注册但通过一些动态引用魔法最终将被复制到无论如何,目标 bin 目录,因为 Visual Studio 看到第一个 DLL 依赖于第二个。

    这里是原始的nuspec reference。

    【讨论】:

    • "...通过一些动态引用魔法最终将被复制到目标 bin 目录中..."。这似乎不适用于 unmanged dll,这就是问题所在。
    • 好吧,在我的情况下它不起作用,但 stackoverflow.com/a/33041626/798781 起作用了。
    【解决方案3】:

    Nuget 论坛回复:http://nuget.codeplex.com/discussions/352689

    普拉纳夫公里: SQLCE 包有一个类似的问题,我们通过 PS 处理 脚本。签出脚本 https://bitbucket.org/davidebbo/nugetpackages/src/1cba18b864f7/SqlServerCompact/Tools.

    【讨论】:

      【解决方案4】:

      我主要使用 Lars Michael 的方法来完成这项工作,但我需要补充的一件事来自 James Eby 的回答。 Visual Studio 试图在我的lib 目录中注册所有 dll,因此我在 nuspec 文件的元数据中添加了一个 references 元素,以告诉它只注册托管 dll:

      <references>
          <reference file="FANNCSharp.dll" />          
      </references>
      

      也在

      <MyPackageFiles Include="$(MSBuildProjectDirectory)\..\Packages\MyPackage\lib\*.*"/>
      

      我首先尝试了我的包的 ID FANNCSharp-x64,但它需要完整的包名:FANNCSharp-x64.0.1.4。

      【讨论】:

      • 我修改了原始答案以解决您提到的问题。谢谢。
      【解决方案5】:

      我遇到的一个问题是包路径相对于项目文件并不总是在同一个位置。以下对我有用:

      1. 在 NuGet 包中,将非托管 DLL 放在 lib\native 文件夹中。

      2. 将以下脚本添加到工具文件夹:

      安装.ps1

      #This script creates or updates a PackagesPath property in the project file
      param($installPath, $toolsPath, $package, $project)
      
      $project.Save()
      
      #Load the csproj file into an xml object
      [xml] $xml = Get-Content -path $project.FullName
      
      #grab the namespace from the project element 
      $nsmgr = New-Object System.Xml.XmlNamespaceManager -ArgumentList $xml.NameTable
      $nsmgr.AddNamespace('a',$xml.Project.GetAttribute("xmlns"))
      
      #find or create the property
      $property = $xml.Project.SelectSingleNode("//a:PropertyGroup//a:PackagesPath", $nsmgr)
      if (!$property)
      {
          $property = $xml.CreateElement("PackagesPath", $xml.Project.GetAttribute("xmlns"))
          $propertyGroup = $xml.CreateElement("PropertyGroup", $xml.Project.GetAttribute("xmlns"))
          $propertyGroup.AppendChild($property)
          $xml.Project.InsertBefore($propertyGroup, $xml.Project.ItemGroup[0])
      }
      
      #find the relative path to the packages folder
      $absolutePackagesPath = (get-item $installPath).parent.FullName
      push-location (split-path $project.FullName)
      $relativePackagesPath = Resolve-Path -Relative $absolutePackagesPath
      pop-location
      
      #set the property value
      $property.InnerText = $relativePackagesPath
      
      #save the changes.
      $xml.Save($project.FullName)
      
      1. 将目标文件添加到构建文件夹。 (将“MyPackage”更改为您的包裹名称)。为目标使用唯一名称,如“CopyMyPackage”,避免与试图定义“AfterBuild”目标的其他包发生冲突。此目标文件使用上述脚本定义的 $(PackagesPath) 属性。

      MyPackage.targets

      <?xml version="1.0" encoding="utf-8"?> 
      <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
        <Target Name="CopyMyPackage" AfterTargets="AfterBuild"> 
          <ItemGroup> 
            <MyPackageSourceFiles Include="$(PackagesPath)\MyPackage.*\lib\native\*.*"/> 
          </ItemGroup> 
          <Copy SourceFiles="@(MyPackageSourceFiles)" DestinationFolder="$(OutputPath)" > 
          </Copy> 
        </Target> 
      </Project>
      
      1. 最后,将“MyPackageReadMe.txt”添加到内容文件夹。这将使软件包能够安装。

      另请参阅:http://alski.net/post/2013/05/23/Using-NuGet-25-to-deliver-unmanaged-dlls.aspx

      【讨论】:

        【解决方案6】:

        对于 .NET Core,如果您知道本机代码的目标运行时平台,这非常简单。构建时,您可能会注意到 bin 树下的 .NET Core 构建文件夹中有一个名为“runtimes”的文件夹。它看起来像这样:

        这些文件夹旨在保存任何特定于平台的内容,包括非托管/本机 DLL。

        在您的 NuGet 包中,在“文件”部分下添加以下内容:

        <file src="[source path for file in package]" target="runtimes\[platform]\native\[file name]" />
        

        在执行应用程序时,运行时环境会在对应的平台目录中寻找非托管的dll。

        如果您想针对多个平台,只需为每个平台添加另一个文件条目。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-03-06
          • 1970-01-01
          • 2010-09-25
          • 2011-04-29
          • 1970-01-01
          • 1970-01-01
          • 2010-10-14
          • 2017-10-16
          相关资源
          最近更新 更多