3

I would like to change the directory of the bin and obj folders created from build by Visual Studio 2022.

For example, a project in this path :

C:\Users\MyUserName\source\repos\SolutionName\ProjectName\ProjectName.csproj

Would build :

C:\Users\MyUserName\source\repos\SolutionName\ProjectName\bin C:\Users\MyUserName\source\repos\SolutionName\ProjectName\obj

I want to change the path for bin and obj folders to :

C:\Users\MyUserName\MyProjectsBuilds\SolutionName\ProjectName\bin C:\Users\MyUserName\MyProjectsBuilds\SolutionName\ProjectName\obj

I already found answers on how to do this in the project's properties but I want to make this for all all solutions and projects.

How can I make Visual Studio 2022 do this by default instead of having to change all projects properties individually?

3
  • As @Behtash said, you can use Directory.Build.props to set the output directory.Create a file in the solution folder, Directory.Build.props, to set the appropriate MSBuild properties in one place, to apply to all the projects in the solution. Commented Jun 27 at 2:31
  • @Behtash is incorrect about placing the Directory.Build.props file in the install directory under C:\Program Files. It doesn't even make sense because the C:\Program Files directory has restricted access. That answer should be downvoted. Commented Jun 27 at 12:31
  • The Directory.Build.props and Directory.Build.targets files are searched for by walking up through the parent directories. If the files are already in use in the code tree, your local file may not be imported. Commented Jun 27 at 12:35

2 Answers 2

2

If you are thinking of something like PowerShell Profiles, there is no equivalent feature in MSBuild. But there are features that can be used to meet your need.

.user File

As a peer of the project file, e.g. foo.csproj, create a .user file that matches the project name, e.g. foo.csproj.user. This file is expressly meant for local customization and should be excluded from source control. (See ".user file".)

It is, however, per-project. You would need to create and maintain a separate .user file for each project.

Directory.Build.props and Directory.Build.targets

For both Directory.Build.props and Directory.Build.targets, MSBuild will always walk up the chain of parent directories and import the file if it is found.

You could create a Directory.Build.props and/or Directory.Build.targets in C:\Users\MyUserName. These files will be found and used by all proejcts in sub-directories of C:\Users\MyUserName -- unless another file is found first.

It is a good idea to implement "multi-level merging". Essentially customize every Directory.Build.props and Directory.Build.targets file to continue walking up the directories and chain import. This is nice because sets of projects can share customizations.

The documentation gives the following example for a Directory.Build.props:

<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />

This can be generalized to work for both Directory.Build.props and Directory.Build.targets by using the $(MSBuildThisFile) property instead of hard-coding the file name.

The Import will throw an error if the Project attribute is empty, i.e. there will be an error when no file is found above.

Often a file is created in the top of the code tree that doesn't look above. That stops the import chain and doesn't throw an error but prevents using a 'global' file that is outside of the code tree.

However, the Import can have a condition so boilerplate for the Directory.Build.props and Directory.Build.targets files can be:

<Project>
  <PropertyGroup>
    <ParentFile>$([MSBuild]::GetPathOfFileAbove('$(MSBuildThisFile)', '$(MSBuildThisFileDirectory)../'))</ParentFile>
  </PropertyGroup>
  <Import Project="$(ParentFile)" Condition="$(ParentFile) != '' and Exists($(ParentFile))" />

  ...

To keep things consistent and sane I recommend to always import the "parent file" at the top of the "child file".

Given a project directory path of A\B\C with a Directory.Build.targets file in each directory:

  1. A\B\C\Directory.Build.targets will be found first and will import A\B\Directory.Build.targets.
  2. A\B\Directory.Build.targets will import A\Directory.Build.targets.
  3. A\Directory.Build.targets will find no file to import.

The order of the content of the files in the project after import will be:

  1. A\Directory.Build.targets
  2. A\B\Directory.Build.targets
  3. A\B\C\Directory.Build.targets

A file lower in the code tree (and closer to the project file) can override customizations from higher in the code tree. This is a good general pattern even if it seems counter to your needs.

But you should also follow the "MSBuild best practices" and test properties before setting them.

If the following is used in A\B\C\Directory.Build.targets and BaseOutputPath has already been defined in A\Directory.Build.targets, the value will not be overridden.

  <PropertyGroup>
    <BaseOutputPath Condition="'$(BaseOutputPath)' == ''">$(USERPROFILE)</BaseOutputPath>
  </PropertyGroup>

I know this probably feels a bit DIY but it is very flexible, extensible, and well supported by MSBuild.

1
  • 1
    Creating a "Directory.Build.props" in C:\Users\MyUserName worked just fine. Using "multi-level merging" seems unnecessary for what I want but it`s nice to know about it. Thank you! Commented Jun 28 at 0:15
0

1)Locate the MSBuild Directory: C:\Program Files\Microsoft Visual Studio\2022\<YourEdition>\MSBuild\Current\Bin\MSBuild.exe

2)Create or Edit the Directory.Build.props file in the MSBuild Directory: C:\Program Files\Microsoft Visual Studio\2022\<YourEdition>\MSBuild In this directory, create a file named Directory.Build.props if it doesn’t already exist, or edit it if it does.

3)Configure the Directory.Build.props File: Open the Directory.Build.props file with a text editor (you might need to open your editor as an administrator to save changes in this directory).

<Project>
  <PropertyGroup>
    <!-- Define a base output path variable -->
    <BaseOutputPath>C:\Users\MyUserName\MyProjectsBuilds\$(SolutionName)\$(MSBuildProjectName)\</BaseOutputPath>
    
    <!-- Set the output paths for bin and obj folders -->
    <BaseIntermediateOutputPath>$(BaseOutputPath)obj\</BaseIntermediateOutputPath>
    <OutputPath>$(BaseOutputPath)bin\</OutputPath>
  </PropertyGroup>
</Project>

4)Restart Visual Studio

ref: https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory?view=vs-2022

2
  • A Directory.Build.props file under the Visual Studio install directory will be used? Is that documented somewhere? (It's not in the documentation that your reference.) Commented Jun 26 at 19:47
  • 1
    I tried it but it didn't work. Commented Jun 27 at 13:11

Not the answer you're looking for? Browse other questions tagged or ask your own question.