将 x86 和 x64 库添加到 NuGet 包

Adding x86 and x64 libraries to NuGet package

我制作了一个依赖于 CefSharp 的库,它需要为特定平台构建库。所以没有 AnyCPU 支持。

现在我想将其打包到 NuGet 中。据我所知,您必须将这些文件放入构建文件夹中,并有一个 .targets 文件来选择要引用的正确 dll。所以我最终得到了一个看起来像这样的 NuGet 包:

lib
    monodroid
        MyLib.dll
    xamarin.ios10
        MyLib.dll
    net45
        MyLib.dll (x86)
build
    net45
        x86
            MyLib.dll (x86)
        x64
            MyLib.dll (x64)
        MyLib.targets

我将以下内容放入 .targets 文件中:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="PlatformCheck" BeforeTargets="InjectReference"
    Condition="(('$(Platform)' != 'x86') AND  ('$(Platform)' != 'x64'))">
    <Error  Text="$(MSBuildThisFileName) does not work correctly on '$(Platform)' platform. You need to specify platform (x86 or x64)." />
  </Target>
  
  <Target Name="InjectReference" BeforeTargets="ResolveAssemblyReferences">
    <ItemGroup Condition="'$(Platform)' == 'x86' or '$(Platform)' == 'x64'">
      <Reference Include="MyLib">
        <HintPath>$(MSBuildThisFileDirectory)$(Platform)\MyLib.dll</HintPath>
      </Reference>
    </ItemGroup>
  </Target>
</Project>

到目前为止一切顺利。现在问题来了。将此 NuGet 添加到新的 WPF 项目时,我看到对库的引用出现在 .csproj 文件中,如:

<Reference Include="MyLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d64412599724c860, processorArchitecture=x86">
  <HintPath>..\packages\MyLib.0.0.1\lib\net45\MyLib.dll</HintPath>
  <Private>True</Private>
</Reference>

尽管我没有看到任何关于 .targets 文件的内容。这仍然是使用 NuGet 3 的方法吗?我做错什么了吗?目前,由于引用了 x86 lib.运行 x64,这在运行时失败。

在摆弄这个太久之后,我想通了。

显然,build.prop 和 build.target 文件的名称必须与 NuGet 包的名称完全相同,否则将不会添加到 csproj 文件中。

编辑:

我创建了一个 small GitHub repository 展示如何将其用于您自己的项目。

它演示了一个包含 3 个项目的解决方案 - 一个用于 iOS,一个用于 Android,以及一个同时针对 x86 和 x64 的 Net45。

请注意,在 .props 文件中,路径指向解压后的 NuGet 的文件夹结构。所以这些路径映射到您在 nuspec 文件中放置的内容。

因此,就像在回购协议中一样,您定义了一个 nuspec,例如:

<?xml version="1.0"?>
<package>
  <metadata>
    <id>My.Awesome.Library</id>
    <version>1.0.0</version>
    <title>My Awesome Library</title>
    <description>Herpa Derpa</description>
  </metadata>
  <files>
    <file src="My.Awesome.Library.Droid\bin\Release\My.Awesome.Library.*"
      target="lib\monodroid70" />

    <file src="My.Awesome.Library.iOS\bin\Release\My.Awesome.Library.*"
      target="lib\xamarin.ios10" />

    <file src="My.Awesome.Library.Net45\bin\x64\Release\My.Awesome.Library.*"
      target="build\x64" />

    <file src="My.Awesome.Library.Net45\bin\x86\Release\My.Awesome.Library.*"
      target="build\x86" />
    <file src="My.Awesome.Library.Net45\bin\x86\Release\My.Awesome.Library.*"
      target="lib\net45" />
    
    <file src="My.Awesome.Library.props" target="build\net45" />
  </files>
</package>

我将 x86 文件放入 build\x86,将 x64 文件放入 build\x64。在这种情况下,对于这些文件,文件夹 build 的名称基本上可以是任何名称。这里重要的是 props 文件,下面指向各个平台的这些文件夹。

我不确定将 x86 库放入 lib\net45 是否重要。你可以试验一下。无论如何,道具文件应该为您选择正确的。

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Reference Include="My.Awesome.Library" Condition="'$(Platform)' == 'x86'">
      <HintPath>$(MSBuildThisFileDirectory)..\x86\My.Awesome.Library.dll</HintPath>
    </Reference>
    <Reference Include="My.Awesome.Library" Condition="'$(Platform)' == 'x64'">
      <HintPath>$(MSBuildThisFileDirectory)..\x64\My.Awesome.Library.dll</HintPath>
    </Reference>
  </ItemGroup>
</Project>

在这种情况下,$(MSBuildThisFileDirectory) 将是 build\net45\ 文件夹,确保您的路径正确指向 dll。 build\net45 文件夹在这里很重要。这就是 NuGet 自动导入目标和道具文件的方式。

