19

I want to start using Microsoft.Net.Compilers to simplify work with our build server. However, I could only get it to work at a per-project level, by adding the package to all projects.
This is problematic because the package would have to be added to each new created project. This could lead to a case where the code compiles on the developer's machine (which has the latest compiler), but would fail on the build server. We have many projects (over 100), so this is relatively common.

Is there a way of using Microsoft.Net.Compilers at solution level?

If there is no supported way, is there a command line tool I would not have to install on the build server? Alternatively, is this not an intended usage of these tools?

Community
  • 1
  • 1
Kobi
  • 135,331
  • 41
  • 252
  • 292
  • The chat has [some remarks on this question](http://chat.stackoverflow.com/transcript/message/36678159#36678159) (and enlightening information on bacteria reproduction). – Kobi Apr 18 '17 at 13:38

3 Answers3

17

If in VS 2017 (update 1, build numbers >= 15.1.*) you can use the MSBuild integrated PackageReference mechanism instead of packages.config which was previously only available for .net core and .net standard project types. See the PackageReference documentation as well as the NuGet blog post announcing the support, especially the section "What about other project types that are not .NET Core?".

The idea is to switch from installing a package and adding it to packages.config for restore to just specifying an MSBuild items in the csproj file. This can be set up for new projects in VS: Switch from packages.config to ProjectReference (animation is from the NuGet blog post linked above)

A new feature of MSBuild 15 is that it supports automatically including files in the directory hierarchy that have special names. Those are Directory.Build.props and Directory.Build.targets which will get included before (props) and after (targets) your project file's content (there is a bug with the .targets version for multi targeting projects for which a fix is about to be released).

If you create a Directory.Build.props file with the following content at the solution level, all projects in the directory hierarchy below it will inherit it's content and you can force a NuGet dependency onto each project:

<Project>
  <ItemGroup>
    <PackageReference Include="Microsoft.Net.Compilers" Version="2.1.0"/>
  </ItemGroup>
</Project>
Martin Ullrich
  • 94,744
  • 25
  • 252
  • 217
  • Thanks! This sounds good. Now, I'm going to be difficult: does that mean I have to install MSBuild 15 on my build server anyway? Wasn't the "point" of `Microsoft.Net.Compilers` that I shouldn't have to install it? – Kobi Apr 30 '17 at 05:16
  • Well at some point you'll have to update servers, even if it's just installing new targeting packs for new .NET Versions (or use unofficial NuGet pkgs for that). MSBuild isn't a compiler though, it's the build system that uses the compiler. – Martin Ullrich Apr 30 '17 at 06:19
  • If you want to never install anything on build serves, I suggest looking into building with Docker containers (letting each repository specify the software image it needs) or using the .net CLI (".NET Core Sdk") which can build "new-world" csproj files and contains a self-contained distribution of MSBuild 15 - A lot of appveyor definitions on GitHub have a step to download a local copy of it. – Martin Ullrich Apr 30 '17 at 06:27
  • -1 because I don't understand how this answers the question. The question was "how do I enable .Compilers solution-wide without requiring msbuild15" but this answer is "how to force projects to require msbuild15" – EKW Mar 20 '18 at 21:30
1

For existing projects in the solution:

Right-click your solution > Manage NuGet Packages for Solution...

... Or:

Tools > Library Package Manager > Manage NuGet Packages for Solution...

Then add it to all the projects by browsing for your package, then checking the top checkbox, and clicking install.

Source : https://stackoverflow.com/a/8653312/7007466


For the new projects:

Create a template mimicking the original one for each type of project you need (Console, Library etc...) and adding the package to it.

  • Create a project.

    Note: Use only valid identifier characters when naming a project that will be the source for a template. A template exported from a project named with invalid characters can cause compilation errors in future projects based on the template.

  • Edit the project until it is ready to be exported as a template.
  • As appropriate, edit the code files to indicate where parameter replacement should take place.
  • On the File menu, click Export Template. The Export Template wizard opens.
  • Click Project Template.
  • If you have more than one project in your current solution, select the projects you want to export to a template.
  • Click Next.
  • Select an icon and a preview image for your template. These will appear in the New Project dialog box.
  • Enter a template name and description.
  • Click Finish. Your project is exported into a .zip file and placed in the specified output location, and, if selected, imported into Visual Studio.

If you have the Visual Studio SDK installed, you can wrap the finished template in a .vsix file for deployment by using the VSIX Project template.

Source : https://msdn.microsoft.com/en-us/library/xkh1wxd8.aspx

If someone has an easier way than creating templates, I'll gladly take it.

Community
  • 1
  • 1
satibel
  • 290
  • 3
  • 9
  • This can work, but is rather complicated, and introduces a significant overhead - much more than just adding the package to all projects and maintaining it. It still requires creating a special "procedure" for creating projects. – Kobi Apr 19 '17 at 11:26
0

On solution level, create CommonProjectBuildProperties.targets:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
    <ItemGroup>
        <PackageReference Include="Microsoft.Net.Compilers" Version="4.2.0">
            <PrivateAssets>all</PrivateAssets>
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
        </PackageReference>
    </ItemGroup>
</Project>

on each project, add:

    <Import Project="../CommonProjectBuildProperties.targets"/>

this way you can manged any changes in one place

Yochai Lehman
  • 323
  • 3
  • 8