69

Is there a way to globally declare a #define?

Like I want to have a file that has for instance,

#define MONO

and I want all source-code files to know that this pre-processor directive is defined. How would I achieve that?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
bevacqua
  • 47,502
  • 56
  • 171
  • 285
  • 3
    Possible duplicate of [Is There anyway to #define Constant on a Solution Basis?](http://stackoverflow.com/questions/5268177/is-there-anyway-to-define-constant-on-a-solution-basis) – turbo Feb 05 '16 at 07:00
  • 1
    Here there is answer that meets the requirement: "#define Constant on a Solution Basis" https://stackoverflow.com/questions/5268177/is-there-anyway-to-define-constant-on-a-solution-basis – user3680149 May 27 '14 at 14:06

11 Answers11

40

Update: You cannot do a "solution-wide" define afaik, however the answer below is workable on a per-project basis.

You set them in your Compilation Properties or Build options:

http://msdn.microsoft.com/en-US/library/76zdzba1(v=VS.80).aspx (VS2008) http://msdn.microsoft.com/en-US/library/76zdzba1(v=VS.100).aspx (VS2010)

see the "To set a custom constant" heading.

Update

Microsoft Documentation on Build Options

You get to the build options by right-clicking the project and selecting properties from the menu.

Project Build Options

BJ Safdie
  • 3,399
  • 23
  • 23
24

I know solution for C# projects (I don't tested it for any other projects)

For example you have:

Project1\
Project2\
Solution1\Solution1.sln
Solution2\Solution2.sln

Create SolutionDefines.targets file in solution directory

Project1\
Project2\
Solution1\Solution1.sln
Solution1\SolutionDefines.targets
Solution2\Solution2.sln
Solution2\SolutionDefines.targets
Solution3\Solution2.sln
Solution3\|no target file|

in each project file add:

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

In Solution1\SolutionDefines.targets add:

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <DefineConstants>$(DefineConstants);TRACING_BUILD</DefineConstants>
    </PropertyGroup>
</Project>

In Solution2\SolutionDefines.targets add:

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <DefineConstants>$(DefineConstants);ANOTHER_DEFINE</DefineConstants>
    </PropertyGroup>
</Project>

In this case you have:

For Solution1 - all projects have TRACING_BUILD define added

For Solution2 - all projects have ANOTHER_DEFINE define added

For Solution3 - all projects - no defines added

In this approach you must store all solutions with solution wide defines in separate directories

Andrei Krasutski
  • 4,913
  • 1
  • 29
  • 35
Alexei Shcherbakov
  • 1,125
  • 13
  • 10
  • 7
    Got it to work with two more infos, thanks a lot! 1) In the `SolutionDefines.targets` file I had to declare `` without any attributes, so it worked also with new "Microsoft.NET.Sdk" projects. 2) The include must be placed _after_ all other `` of the project. – martinstoeckli Mar 17 '19 at 19:21
  • 4
    The best (and the only, i guess) way to keep the things DRY – T-moty Apr 02 '19 at 16:30
  • 2
    For some reason I need to rebuild the project/solution twice in order for changes in `SolutionDefines.targets` to have effect and VS intellisense does not always detect changes even after reloading the solution. – Eliahu Aaron Oct 19 '20 at 10:42
23

Years later, and similar to Alexei's answer but supported innately.

One can make a Directory.Build.props similar to a NuGet.Config file as per

https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2019

Ours looks like:

<Project>
    <PropertyGroup>
        <DefineConstants>RC_427</DefineConstants>
    </PropertyGroup>
</Project>

