Skip to content

Specifying the right dependencies

Hari Menon edited this page Apr 11, 2014 · 10 revisions

Squirrel has a couple of tricks to easily transform a NuGet package and turn it into a self-contained installer. The big one is scanning for dependencies and merging them into your created package.

Why bother with this?

  • nested dependencies are flattened up front
  • the installer becomes self-contained - no need to have internet access to install
  • dependencies are frozen at build time - future releases will not be applied until you're ready

However, there are some other things you need to be aware of when creating packages.

Firstly, a quick overview on what gets generated by Visual Studio when you turn a project into a NuGet package.

The important pieces are:

  • the library or executable for your project which is compiled by Visual Studio
  • the packages.config file in your project
  • the files element in the nuspec file at the root of the repository

So what other things are important which are probably being overlooked by this process?

  • project references
  • package.config files from referenced projects
  • referenced external assemblies

And how do we get these into our release package?

Project References

When you reference a project in your application, the assemblies from that project are brought across at build time, but the package created will not contain them. Consider them to be just like any other assembly which your application needs.

But given your application is probably already using NuGet packages to track external dependencies, why not also use NuGet to track local dependencies too?

Your project needs two things:

  • Inside your .csproj file, add a <BuildPackage>true</BuildPackage> element to tell NuGet that it should create packages after each build.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <!-- a whole bunch of other settings --> 

        <!-- Property that enables building a package from a project -->
        <BuildPackage Condition="$(BuildPackage) == ''">true</BuildPackage>
    </PropertyGroup>
    <!-- more important stuff down here -->
</Project>
  • a .nuspec file matching the project's name
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
  <metadata>
    <id>SomeOtherProject</id>
    <title>A library which is used in my main project</title>
    <version>$version$-beta</version>
    <authors>Brendan Forster</authors>
    <description>A description of SomeOtherProject goes here</description>
  </metadata>
</package>

NOTE: it would be really cool if you could just do Enable-NuGetPackage on a project without having to install Squirrel into it (or hack csproj files like this)...

Then, in your main project, you specify the dependencies inside the .nuspec file:

<?xml version="1.0"?>
<package>
  <metadata>
    <!-- all my other metadata here -->
    <dependencies>
      <dependency id="SomeOtherProject" version="[$version$]" />
    </dependencies>
  </metadata>
</package>

package.config files from referenced projects

If your solution has multiple projects, they each probably have their own packages.config specifying what NuGet has added to the project.

By specifying that your project should create a NuGet package during build, you get the additional benefit of having everything inside the packages.config merged into your <dependencies> when the NuGet package is created.

External Libraries

So if "everything is a reference" then how do we include them in a NuGet package?

The .nuspec file supports providing a files element, like this:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
  <metadata>
    <!-- your application metadata here -->
  </metadata>

  <files>
    <file src="..\ext\Ionic.Zip.dll" target="lib\net40\\" />
  </files>
</package>

Where the path is relative to your .nuspec file. So if you have libraries which aren't a part of the NuGet package, include them here for maximum happiness.

But what about assemblies which are generated at build time (and could live in a \bin\Debug\ folder or \bin\Release\ depending on the active project configuration?

There's a mention in the NuGet documentation about how, when you're building a package from MSBuild, you can get access to the configuration which is currently running:

<files>
  <file src="..\SomeOtherProject\bin\$configuration$\SomeOtherProject.dll" target="lib\net40\\" />
</files>
Clone this wiki locally