8

I can't seem to find any useful documentation from Microsoft about how one would use the Delimiter and InheritsFromParent attributes in the UserMacro element when defining user Macros in .vsprops property sheet files for Visual Studio.

Here's sample usage:

<UserMacro Name="INCLUDEPATH" Value="$(VCROOT)\Inc"
    InheritsFromParent="TRUE" Delimiter=";"/>

From the above example, I'm guessing that "inherit" really means "a) if definition is non-empty then append delimiter, and b) append new definition" where as the non-inherit behavior would be to simply replace any current macro definition. Does anyone know for sure? Even better, does anyone have any suggested source of alternative documentation for Visual Studio .vsprops files and macros?

NOTE: this is not the same as the InheritedPropertySheets attribute of the VisualStudioPropertySheet element, for example:

<VisualStudioPropertySheet ... InheritedPropertySheets=".\my.vsprops">

In this case "inherit" basically means "include".

jwfearn
  • 28,781
  • 28
  • 95
  • 122

3 Answers3

9

[Answering my own question]

InheritsFromParent means prepend. To verify this, I did an experiment that reveals how User Macros work in Visual Studio 2008. Here's the setup:

  • Project p.vcproj includes the property sheet file d.vsprops ('d' for derived) using the InheritedPropertySheets tag.
  • d.vsprops includes the property sheet file b.vsprops ('b' for base.)
  • p.vcproj also defines a Pre-Build Event which dumps the environment.
  • Both .vsprops files contain User Macro definitions.

b.vsprops

...
<UserMacro Name="NOENV" Value="B"/>
<UserMacro Name="OVERRIDE" Value="B" PerformEnvironmentSet="true"/>
<UserMacro Name="PREPEND" Value="B" PerformEnvironmentSet="true"/>
...

d.vsprops

...
<VisualStudioPropertySheet ... InheritedPropertySheets=".\b.vsprops">
<UserMacro Name="ENV" Value="$(NOENV)" PerformEnvironmentSet="true"/>
<UserMacro Name="OVERRIDE" Value="D" PerformEnvironmentSet="true"/>
<UserMacro Name="PREPEND" Value="D" InheritsFromParent="true"
    Delimiter="+" PerformEnvironmentSet="true"/>
...

p.vcproj

...
<Configuration ... InheritedPropertySheets=".\d.vsprops">
<Tool Name="VCPreBuildEventTool" CommandLine="set | sort"/>
...

build output

...
ENV=B
OVERRIDE=D
PREPEND=D+B
...

From these results we can conclude the following:

  1. PerformEnvironmentSet="true" is necessary for User Macros to be defined in the environment used for build events. Proof: NOENV not shown in build output.
  2. User Macros are always inherited from included property sheets regardless of PerformEnvironmentSet or InheritsFromParent. Proof: in b.vsprops, NOENV is not set in the environment and in d.vsprops it is used without need of InheritsFromParent.
  3. Simple redefinition of a User Macro overrides any previous definition. Proof: OVERRIDE is set to D although it was earlier defined as B.
  4. Redefinition of a User Macro with InheritsFromParent="true" prepends the new definition to any previous definition, separated by a specified Delimiter. Proof: PREPEND is set to D+B (not D or B+D.)

Here are some additional resources I found for explanation of Visual Studio .vsprops files and related topics, it's from a few years back but it is still helpful:

understanding the VC project system part I: files and tools

understanding the VC project system part II: configurations and the project property pages dialog

understanding the VC project system part III: macros, environment variables and sharing

understanding the VC project system part IV: properties and property inheritance

understanding the VC project system part V: building, tools and dependencies

understanding the VC project system part VI: custom build steps and build events

understanding the VC project system part VII: "makefile" projects and (re-)using environments

jwfearn
  • 28,781
  • 28
  • 95
  • 122
0

There's documentation on the UI version of this here. A lot of the XML files seem somewhat undocumented, often just giving a schema file. Your guess as to how they function is pretty much right.

Eclipse
  • 44,851
  • 20
  • 112
  • 171
0

It is not the whole story.

  • Delimiters are not inherited. Only the list of items they delimit are inherited: The same user macros can have different delimiters in different property sheets but only the last encountered delimiter is used. (I write "last encountered" because at project level, we cannot specify a delimiter and what gets used there is the last property sheet that specified inheritance for that macro)
  • Delimiters works only if made of a single character. A delimiter longer than one character may have its first and/or last character stripped in some cases, in a mistaken attempt to "join" the list of values.
  • $(Inherit) appears to work inside user macros. Like for aggregate
    properties, it works as a placeholder for
    the parent's values, and it can appear multiple times. When no $(Inherit) is found, it is implied at the beginning if the inheritance flag is set.
  • $(NoInherit) also appears to work in user's macros(makes VC behaves as if the checkbox was unticked).
  • User macros (and some built-ins) appears to work when used for constructing a property sheet's path (VC's own project converter uses that feature). The value taken by user's macros in this situation is not always intuitive, though, especially if it gets redefined in other included property sheets.
  • In general, what gets "inherited" or concatenated are formulae and not values (ie. you cannot use a user macro to take a snapshot the local value of (say) $(IntDir) in a property sheet and hope to "bubble up" that value through inheritance, because what gets inherited is actually the formula "$(IntDir)", whose value will eventually be resolved at the project/config/file level).
  • A property sheet already loaded is ignored (seem to avoid that the same property sheet has its user macros aggregated twice)
  • Both "/" and "\" appear to work in property sheet paths (and in most places where VS expects a path).
  • A property sheet path starting with "/" (after macros have been resolved) is assumed to be in "./", where '.' is the location of the calling sheet/project). Same if the path does not start with "./", "../" or "drive:/" (dunno about UNC).