And it effectively includes this into all CSPROJ files in your SLN. For some reason that particular solution is insanely hard to find via google. Been around since MSBuild 15

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Malachi
  • 2,260
  • 3
  • 27
  • 40
  • 5
    Also note it seems if you change the constants in this new global solution file, you'll have to unload and re-load each vs project in order for VS intellisense to pick up the change (the ms build will pick up the change fine however). – Michael Adamission May 21 '20 at 04:32
  • 2
    This solution is great for projects using the new SDK-style project format but projects using the old non-SDK-style project format have issues using `Directory.Build.props`. See [.props File Properties Not Reloaded When Changed](https://developercommunity.visualstudio.com/content/problem/187797/props-file-properties-not-reloaded-when-changed.html) – Eliahu Aaron Oct 19 '20 at 10:54
  • 2
    Does not work for me with Azure SF project in C#. Unload/Reload/Rebuild the project does not help. – Alexander Farber Nov 09 '20 at 14:45
  • 2
    MSBuild can correctly support this feature, but even VS 2022 need be restarted after editing Directory.Build.props file. 2 years passed and this bug is not fixed :-( – Alexei Shcherbakov Mar 20 '22 at 10:29
  • Can someone explain exactly how to do this. The MSDN article suggests dropping the file "in the root where all your source lies". I've done exactly that with the example in the answer, restarted VS 2019...and the symbol is not detected in code. Is there something more than just dropping a file in a folder somewhere, like a project or solution setting that needs to change? – AlainD Jun 07 '23 at 17:24
5

I don't think there is a way to create a solution-wide #define. You can create one for each project/assembly, as the other answers have described, but you'll need to do this for each and every project in the solution if you need all source code files to know of that #define.

Justin
  • 680
  • 9
  • 19
4

To expand on the answers @Murtago and @Mark Cidade to make it solution wide:

Open the configuration manager for the solution and create a new configuration (copied from the closest match) then change conditional symbols for the projects that need different ones.

enter image description here

Kevin S. Miller
  • 913
  • 1
  • 9
  • 21
4

In case you have both C# and C++ projects in the solution and need to share preprocessor definitions among them. Create some SolutionDefines.targets file near your *.sln as follows

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <DefineConstants>$(DefineConstants);MY_DEFINITION</DefineConstants>
    </PropertyGroup>
  <ItemDefinitionGroup>
    <ClCompile>
      <PreprocessorDefinitions>MY_DEFINITION;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
  </ItemDefinitionGroup>
</Project>

Then add to C/C++/C# *.vcproj/*.vcxproj/*.csproj project files this line somewhere in the end

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

Ok, now you can enjoy #if MY_DEFINITION in C# and #ifdef MY_DEFINITION in C/C++. Visual Studio C# editor doesn't like this way and tells there is no MY_DEFINITION defined. But, C# compiler csc.exe gets the symbol properly.

3

There is one more workaround, correct me if i'm wrong:

For example, ProjectA references ProjectB, and ProjectsCommon contains base static variable. Both projects refernece ProjectsCommon.

Code in ProjectsCommon:

[assembly: InternalsVisibleTo("ProjectA")]

------------------------------------------

public class ConditionVariables
{
    public static bool IsABC { get; internal set; } = false;
}

Code in ProjectA:

#if ABC
    ProjectsCommon.ConditionVariables.IsABC = true;
#endif

Code in ProjectB:

if (ProjectsCommon.ConditionVariables.IsABC )
{
    // first scenario
}
else
{
    // second one
}

However, code in ProjectA should run first. This is probably good when ProjectA is a bootstarapper project.

Andrey K.
  • 665
  • 8
  • 29
2

in vs 2013 you can use /define:x or /d:x http://msdn.microsoft.com/en-us/library/0feaad6z.aspx

Bas Smit
  • 645
  • 1
  • 7
  • 19
  • 2
    this option has been there forever, not only VS2013, but it sets options for a single compilation, not defining a macro for the whole solution – phuclv Apr 02 '19 at 04:37
2

Create a new solution configuration in Configuration Manager and make sure that the box is checked to create new project configurations as well. And then in the Build properties of each project enter MONO into the Conditional compilation symbols box.

Mark Cidade
  • 98,437
  • 31
  • 224
  • 236
1

The proper place for a pre-processor directive is the VS build configuration. If you are using a command line to build your solution you can also pass it using /define option.

muratgu
  • 7,241
  • 3
  • 24
  • 26
1

I don't know of a solution wide definition, but I was able to quickly add a preprocessor definition to all projects by doing the following:

  1. hold ctrl and select each project
  2. right click on any selected project and choose Properties
  3. go to C/C++ --> Preprocessor
  4. click the little down arrow beside Preprocessor Definitions
  5. choose <Edit...>
  6. add my definition after <different options>
  7. OK out of the menus

I'm using Visual Studio Community 2019 with a C code base.

Samuel
  • 8,063
  • 8
  • 45
  • 41
  • 1
    Can a function-like macro be added? Something like `#define IS_DOUBLE(X, Y) ((Y * 2 == X) ? 1 : 0)`. How can something like this be added globally? – mireazma Mar 03 '21 at 15:42