MSBuild单个NuGet包中的多个dll

时间:2017-07-07 17:49:17

标签: msbuild visual-studio-2017

我有一个包含两个项目的Visual Studio 2017解决方案:

Foo.csproj
Foo.Core.csproj

这两个项目都针对多个框架:net452;netstandard1.2

Foo.csproj包含对Foo.Core.csproj的项目引用:

<ItemGroup>
    <ProjectReference Include="..\Foo.Core\Foo.Core.csproj" />
</ItemGroup>

当我为Foo.csproj生成NuGet包时,我希望nupkg文件包含这两个程序集。

目前发生的是创建的NuGet包具有Foo.dll,然后是Foo.Core上的NuGet依赖(不存在)。

如何使用包含两个程序集的msbuild生成单个NuGet包?

作为参考,这是我目前正在使用的命令(我的工作方式不正常):

msbuild /p:restore,pack Foo.csproj

4 个答案:

答案 0 :(得分:18)

NuGet目前尚未直接支持此功能。您可以按this GitHub issue进行更新。

但是,有几种方法可以创建这样的NuGet包。

  1. 使用“Nugetizer 3000”
  2. 这是一个新开发的工具,可以通过安装NuGet.Build.Packaging nuget包来从项目和工作中构建NuGet包。你可以在它的GitHub wiki页面上找到一些关于它的文档,但由于它是一个非常新的项目,它周围没有太多的文档或社区知识(!)(但开发它的团队非常有帮助,你可以提交GitHub如果你遇到问题就会出问题。

    1. 在项目中添加自定义目标(2.0.0 tooling / VS 2017 15.3+):在csproj中创建一个包含引用项目输出DLL的项目
    2. 这种方法非常糟糕,因为它依赖于包目标使用的内部MSBuild项。它的工作原理是首先将<ProjectReference>标记为不能从创建的nuget包中引用,如下所示:

      <ProjectReference Include="..\libA\libA.csproj" PrivateAssets="All"/>
      

      然后,您可以将其添加到项目中,以将生成的libA.dll包含在nuget包中:

      <PropertyGroup>
        <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);IncludeP2PAssets</TargetsForTfmSpecificBuildOutput>
      </PropertyGroup>
      <Target Name="IncludeP2PAssets">
        <ItemGroup>
          <BuildOutputInPackage Include="$(OutputPath)\testprivatelib.dll" />
        </ItemGroup>
      </Target>
      

      请注意,这需要您将引用项目的所有<PackageReference>项添加到生成包的项目中,因为它们会从生成的包中丢失,因为您已经有效地禁用了传递引用行为。

      1. 创建自定义.nuspec文件
      2. 在撰写本文时,这可能是最“支持”的方式,但也是最复杂的方式。 NuGet允许您通过在项目中设置.nuspec属性以及允许您通过替换的<NuspecFile>属性来禁用自动生成生成的<NuspecProperties>文件和自动文件收集用于解析.nuspec文件的标记。

        这可以通过修改项目文件来实现:

        <Project Sdk="Microsoft.NET.Sdk">
          <PropertyGroup>
            <TargetFramework>netstandard1.4</TargetFramework>
            <NuspecFile>$(MSBuildThisFileDirectory)$(MSBuildProjectName).nuspec</NuspecFile>
          </PropertyGroup>
          <ItemGroup>
            <ProjectReference Include="..\LibB\LibB.csproj" />
          </ItemGroup>
        
          <Target Name="SetNuspecProperties" BeforeTargets="GenerateNuspec">
            <PropertyGroup>
              <NuspecProperties>$(NuspecProperties);id=$(AssemblyName)</NuspecProperties>
              <NuspecProperties>$(NuspecProperties);config=$(Configuration)</NuspecProperties>
              <NuspecProperties>$(NuspecProperties);version=$(PackageVersion)</NuspecProperties>
              <NuspecProperties>$(NuspecProperties);description=$(Description)</NuspecProperties>
              <NuspecProperties>$(NuspecProperties);authors=$(Authors)</NuspecProperties>
            </PropertyGroup>
          </Target>
        </Project>
        

        这将自动查找与项目名称相同的.nuspec文件(somelib.csproj =&gt; somelib.nuspec),并将一些属性传递给它。属性在目标中创建,以便能够访问完全解析和默认的属性,如PackageVersion

        .nuspec文件可能如下所示:

        <?xml version="1.0" encoding="utf-8"?>
        <package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
          <metadata>
            <id>$id$</id>
            <version>$version$</version>
            <authors>$authors$</authors>
            <requireLicenseAcceptance>false</requireLicenseAcceptance>
            <description>$description$</description>
            <dependencies>
              <group targetFramework=".NETStandard1.4">
                <dependency id="NETStandard.Library" version="1.6.1" exclude="Build,Analyzers" />
              </group>
            </dependencies>
          </metadata>
          <files>
            <file src="bin\$config$\netstandard1.4\*.dll" target="lib\netstandard1.4\" />
          </files>
        </package>
        

        请注意,您必须将所有引用的NuGet包添加为<dependency>文件中的.nuspec元素,因为这些不再自动从项目文件中的<PackageReference>项生成。有关详细信息,请参阅NuSpec Reference

        我最近为此目的创建了example project on GitHub demonstrating the use of a custom .nuspec file

答案 1 :(得分:1)

由于遇到了同样的问题,没有建议的解决方法起作用(https://github.com/NuGet/Home/issues/3891),我无法更改csproj以使用.netcore附带的新SDK。

幸运的是,nuget pack命令带有-IncludeReferencedProjects选项(参考:https://docs.microsoft.com/en-us/nuget/tools/cli-ref-pack),该选项正是这样做的: “表示所构建的软件包应包括作为依赖项或作为软件包一部分的被引用项目。如果被引用项目具有与该项目同名的相应.nuspec文件,则该被引用项目将被添加为依赖性。否则,引用的项目将作为软件包的一部分添加。

无论* .nuspec文件如何(此处不需要),都将-IncludeReferencedProjects添加到pack命令,并且所引用的项目dll将与nuget dll一起包含。

nuget.exe pack yourProject.csproj -IncludeReferencedProjects

答案 2 :(得分:0)

Martin Ullrich提到的第二个选项是唯一可以与.NET Standard即用的选项,它允许“在生成时生成NuGet软件包”作为生成的组成部分。

但是,就像他提到的那样,它对dll的名称具有“硬编码”依赖关系,而您希望它的确切名称(在输出文件夹中)会在将来对您造成影响。我找到了一个更好的替代方法,它在.NET Standard中对我有用,而无需进行任何其他修改on this post

出于完整性考虑,我在这里引用。 首先,您要编辑csproj并为要包含的引用定义PrivateAssets标签:

<ItemGroup>
  <ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj">
    <PrivateAssets>all</PrivateAssets>
  </ProjectReference>
</ItemGroup>

然后将其添加到csproj:

<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>

<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
    <ItemGroup>
        <BuildOutputInPackage Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'all'))" />
    </ItemGroup>
</Target>

该帖子还显示了必要时如何将PDB包括在NuGet软件包选项中(在此省略)。

答案 3 :(得分:0)

我最近发现您不能为要在msbuild命令行中替换的Nuspec属性设置默认值,例如如果在“ <Version>2.0.0</Version>”的.csproj文件中设置了元数据值,则运行:

msbuild myproject.csproj -t:pack -p:Configuration=Release -p:NuspecProperties=Configuration=Release;PackageVersion=1.2.3

您的.nupgk文件仍将具有2.0.0版本。令人烦恼的是,MS文档尚不清楚,并且没有错误显示。