I have a system with a 1 TB SATA-connected SSD as the system disk and a 256 GB M.2 SSD as an auxiliary data disk/scratch drive. I would like to configure Visual Studio 2022 to create all project build directories (but not the projects themselves) inside a folder on this scratch drive (F:\build
). From what I can tell, CMake-based projects can achieve this by creating a global CMakeSettings.json
template; however, I haven't found anything for MSBuild-based projects. Is it possible to configure the MSBuild defaults to do this?
A folder tree of what I'm trying to do would look a little like this:
F:\
|- foo
|- bar
|- build
|- Project1
|- Project2
CodePudding user response:
MSBuild is not a build script generator like CMake. When you create a project file with Visual Studio or the dotnet tool, the project itself is an MSBuild script. The project file should be source controlled. It is not a 'scratch' file.
Generally, MSBuild projects use an 'intermediate' directory and an 'output' directory. By default, the intermediate directory is obj\
and the output directory is bin\
. These defaults can be changed by changing the BaseIntermediateOutputPath
and BaseOutputPath
properties. (See List of common properties and parameters.)
You can set or change properties globally by using a Directory.Build.props file. (See Customize your build.) The Directory.Build.props file is imported very early which is important because there are numerous properties defined based on the BaseIntermediateOutputPath
and BaseOutputPath
properties.
You might create a Directory.Build.props file like the following:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetPathOfFileAbove('$(MSBuildThisFile)', '$(MSBuildThisFileDirectory)../'))" />
<PropertyGroup>
<Acme-Drive Condition="'$(Acme-Drive)' == ''">F:</Acme-Drive>
<Acme-BuildDir Condition="'$(Acme-BuildDir)' == ''">$(Acme-Drive)\build\</Acme-BuildDir>
<BaseOutputPath Condition="'$(BaseOutputPath)' == ''">$(Acme-BuildDir)$(MSBuildProjectName)\bin\</BaseOutputPath>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)' == ''">$(Acme-BuildDir)$(MSBuildProjectName)\obj\</BaseIntermediateOutputPath>
</PropertyGroup>
</Project>
Some notes on this MSBuild code:
- MSBuild will search up the directory structure and will load the first Directory.Build.props file found. The
Import
will search for and if present will load the next file. It's a good practice to always add theImport
when creating a Directory.Build.props file (or a Directory.Build.targets file). The chain of imports will continue to work if Directory.Build.* files are added or removed in the directory tree. Acme-Drive
andAcme-BuildDir
are custom properties. 'Acme-' is used as a prefix. The prefix can be anything that is appropriate for your organization or product. The prefix both provides a lower chance of a property name collision and indicates this is a custom property.- The
Condition="'$(Acme-Drive)' == ''"
tests if the property is unset. The valueF:
is only set if theAcme-Drive
property doesn't already have a value. Properties can be redefined and overridden from other files and from the command line. For example, passing/p:"Acme-Drive=z:"
on the MSBuild command line would switch the drive for that one run. - The value of the
$(MSBuildProjectName)
property is the name of the current project.
If
- Your local working directory for the source code is C:\repos\MyProduct.
- The code above is saved as C:\repos\MyProduct\Directory.Build.props.
- You have project files:
- C:\repos\MyProduct\project1\Project1.csproj
- C:\repos\MyProduct\project1\Project2.csproj
then
- Both projects will use the same Directory.Build.props file.
- For Project1,
$(BaseOutputPath)
will be F:\build\project1\bin. - For Project2,
$(BaseOutputPath)
will be F:\build\project2\bin.