Multi-framework NuGet build with symbols for internal dependency management

喜欢而已 提交于 2019-12-02 18:06:47
David Boike

Xavier's answer led me in the proper direction, and also informed my Google searching. I was not fully aware of the file declarations, and when searching along those lines, I found Joshua Flanagan's post Tips for building NuGet packages, which is excellent. Xavier and Joshua together taught me a few things:

  1. You don't have to assemble a conventions-conforming file tree in order to build a package. It's much better to use the file element to select files and target them to a destination directory within the assembled NuGet package.
  2. NuGet's -Symbols flag doesn't just work for packaging on a .csproj file. When you do use it on a .csproj file, then sure, that's how it figures out how to package up all your source files. But you can also use -Symbols on a .nuspec file that includes the source via file elements. The normal NuGet package will not include the src directory, but the Symbols package will.

So now, let me describe my build process as it occurs on my CI server:

  1. Build the solution using the "3.5 Release" solution configuration.
  2. Build the solution using the "4.0 Release" solution configuration.
  3. Use ILMerge.exe to internalize some assemblies. I have these output to (for example) bin\Release-3.5\merged so I don't have to monkey with renaming the target assembly to temp.dll before I use it in the merge.
  4. Build the package against the .nuspec in Powershell.

Here is the package command:

nuget pack src\MyProject\MyProject.nuspec -OutputDirectory .\output -Build -Symbols -Version $Version

Note that $Version is passed in from the build server so I can use its build number as the last part of the version.

Here is the .nuspec file:

<?xml version="1.0"?>
<package>
    <metadata>
        <id>MyProject</id>
        <version>0.0.0</version>
        <title>MyProject</title>
        <authors>David Boike</authors>
        <owners>David Boike</owners>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <description>MyProject</description>
        <releaseNotes></releaseNotes>
        <copyright>Copyright 2012</copyright>
        <tags>my tags</tags>
    </metadata>
    <files>
        <file src="bin\Release-4.0\merged\MyProject.dll" target="lib\net40" />
        <file src="bin\Release-4.0\merged\MyProject.pdb" target="lib\net40" />
        <file src="bin\Release-4.0\MyProject.xml" target="lib\net40" />
        <file src="bin\Release-3.5\merged\MyProject.dll" target="lib\net35" />
        <file src="bin\Release-3.5\merged\MyProject.pdb" target="lib\net35" />
        <file src="bin\Release-3.5\MyProject.xml" target="lib\net35" />
        <file src="**\*.cs" target="src" />
    </files>
</package>

Note that I have removed a lot of the more informative elements from my nuspec because it just doesn't matter for an internal project like this.

The result is a package for my private NuGet server that contains DLL, PDB, and XML documentation for the assembly for both .NET 3.5 and 4.0, and then a separate symbols package for my private SymbolServer that includes all of the above plus the source. This is very easy to view with the NuGet Package Explorer which I highly recommend you download.

Finally, I tested everything and with the Visual Studio setup suggested at symbolsource.org (except with my own private symbol server) I was able to debug the code and easily step into the source.

Thanks again to Xavier for leading me down the right path!

You know there is a third option? When targeting a csproj file, it will also look for a nuspec file with the same name as your project file (myProject.csproj --> myProject.nuspec). This means that you can add extra metadata to the resulting package by defining it into the nuspec file, whilst still targeting your csproj file. In essence, you'll end up with a package containing the merged metadata from your csproj file and nuspec file.

In your specific scenario, if you want to package multiple platform builds of the same project, you'll indeed have to build those projects first before packaging using the nuspec.

I'd advise you to create two projects, one targeting NET35, the other one targeting NET40, and adding the files as links into one of the projects. As such you can build both projects, and package all output in one NuGet package using a nuspec file.

Now as for symbols, I think you could have a second nuspec file (myProject.symbols.nuspec for instance), where you could add all contents of the project (sources etc) using wildcard characters, similar to what's shown below.

<file src="myProject35\**\*.cs" target="src" />
<file src="myProject40\bin\Release\*.dll" target="lib\net40" />
<file src="myProject40\bin\Release\*.pdb" target="lib\net40" />
<file src="myProject35\bin\Release\*.dll" target="lib\net35" />
<file src="myProject35\bin\Release\*.pdb" target="lib\net35" />

Hope this helps or at least provides you some info to find a way out :)

Cheers, Xavier

Check out the new features in NuGet 2.5 related to framework version dependant references: http://docs.nuget.org/docs/release-notes/nuget-2.5

It might be an option for you to use build configurations with conditional references elements in the csproj files (conditinal on the TargetFrameworkVersion), then run your build in all configurations, and produce output for net35 and net40 with optional targeting of references in your nupkg.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!