Inherited Properties and Property Sheets


In my last post, I talked at length about the various types of MSBuild elements – items, properties, imports, etc. One of the things that I said I would get around to in a later post was to explain what I meant by “inherited properties”, where they came from and how you can create your own. Well, I’m slow but I’m finally getting around to it!

What you are going to learn is how to take advantage of one of the most powerful – but lesser known – features of VC++ Projects: Property Sheets. And if that isn’t enough for you – you’ll also learn the foundations needed to understand my next post…What happened to VC Directories?!?!!?

The above image is straight out of a new Win32 Console application project property window. Notice how some of the property values (Debug Information Format and Warning Level) are bolded while others are not? What this means is that the values that are bold in value are defined in the .vcxproj (or associated .user file), while the other values are inherited from another file. How does that work? As I said in my previous post, an MSBuild file can import other files – just like a #include for a header file. In this case, if you open your .vcxproj file, you’ll see an import for Microsoft.Cpp.default.props and Microsoft.Cpp.props. Pretty much all of your inherited property values in a new VC++ project comes from these files – or their imports.

What this allows Microsoft to do is define the defaults in a set of files that all projects import – and therefore not have to replicate them in everyone’s project file. The trick is, you can do the exact same thing – it’s called Property Sheets.

A property sheet is simply an MSBuild file that you import into your project that defines some property values. But because it is a separate file, it can be shared among multiple projects, allowing you to centralize some settings and perform a central edit operation. Examples of where this is useful are

  • Setting build conventions for teams, such as warning levels, use of exceptions and optimization settings.
  • Setting system information, such as the include and library paths for an SDK you might consume.
  • Feature settings, such as the various properties to set when using Unicode or Ansi strings.

The system is open, so you can use it for pretty much whatever takes your fancy.

Of course, to make it really useful, we need to allow you to work with them inside the IDE. To see property sheets in action, bring up the Property Manager window. This may already be in your windows next to the solution explorer – or you can bring it up from the View->(Other Windows)->Property Manager (whether it is in Other Windows or not depends on what profile you selected when you first started Visual Studio).

What you’ll notice is that it is somewhat like the solution explorer – it lists out all of the VC++ projects in the solution. However, rather than source files, it shows property sheet “sources”, grouped by their configurations. In this case, you can see that there are four existing property sheets by default for a new Win32 console application project. For each of them, you can right-click and bring up the property window just as you did for the project earlier. Now, however, it shows the settings that are known about by the property sheet you have selected (Microsoft.Cpp.Win32.user is shown below).

Some things to notice about this window

  1. The Configuration and Platform selections are grayed out.
    This is because you select them automatically when you click on the property sheet in the Property Manager window. (Yes, I know this is inconsistent and a bit strange, but it’s the way it’s been since property sheets arrived – so until we do a larger UI overhaul, consider it a lovely quirk).
  2. Some properties are still not bolded.
    Editing a property sheet is like editing a project – it can have it’s own property sheets that are providing defaults.
  3. There are a lot more rules (left column of C/C++, Linker, etc).
    This is because in a project view, we only show rules that apply to the project as it is…if you have no .rc files, then we don’t show the Resources rule. Property Sheets, however, can be applied to multiple projects and therefore we don’t filter out any known rule.

Now, you may notice that if you selected one of the property sheets that has an icon that looks like a computer with a sheet in front of it, that everything was read-only. That is because these are System Property Sheets. Simply, a system property sheet is one that is provided by the build system automatically (part of the Microsoft.cpp.props for example) and therefore is not meant to be edited. That doesn’t mean you can’t override their values in a property sheet or project file – only that you can’t edit the system property sheet itself. It is displayed only so that you can see what those sheets contribute.

Okay, so let’s create our own property sheet to get the feel for it. First thing to do is to select a context in the property manager window – if you pick a project, the property sheet is applied to all config/platform settings. If you pick a specific config/platform, then obviously it would only apply for that one. Anyway – go ahead and right-click and select “Add New Project Property Sheet’” and follow the wizard. The only real thing to note here is that you have to say where the file should be located. Remember, the value of a property sheet is that it can be shared between multiple projects so a common directory near the top of your solution source is probably a good idea.

You should now have 5 property sheets – 3 system property sheets and two user property sheets. You might be wondering whether or not the order of them in the list has any importance (if not, go ahead and do it now, we’ll wait….Hey, did you know it rains a lot in Seattle? How about those Seahawks, eh?).

Ah, your back! Great – I can now cease your wondering by me saying that yes, indeed, the order matters. What the order is telling you is that the property sheet at the bottom is applied first, then the next and the next, so on up the list. This means that your newest property sheet will be applied last – just before the project itself is evaluated. If you want to change that ordering, just right-click on the property sheet and select either “Move Earlier in Evaluation” or “Move Later in Evaluation”.

An important note: Notice how “Move Earlier in Evaluation” is grayed out above? That is because not only are system property sheets read-only, they also are read-only when it comes to ordering.

Now here is another trick – try right clicking on a property sheet and selecting “Add New Project Property Sheet” (as also visible above). The result is a child property sheet. Again, you have control over the evaluation ordering, just remember that move earlier/later on children obviously only affect the group of children sheets. Similar to the main list, children are evaluated from the bottom up – and all the children of a parent are evaluated just before the parent itself is evaluated.

