Kzu's Today I Learned
GitHubX/TwitterBlog
  • Today I Learned
  • dotnet
    • How to emit descriptions for exported JSON schema using JsonSchemaExporter
    • NuGet
      • Suppress dependencies when packing
      • Hide contentFiles from your nuget packages
      • Packaging transitive analyzers with NuGet
      • How to add search to static nuget feed
      • Populate RepositoryBranch in CI for NuGet Pack
    • Ignore folder from dotnet-format
    • Accessing Tor .onion URLs via HttpClient with .NET6
    • Installing .NET 5.0 on Raspberry Pi 4
    • Quickly check C# compiler and language version
    • Disable diagnostic analyzers for entire folder/submodules
    • Persisting output files from source generators
    • Use C# 9 records in non-net5.0 projects
    • AsyncLocal never leaks and is safe for CallContext-like state
    • Using HashCode in .NETFramework
    • How to locate dotnet
  • testing
    • Conditional unit tests
    • Skip tagged scenarios in SpecFlow with Xunit
  • msbuild
    • How to get user home dir ~ cross-platform
    • Modifying the build for every solution in a repository
    • Detect CI builds for every CI system
    • Modify all command-line builds in entire repo
    • Write entire XML fragments in MSBuild with XmlPoke
    • How to select first item in an ItemGroup
    • How to include commit URL in nuget package description
    • How to include package reference files in your nuget
    • How to build project when content files change
  • azure
    • How to launch multiple Azure Functions apps on different ports
    • C# script function apps beyond Azure portal
    • Publishing function app from GitHub folder
    • Exploring Azure Data with Kusto and Dashboards
    • Shared secret authorization with Azure SignalR Service
    • Using Azure File Copy from DevOps yaml pipeline
    • Code-less redirection with serverless Azure Functions
  • DevOps/CI/CD
    • How to run Azure Storage unit tests in CI
    • How to skip steps or jobs in GitHub Actions for PRs from forks
    • Update version and publish npm from GH
    • Push to protected branch from GitHub actions
Powered by GitBook
On this page
  1. msbuild

Modifying the build for every solution in a repository

PreviousHow to get user home dir ~ cross-platformNextDetect CI builds for every CI system

Last updated 3 years ago

Just like you can have to customize your projects' build, you can also use Directory.Solution.props and Directory.Solution.targets to customize your solutions (command-line) builds. Just like the original (older?) mecanisms, , however.

In order to inspect how and where they are included in the build, it's useful to set use the of setting the envvar MSBUILDEMITSOLUTION=1 and run a build. You can inspect the .metaproj MSBuild project generated from the solution, where you will see the imported projects.

For a Directory.Solution.props with:

<Project>
  <PropertyGroup>
    <SolutionPropsProp>from-solution.props</SolutionPropsProp>
  </PropertyGroup>
</Project>

And a Directory.Solution.targets with:

<Project>
  <PropertyGroup>
    <SolutionTargetsProp>from-solution.targets</SolutionTargetsProp>
  </PropertyGroup>

  <Target Name="CustomSolutionBuild">
  </Target>
</Project>

You will see a .metaproj similar to:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" InitialTargets="ValidateSolutionConfiguration;ValidateToolsVersions;ValidateProjects" DefaultTargets="Build">
  <PropertyGroup>
    <RoslynTargetsPath>C:\Program Files\dotnet\sdk\5.0.100-rc.2.20479.15\Roslyn</RoslynTargetsPath>
    <_DirectorySolutionPropsFile>Directory.Solution.props</_DirectorySolutionPropsFile>
    <_DirectorySolutionPropsBasePath>C:\Code\kzu\moq</_DirectorySolutionPropsBasePath>
    <DirectorySolutionPropsPath>C:\Code\kzu\moq\Directory.Solution.props</DirectorySolutionPropsPath>
    <SolutionPropsProp>from-solution.props</SolutionPropsProp>
    <Configuration>Debug</Configuration>
    <Platform>Any CPU</Platform>
    ...
    <_DirectorySolutionTargetsFile>Directory.Solution.targets</_DirectorySolutionTargetsFile>
    <_DirectorySolutionTargetsBasePath>C:\Code\kzu\moq</_DirectorySolutionTargetsBasePath>
    <DirectorySolutionTargetsPath>C:\Code\kzu\moq\Directory.Solution.targets</DirectorySolutionTargetsPath>
    <SolutionTargetsProp>from-solution.targets</SolutionTargetsProp>
  </PropertyGroup>
  ...
  <Target Name="_IsProjectRestoreSupported" Returns="@(_ValidProjectsForRestore)" />
  <Target Name="CustomSolutionBuild" />
  <Target Name="Build" Outputs="@(CollectedBuildOutput)">
  ...
</Project>

Notice how the targets aren't imported but rather embedded in specific places (top of property group for .props-declared properties, bottom of property group for .targets-declared properties, and before Build target for targets). If you have properties, they are actually even evaluated before being embedded in the file, i.e.:

<SolutionNow>$([System.DateTime]::Now)</SolutionNow>

is embedded in the .metaproj as the actually evaluated value, such as:

    <SolutionNow>10/21/2020 4:36:30 AM</SolutionNow>
Directory.Build.props and Directory.Build.targets
Visual Studio will not load those customizations either
troubleshooting technique