将x86和x64库添加到NuGet包中

时间:2016-02-03 14:15:21

标签: nuget msbuild-target

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

现在我想将它打包成NuGet。据我所知,你必须将这些文件放入build文件夹并有一个.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库的引用,在运行x64时运行时会失败。

3 个答案:

答案 0 :(得分:18)

经过长时间摆弄这个问题后,我想出来了。

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

修改

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

它演示了一个包含3个项目的解决方案,一个用于iOS,一个用于Android,另一个用于x86和x64。

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

因此在repo中,您可以定义一个类似于

的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>

我将build\x86和x64文件中的x86文件放入build\x64。对于这些文件,文件夹构建的名称在本例中基本上可以是任何内容。这里重要的是道具文件,下面指向各个平台的这些文件夹。

我不确定将x86 lib放入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不会导入它。

答案 1 :(得分:2)

我从上述解决方案中有一些不同意的事情。 如果通过将文件添加到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是在某些情况下可能需要的补充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>

.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') and '$(TargetFrameworkVersion)'=='v4.6'">
      <Reference Include=" YourProjectName ">
        <HintPath>$(MSBuildThisFileDirectory)..\..\lib\net46\$(Platform)\ YourProjectName.dll</HintPath>
      </Reference>
    </ItemGroup>
  </Target>
</Project>

您可以通过使用Nuget Package Manager APP打开您的nuspec文件并检查您添加的所有文件来检查上述情况是否有效。现在,当您将这些添加到项目时,它将根据为其引用的项目选择的架构加载dll。另请注意目标文件中,如果&#34;任何CPU&#34;已选中,并通知用户他们必须在x86和x64之间进行选择

修改

一点不清楚的是.target和.props的命名需要与nuget包文件名相同(也就是版本)。 如果没有这个,重新打开visual studio时会出现双引用

答案 2 :(得分:-1)

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

.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>

.targets文件

<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%有效的解决方案。