Just two more things to say about property sheets at this point.

  1. Notice how the right-click context menu above has a “Save” option? Yes – I’m afraid that property sheets are not owned by a project and therefore saving a project does not save property sheets – so they have their own save command. All I can say is (a) it was that way in VS 2008 and that (b) addressing some of the UI hiccups is high on my own priority list for the next release…back me up on this one!
  2. Microsoft.Cpp.Win32.user is a special – but optional – property sheet. This guy lives in your LocalAppData directory and is automatically part of any new or upgraded project. Therefore anything set in this property sheet, by default, applies to ALL projects. We’ll get more into him in a following post on “What the heck happened to the Tools->Options VC Directories?”

To complete the circle, set a property value in your new property sheet and then go back to the project properties window and you should see your value showing up – and not-bolded – proving the inheritance.

So there you have it, Property Sheets in a nut-shell. I’ll be honest with you – these aren’t the easiest things to understand when you first come across them – make sure to play around with them a bit to get a feel and post up any questions you have. Once you get the hang of them, you’ll wonder how you ever did anything without them.

Up next (from me anyway) – The prodigal VC Directories returns.


Comments (5)

  1. Jalf says:

    "What this allows Microsoft to do is define the defaults in a set of files that all projects import – and therefore not have to replicate them in everyone’s project file."

    And yet you do just that (as seen in the bolded line in the example above. Why is so much replicated in everyone’s project file by default?

    The thing I really don’t understand about property sheets is why you give us the feature, and then try to make it as troublesome as possible to use?

    Please, in VS2010, can we have default projects that rely 100% on property sheets, without overriding anything in the .vcxproj? That would make it so much simpler for us to define our own property sheets. It is such a pain to have to manually clear out all your overrides in order for our property sheets to take effect.

    Pretty please? You’ve got the feature, let’s use it.

    And the second problem is that for some reason, half the features under the General pane are not exposed to property sheets. I can’t use a property sheet to toggle between dll/lib/exe, or switch Unicode on and off (or link-time code generation). Why why why why?

    Those are my two complaints about property sheets. Both seem like simple oversights that could be fixed in about 20 minutes. But we’ve had to suffer them for years now. Any chance of a fix?

  2. Brian Tyler says:

    Jalf,

    Good points – the first issue is something we need to clean up, the second is by design. Let me go into some more detail…

    Wizards and their behavior

    ————————–

    Yes, you are correct that the current wizards set too many values that are the defaults – we need to stop doing that. There is a discussion going on right now about that, but I can’t say what, if anything, is going to be done – the code change is small, but the QA is larger, and there is still a lot of work to do before release. However – you have been heard!

    General Properties

    ——————

    This one is harder to explain in a short space, but we’ll have a blog post coming that explains the layout of .vcxproj files.

    However, if you open it up, you’ll see a group of properties that are set before Microsoft.cpp.props and then those that are set after. The ones that are set before that import are mostly the "General" properties and they control the system property sheets (and other cogs of the VC++ build system) that are brought in. For example, if you select Unicode or MSBC, or EXE or Makefile, it all controls what happens inside Microsoft.Cpp.props.

    Therefore, these properties cannot be controlled via property sheets. It’s a trade-off we had to make to avoid the complexity of pre-import and a pre-pre-import and a pre-pre-pre-import. I won’t say it’s a perfect solution, but it is one that we had to make some trade-offs on.

    I doubt we are going to be able to change them this late in the game (the change has major ramifications through-out the system), but please file Connect issues with the ones you feel are serious problems. That will get them into discussions (yes, we look at Connect very closely for the Beta).

  3. bahbar says:

    I have only tested 2008 so far, so sorry if this is not relevant for 2010. However, it looks like none of the following issues have been addressed :

    1) Finding exactly what a property sheet defines from the IDE is a pain. One has to open all the Rules one by one to try to find what it actually affects. AFAIK, there is no way to open the corresponding xml file either (again, from the IDE)

    2) related, finding which file stores the sheet is non trivial . only the filename shows in the context menu, not the the path. Double clicking opens the properties dialog, not the underlying file. You know where it is, please let me look 😀

    3) When I see a unexpected inherited property, finding which property sheet defines it is painful (especially when there are many sheets).

    There… I already feel better

  4. David Ward says:

    We have always had trouble using inherited property sheets effectively. I understand that relative paths are wrt to the project. This isn’t very useful as we would like to define a hierarchy of propertysheets and share them across projects.

    The only (unsatisfactory) solution we came up with is to use $(SolutionDir)/PropertySheets/…. which forces to put all our solutions at the same level in source.

    Is there are more effective way?

    Regards,

    David.

  5. Pavan Adharapurapu says:

    This is a response to the comment on  Monday, July 27, 2009 3:38 AM by David Ward

    MSBuild considers all relative paths appearing in Import statements to be relative to the importing file. In other words, if property sheet "A" imports property sheet "B" such that the import statement for "B" in "A" contains a relative path, then MSBuild considers it as relative to "A"’s location. However, we have a bug in Beta1 (the version you are using) wherein the project system computes the path relative to the *project* :( Hence when you add property sheets through the UI, you will see incorrect relative paths printed in the Import statements whenever the relative path w.r.t to project is different from relative path w.r.t. the importing property sheet. We have fixed this bug and in Beta2 you should be able to create your hierarchy of property sheets and use it in multiple projects.

    For now, as a work around, you can manually correct the import paths using notepad. With such a correction, the build will work fine although the UI may be confused.