40

Is There anyway to #define Constant on a Visual Studio Solution Basis?

One can define a constant on a csproject basis, and one can put #define constant in cs file, but I wonder whether one can define it on a vs sln basis?

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Graviton
  • 81,782
  • 146
  • 424
  • 602

6 Answers6

23

You can actually use a variation on Ritch's approach with common project settings. Essentially you have to make a single change to the end of each project file in your solution:

  <PropertyGroup Condition="'$(SolutionDir)' == '' or
                     '$(SolutionDir)' == '*undefined*'">
      <SolutionDir>..\..\</SolutionDir>
    </PropertyGroup>
    <Import Project="$(SolutionDir)CommonSettings.targets" />
  </Project>

Then you can define CommonSettings.targets to contain the solution wide settings.

  <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
           ToolsVersion="3.5">
      <PropertyGroup>
          <TacoBuild>true</TacoBuild>
      </PropertyGroup>
  </Project>

That's basically it unless you want to override or merge project settings already defined in each project. The link below discusses how to do this in some detail.

http://www.ademiller.com/blogs/tech/2007/12/common-project-settings-for-your-visual-studio-solution/

Ade Miller
  • 13,575
  • 1
  • 42
  • 75
  • That's a clever approach. I'll have to add that one to my toolbox. – Ritch Melton Mar 11 '11 at 05:44
  • 1
    Note that in my attempts (with Visual Studio 2012 Express) to set DefineConstants this way for multiple projects I was able to get it to build correctly, but Visual Studio itself wasn't aware of the defines and so syntax colouring was incorrect for #if / #endif code blocks. – yoyo Jul 20 '14 at 00:47
  • This way of doing the define doesn't seem to work for me, but Tim's solution below yours seems to work. Any ideas why? – gnychis Feb 07 '15 at 13:22
  • I'd love to see this as a VS extension with UI. Would be a good project if someone has spare time. – rollsch Jul 09 '18 at 23:29
15

I have another approach for doing this:

  1. Edit global config file. For example in my case it's .netcf2.0 so it's $(MSBuildBinPath)\microsoft.compactframework.csharp.targets.

    Add the following line:

    <Import Project="$(SolutionDir)CommonSettings.targets" Condition="exists('$(SolutionDir)CommonSettings.targets')" />
    

    This is to tell MSBuild import the CommonSettings.targets if it's existed in your solution folder.

  2. Create CommonSettings.targets under your solution folder.

    For example to define ABC symbol:

    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
        <PropertyGroup>
        <DefineConstants>$(DefineConstants);ABC</DefineConstants>
        </PropertyGroup>
    </Project>
    
Jason Sturges
  • 15,855
  • 14
  • 59
  • 80
  • 1
    Don't modify a "system" file. Instead modify the project file which depends on the flag the same way you done it as it is a nice way. Hence my +1. – Softlion Jun 24 '13 at 12:12
  • the `Condition="exists('...')"` is what makes this the right answer. make your common properties file with a name similar to the solution, so a different solution won't have it, and won't load it. – Dave Thieben Apr 28 '17 at 19:22
8

Indirectly there is. If you set an environment variable with a flag and run VS:

set TacoBuild=true
devenv.eve bigproject.sln

or launch MSBuild from the command line:

msbuild /p:TacoBuild=true

In your .csproj files you need to add a PropertyGroup:

<PropertyGroup Condition="'$(TacoBuild)'=='true'">
    <DefineConstants>$(DefineConstants);TacoBuild</DefineConstants>
</PropertyGroup>

In your code you need a preprocessor def:

#if TacoBuild 
    const int myConst = 42;
#endif

A VS only alternative is to define a preprocessor definition in the build settings for a new project configuration and use that configuration in your build.

A non MSBuild solution is to create a constants.cs file and write a custom settings tool that updates the cs file. I wish there were a better solution, but I haven't found one.

Ritch Melton
  • 11,498
  • 4
  • 41
  • 54
  • the problem is that you can only do it via command line, but I want to be able to launch an IDE, set the `constant`, and run F5 debug build for this. – Graviton Mar 11 '11 at 03:34
  • @Graviton - If you are going to use the IDE, why not just create a project with a single constants.cs file that all the projects in the solution? Anyway, I did address how to use the posted technique with the IDE. – Ritch Melton Mar 11 '11 at 03:44
7

Starting with MSBuild 15.0, you can use Directory.Build.props to define constants over multiple projects. https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2019

It is like a csproj but it defines values thaty will apply to all csproj in children folders.

Create a file at the top of your folder tree (to apply to all children csproj), named Directory.Build.props.

Add:

<Project>
 <PropertyGroup>
   <DefineConstants>MaConstante</DefineConstants>
 </PropertyGroup>
</Project>
laperouse
  • 151
  • 1
  • 4
  • If you want to override/manipulate the DefineConstants defined in the project files you have to use Directory.Build.targets, as Directory.Build.props is imported at the beginning of the project file and there, the DefineConstants of the project are not yet available. You cannot override DefineConstants in Directory.Build.targets for VB projects though, as $(FinalDefineConstants) which is later passed to the VB compiler, is already set before Directory.Build.targets is imported - see: https://developercommunity.visualstudio.com/t/vbprojuser-defineconstants-dont-affect/865956 – exaiwitmx Feb 24 '22 at 14:31
1

I have another option that doesn't involve editing any project files with custom XML.

But it does require custom code in each project that detects each possible solution.

If you put $(SolutionName) in the project preprocessor defines then you can use #ifdefs to check which solution the project is compiling in and provide different configurations for each solution respectively.

This might not fit everyone's situation but this worked for me and solved my issues where I had the same project being used by multiple solutions but requiring ever so slightly different configurations.

applecider
  • 189
  • 1
  • 10
0

This is possible for Unity projects. Creating a file called
mcs.rsp (targeting .Net 3.5 Equivalent) or
csc.rsp (targeting .Net 4.0 Equivalent )
in /Assets/ folder allows you to do that.

Example : /Assets/csc.rsp file includes:

-define:THIS_IS_MY_GLOBAL_PREPROCESSOR_CONSTANT
-define:ANOTHER_GLOBAL_PREPROCESSOR_CONSTANT

In the project, in any player or editor c# script:

#if THIS_IS_MY_GLOBAL_PREPROCESSOR_CONSTANT
        Debug.Log("THIS_IS_MY_GLOBAL_PREPROCESSOR_CONSTANT is defined"); // compiles 
#else
        Debug.Log("THIS_IS_MY_GLOBAL_PREPROCESSOR_CONSTANT is not defined");
#endif

Tested on Unity 2019.1.2

https://docs.unity3d.com/Manual/PlatformDependentCompilation.html