【问题标题】:Adding x86 and x64 libraries to NuGet package将 x86 和 x64 库添加到 NuGet 包
【发布时间】:2016-05-12 19:00:59
【问题描述】:

我制作了一个依赖于 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 时会在运行时失败。

【问题讨论】:

  • 如果您不需要支持使用 project.json 的较新的 Windows 10 项目,我会尝试删除 lib\Net45 目录。 NuGet 应安装到 WPF 项目中,只需将 .targets 文件导入项目文件 (.csproj)。
  • 我不打算支持 UWP 或任何使用新 project.json 内容的新项目。明天再试一次。但是,在添加了 nuget 的 csproj 文件中没有看到引用的目标仍然很困惑。
  • 我尝试删除 lib\net45 文件夹,但它什么也没做,只是因为找不到 dll 而使它无法构建。
  • 在 Windows 和 Mac 上都可以正常工作。我使用您的 MSBuild 目标创建了一个简单的示例 NuGet package。我可以在 C# 项目中使用它并使用 x86 和 x64 构建它,并引用适当的 .dll。
  • 我在这里关注了问题和 cmets,我的 csproj 引用了目标文件并且构建工作正常,但是我添加的 DLL 没有出现在 VS (2015) 参考中.他们应该吗?谢谢

标签: nuget msbuild-target


【解决方案1】:

在玩了太久之后,我想通了。

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

编辑:

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

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

请注意,在 .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>

我将 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 似乎不会导入它。

【讨论】:

    【解决方案2】:

    我不同意上述解决方案的一些内容。

    如果您通过将文件添加到 nuget 文件夹来使用默认文件结构,则 nuspec 文件不必包含任何 &lt;Files&gt; 信息。但是,如果您想从解决方案文件夹中运行 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 包管理器 APP 打开您的 nuspec 文件并检查您添加的所有文件是否被拾取来检查上述是否有效。现在,当您将这些添加到项目时,它将根据为其引用的项目选择的架构加载 dll。还要注意在目标文件中,如果选择“任何 CPU”,它将引发错误,并通知用户他们必须在 x86 和 x64 之间进行选择

    编辑:

    有一点没有明确说明 .target 和 .props 的命名需要与 nuget 包文件名相同(也意味着版本)。 如果没有这个,双重引用会在重新打开 Visual Studio 时出现

    【讨论】:

    • 你需要props和target文件吗?两者有什么区别?
    • 技术上两者都不是必需的。它们提供可以运行的可选操作。检查:docs.microsoft.com/en-us/nuget/create-packages/… 在“在包中包含 MSBuild 道具和目标”部分
    • 我的文件夹结构和上面一样(除了我的架构文件夹在lib下的net452下)。因此,在我将 nuget 包添加到项目后,我将项目设置为 x86,然后将 x86 版本的 dll 复制到 x86 构建文件夹(它的根目录 - 不是子文件夹),这是正确的。但是当我将项目切换到 x64 时,dll 的 x86 版本被复制到 x64 构建文件夹中。我期待捆绑在 nuget 包中的 x64 版本被复制到 x64 构建文件夹中。
    • 您必须在更改构建配置后重新安装 nuget 包。只有当 dll 是“任何 CPU”时,您的预期行为才会起作用
    • 对于任何为此苦苦挣扎的人。 props 文件确保编辑器满意,而 targets 文件确保正确构建。只需确保两个文件中的相对路径都是 100% 正确的。我不需要将确切的版本编码到文件名 My.Awesome.Lib.targets 中就足够了。
    【解决方案3】:

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

    .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% 可行的解决方案。

    【讨论】:

      猜你喜欢
      • 2017-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-05
      相关资源
      最近更新 更多