Ugly syntax
Hello,
When I call targets using the MSBuild task I pass parameters using the "properties" attribute. When the number of properties is big the syntax is really ugly and unreadable. Is there another syntax?
I also want to send a list of files as a parameter (to a task, or a target) and I prefer defining the file set as a sub xml element of the task, to make it readable (like in ANT) is it possible?
Thanks.
[415 byte] By [
OriN] at [2007-12-17]
Right now that's the only syntax. Well you could pass them using an item list like this
<ItemGroup>
<PropertiesToPass Include="a=b"/>
<PropertiesToPass Include="c=d"/>
</ItemGroup>
...
<Target ...>
<MSBuild .... Properties="@(PropertiesToPass)"/>
</Target>
Could you give us some suggestions of how you'd rather see properties pass? I can record them as an Orcas suggestion.
For your second question, there's no way to pass subelements of a task to the task code. It's something we already have been thinking would be nice, though. For example, to have a prettier way to set properties inside targets. Instead of using the clumsy CreateItem/CreateProperty tasks, we could create a PropertyGroup task and an ItemGroup task to make it look just like those things do outside of targets:
<Target ..>
<PropertyGroup>
<foo>bar</foo>
</PropertyGroup>
<SomeOtherTask .../>
</Target>
This would need us to enable passing in subelements to tasks, and also some way to get around needing the <Output> tag... What do you think?
Dan
Hmm, I wonder if you could allow someone to name a PropertyGroup and then treat that property group as a property list (ITaskProperty[] ?). It might look like this:
| |
<PropertyGroup Name="SubProjBuildProps"> ... </PropertyGroup><Target ...> <MSBuild ... Properties="#(SubProjBuildProps)"/> </Target>
|
I'm guessing you would want another operator to denote a property list versus an item list?
I would also like to have a condition evaluation function called "Defined()" that determines if a property has been defined or not e.g.:
| |
<ItemGroup> <Files ...> <SuppressDocGen/> </Files> <Files ... /> </ItemGroup><Target ...> <DocGen Condition="!Defined($(SuppressDocGen))" ... /> </Target>
|
That is much nicer that having to assign some bogus value like yes, true, y, and then have to test for the bogus value.
BTW I wouldn't want to see you guys go too crazy adding new features. MSBuild is something you can wrap your mind around pretty easily right now and I like that. :-)
Dan I was looking on the MSBuild Wiki about this request to support PropertyGroups and ItemGroups within Targets. Let me argue against doing this. First, this obviously doesn't replace CreateItem since CreateItem allows copying from one collection to another and also provides filtering of that copying. Second, for the static case, using the existing ItemGroup and PropertyGroup elements works fine. In fact by placing this information in the target you start to mix up the "what" (items) with the "how" (targets/tasks). I like the notion of putting the "how" into reusable .targets files such that the typical msbuild project file just specifies the "what" (items) and provides some declarative guidance (properties) to the .targets file.
Hello,
The syntax that I prefer is something like that:
<MSBuild projects="myproject.xml" targets="mytarget">
<PropertyGroup>
<FisrtProperty>FirstPropertyValue</FisrtProperty>
<SecondProperty>SecondPropertyValue</SecondProperty>
...
</PropertyGroup>
</MSBuild>
The idea of treating PropertyGroup's as actual groups (today it is just a convenient tag to indicate the nature of its child elements) is interesting. But then could you name ItemGroups... ought ItemGroup to indicate some group trait of its children? I think we'd need a pretty compelling set of scenarios to add new syntax like this.
Whether or not we allow PG/IG in targets (I understand your arguments) I suspect we may end up giving items and properties some of the powers of each other or making them easily interchangeable. We are getting some rude exposure to the real world converting the build process for developer division (devdiv). Some parts of the targets files are beautiful -- where CL for example is invoked as a task with 50 descriptively named attributes like "PreprocessToFile" and "OmitLineNumbers" rather than as the end product of scads of nondescriptive switch concatenation like "/P /EP" in a makefile -- and some parts are not so beautiful. Much of the ugliness in my view always seems to somehow relate to CreateItem/CreateProperty, and I've been enumerating what I see as their various pains on our internal wiki. For example, having to use CreateItem to slosh a property into a list, when you only used a property in the first place so you could in some circumstances erase it. That suggests it would be useful to be able to clear out item lists like you can properties. There are many other variations of this: it should probably be possible to modify items in a list without sloshing into another list.
Discussing this soon impinges on whether we should have types and constraints. For example, if a list always has exactly one item, I can safely write an expression like this in an Exec command
/I@(IntermediateOutputPath)\blah.h
and it will work fine but if there's ever more than one item it will make garbage. I should have written
@(IntermediateOutputPath->'/I%(Identity)', ' ')
A similar bug would occur if I had written
/I%(IntermediateOutputPath.Filename)\blah.h
which would work as expected until there was more than one item, when batching would start happening. It would be nice if I could either prevent this item type having more than one item, or be able to write expressions like this on a property instead. Thinking a bit more wildly, perhaps lists should be able to contain other lists, or meta-data be able to contain lists...
At some point I'm going to create some experimental syntax and features in my head and re-write parts of the devdiv targets. If all the ugliness is gone, that says something. I do have a list of file-format gripes gotten from a team survey, and I should post it...
I actually wanted to add Defines() at the last minute for basically the exact reason you describe. It was just a couple lines' code change. In the devdiv build, there's plenty of places you want to set default values for properties in the common targets files, but in some cases a blank value for those properties is actually significant. For example in a project or subtree I don't want to set either /OPT:REF or /OPT:NOREF on the linker, so I leave <OptRef> property blank. But in the targets say I want a default of /OPT:REF. How do the targets know if the project wanted it blank or didn't care? I end up creating a <NoDefaultOptRef> property and that's pretty lame. The decision for Defines() was I shouldn't add something like that at the last minute, we should take our time to think about whether to create something as important as a distinction between blank and undefined. So we didn't add it (yet).
Dan
"The decision for Defines() was I shouldn't add something like that at the last minute, we should take our time to think about whether to create something as important as a distinction between blank and undefined. So we didn't add it (yet)."
And believe it or not, I do appreciate that kind of thinking a lot. In the past, Microsoft has been a bit too willing to throw in scads of features. Better to think through the consequences first and get it right the first time and that assumes you conclude it is worth doing.