另请注意,My.Awesome.Library 这个名字在各个方面都非常一致。此处重要的是您的 props 文件的名称与 NuGet 包 ID 相匹配。否则,NuGet 似乎不会导入它。

上面的解决方案有几点我不同意。

如果您通过将文件添加到 nuget 文件夹来使用默认文件结构,则 nuspec 文件不必包含任何 <Files> 信息。但是如果你想从你的解决方案文件夹中 运行 nuget 文件,那么它是必需的

更好的 nuspec 内容:

<?xml version="1.0"?>
<package>
  <metadata>
    <id>YourProjectName</id>
    <version>1.0.0</version>
    <authors>John Doe</authors>
    <title>Your Project Name</title>
    <description>Herpa Derpa</description>
  </metadata>
</package>

我也不同意他在 build 文件夹中有 .dll,这些应该放在你的 lib 文件夹中,build 文件夹中应该包含你的 .targets.props 个文件。 nuget here 的文档提到了这一点。

lib 文件夹也用于您的参考资料中的 .dll。其次,添加到您的 build 文件夹的 .dll 是一些 cases-similar 可能需要的补充 dll,以了解 SQlite 如何为它的 interop dll 做这件事。所以在这种情况下,最好将它们保存在 lib 文件夹中。

更好的文件夹结构:

- nuget
-- project.nuspec
-- build 
---- YourProjectName.props
---- YourProjectName.targets
-- lib 
--- <x64>
---- YourProjectName.dll
--- <x86>
---- YourProjectName.dll

.props 文件内容:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Reference Include="YourProjectName" Condition="'$(Platform)' == 'x86'">
          <HintPath>$(MSBuildThisFileDirectory)x86\YourProjectName.dll</HintPath>
        </Reference>
        <Reference Include="YourProjectName" Condition="'$(Platform)' == 'x64'">
          <HintPath>$(MSBuildThisFileDirectory)x64\YourProjectName.dll</HintPath>
        </Reference>
      </ItemGroup>
    </Project>

.目标文件内容:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="PlatformCheck" BeforeTargets="InjectReference"
    Condition="(('$(Platform)' != 'x86') AND  ('$(Platform)' != 'x64'))">
    <Error  Text="$(MSBuildThisFileName) does not work correctly on '$(Platform)' platform. You need to specify platform (x86 or x64)." />
  </Target>
  <Target Name="InjectReference" BeforeTargets="ResolveAssemblyReferences">
    <ItemGroup Condition="('$(Platform)' == 'x86' or '$(Platform)' == 'x64') and '$(TargetFrameworkVersion)'=='v4.6'">
      <Reference Include=" YourProjectName ">
        <HintPath>$(MSBuildThisFileDirectory)..\..\lib\net46$(Platform)\ YourProjectName.dll</HintPath>
      </Reference>
    </ItemGroup>
  </Target>
</Project>

您可以通过使用 Nuget 包管理器应用程序打开您的 nuspec 文件并检查您添加的所有文件是否已被拾取来检查上述是否有效。现在,当您将这些添加到项目时,它将根据为引用它的项目选择的体系结构加载 dll。还要注意在目标文件中,如果选择“Any CPU”,它将引发错误,并且通知用户他们必须在 x86 和 x64

之间选择

编辑:

有一点没有说清楚,就是 .target 和 .props 的命名需要与 nuget 包文件名相同(也意味着版本)。 如果没有这个,双重引用会出现 当 re-opening Visual Studio.

为了阐明整个解决方案,这就是它对我来说完美工作的方式

.nuspec 文件

 <?xml version="1.0"?>
<package>
  <metadata>
    <id>YourProjectName</id>
    <version>1.0.0</version>
    <authors>John Doe</authors>
    <title>Your Project Name</title>
    <description>Herpa Derpa</description>
  </metadata>
</package>

文件夹结构

-- project.nuspec
-- build 
---- YourProjectName.props
---- YourProjectName.targets
-- tools
--- <x64>
---- YourProjectName.dll
--- <x86>
---- YourProjectName.dll

.props 文件

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Reference Include="YourProjectName" Condition="'$(Platform)' == 'x86'">
          <HintPath>$(MSBuildThisFileDirectory)..\tools\x86\YourProjectName.dll</HintPath>
        </Reference>
        <Reference Include="YourProjectName" Condition="'$(Platform)' == 'x64'">
          <HintPath>$(MSBuildThisFileDirectory)..\tools\x64\YourProjectName.dll</HintPath>
        </Reference>
      </ItemGroup>
    </Project>

.目标文件

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="PlatformCheck" BeforeTargets="BuildOnlySettings"
    Condition="(('$(Platform)' != 'x86') AND  ('$(Platform)' != 'x64'))">
    <Error  Text="$(MSBuildThisFileName) does not work correctly on '$(Platform)' platform. You need to specify platform (x86 or x64)." />
  </Target>

</Project>

这是 100% 有效的解决方案。