It seems like if I have a csproj file like the following, I end up with BAR defined and FOO not defined.
<PropertyGroup>
<DefineConstants>FOO</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<DefineConstants>BAR</DefineConstants>
</PropertyGroup>
Is there a syntax for "Define additional constants" so that I can use it and end up with both FOO and BAR defined?
I am aware that in this contrived example, I could just have
<PropertyGroup>
<DefineConstants>FOO BAR</DefineConstants>
</PropertyGroup>
But my actual use case is more complicated. I really need to be able to define a constant in addition to whatever was set before.
This does it:
<PropertyGroup>
<DefineConstants>FOO</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<DefineConstants>$(DefineConstants);BAR</DefineConstants>
</PropertyGroup>
Related
In building an MSBuild script, I need to define a series of properties that are default but can be overridden when running the script. According to the following article, you should use a Conditional to default the property:
http://msdn.microsoft.com/en-us/library/ee240983.aspx
How Microsoft recommends:
<PropertyGroup>
<MyProperty Condition="'$(MyProperty)' == '' ">Default Value</MyProperty>
</PropertyGroup>
However, this behaves exactly the same way:
<PropertyGroup>
<MyProperty>Default Value Without Conditional</MyProperty>
</PropertyGroup>
So, if I have this Target and invoke it with either of the above, it has the same behavior:
<Target Name="DefaultsTest">
<Message Text="$(MyProperty)"></Message>
</Target>
Invocation:
msbuild build.xml /t:DefaultsTest /p:MyProperty="Overridden value"
Please explain the benefits of using the Condition attribute if you are only defaulting the same property that can be overridden from the invocation?
Update:
Here is a full simple config file to demonstrate: defaults.xml
<?xml version="1.0" encoding="utf-8" ?>
<Project DefaultTargets="DefaultsTest" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MyProperty Condition=" '$(MyProperty)' == '' ">MyProperty with Conditional</MyProperty>
<MyOtherProperty>MyOtherProperty without Conditional</MyOtherProperty>
</PropertyGroup>
<Target Name="DefaultsTest">
<Message Text="$(MyProperty)"></Message>
<Message Text="$(MyOtherProperty)"></Message>
</Target>
</Project>
This can be run simply as msbuild defaults.xml
or
msbuild defaults.xml /p:MyProperty="Changed Value" /p:MyOtherProperty="Changed as well"
You correctly noticed, that you can achieve behavior you want with unconditional assignment of property. The following project when built without /p: override on command line will produce Default Value. And when built using command msbuild myproj.proj /t:DefaultsTest /p:MyProperty=NewValue will produce NewValue.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MyProperty>Default Value</MyProperty>
</PropertyGroup>
<Target Name="DefaultsTest">
<Message Text="MyProperty=$(MyProperty)"></Message>
</Target>
</Project>
This is because any properties specified on MSBuild command line or provided as a parameter of task will be treated as Global Properties. For global properties, any assignment or modifications, either conditional or unconditional, are simply ignored -- global properties will remain constant throughout lifetime of the project execution.
The only difference in behavior between conditional assignment and unconditional will be if you use TreatAsLocalProperty attribute.
For example, consider the following project:
<Project TreatAsLocalProperty="Prop1;Prop2" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Prop1>Prop1 Default Value</Prop1>
<Prop2 Condition="$(Prop2) == ''">Prop2 Default Value</Prop2>
</PropertyGroup>
<Target Name="DefaultsTest">
<Message Text="Prop1=$(Prop1)"></Message>
<Message Text="Prop2=$(Prop2)"></Message>
</Target>
</Project>
Two properties -- Prop1 and Prop2 are both declared as local in the Project element. Prop1 is assigned unconditionally, while Prop2 is assigned using non-empty condition. Executing build command:
msbuild b.proj /t:DefaultsTest /p:Prop1=NewValue1 /p:Prop2=NewValue2
will produce output:
Prop1=Prop1 Default Value
Prop2=NewValue2
This means that in general case (if you are not absoluterly sure if property will be global or local), it is safer to use conditional assignment of the default value, because it works always.
I would like to change the value of a property if it is a certain value. In C# I would write:
if(x=="NotAllowed")
x="CorrectedValue;
This is what I have so far, please don't laugh:
<PropertyGroup>
<BranchName>BranchNameNotSet</BranchName>
</PropertyGroup>
///Other targets set BranchName
<Target Name="CheckPropertiesHaveBeenSet">
<Error Condition="$(BranchName)==BranchNameNotSet" Text="Something has gone wrong.. branch name not entered"/>
<When Condition="$(BranchName)==master">
<PropertyGroup>
<BranchName>MasterBranch</BranchName>
</PropertyGroup>
</When>
</Target>
You can do that using Condition on Property:
<PropertyGroup>
<BranchName>BranchNameNotSet</BranchName>
</PropertyGroup>
<Target Name="CheckPropertiesHaveBeenSet">
<!-- If BranchName equals 'BranchNameNotSet' stop the build with error-->
<Error Condition="'$(BranchName)'=='BranchNameNotSet'" Text="Something has gone wrong.. branch name not entered"/>
<PropertyGroup>
<!-- Change BranchName value if BranchName equals 'master' -->
<BranchName Condition="'$(BranchName)'=='master'">MasterBranch</BranchName>
</PropertyGroup>
</Target>
Info on When and Choose:
The Choose, When, and Otherwise elements are used together to provide a way to select one section of code to execute out of a number of possible alternatives.
Choose elements can be used as child elements of Project, When and Otherwise elements.
In your code sample, you use When without Choose and within a target, that is not possible.
this sets BranchName to the string 'CorrectedValue' if it's value equals 'NotAllowed':
<PropertyGroup>
<BranchName Condition="'$(BranchName)'=='NotAllowed'">CorrectedValue</BranchName>
</PropertyGroup>
In MSBuild I have a property which value is Name_Something. How can I get name part of this property.
With MSBuild 4
If you use MSBuild 4, you could use the new and shiny property functions.
<PropertyGroup>
<MyProperty>Name_Something</MyProperty>
</PropertyGroup>
<Target Name="SubString">
<PropertyGroup>
<PropertyName>$(MyProperty.Substring(0, $(MyProperty.IndexOf('_'))))</PropertyName>
</PropertyGroup>
<Message Text="PropertyName: $(PropertyName)"/>
</Target>
With MSBuild < 4
You could use the RegexReplace task of MSBuild Community Task
<PropertyGroup>
<MyProperty>Name_Something</MyProperty>
</PropertyGroup>
<Target Name="RegexReplace">
<RegexReplace Input="$(MyProperty)" Expression="_.*" Replacement="" Count="1">
<Output ItemName ="PropertyNameRegex" TaskParameter="Output" />
</RegexReplace>
<Message Text="PropertyNameRegex: #(PropertyNameRegex)"/>
</Target>
If I understand your question correctly you are trying to get the substring of a MSBuild property. There is no direct way to do string manipulation in MSBuild, like in NAnt. So you have two options:
1). Create separate variables for each part and combine them:
<PropertyGroup>
<Name>Name</Name>
<Something>Something</Something>
<Combined>$(Name)_$(Something)</Combined>
</PropertyGroup>
This works fine if the parts are known before hand, but not if you need to do this dynamically.
2). Write a customer MSBuild task that does the string manipulation. This would be your only option if it needed to done at runtime.
It looks like you could use Item MetaData instead of a Property:
<ItemGroup>
<Something Include="SomeValue">
<Name>YourName</Name>
<SecondName>Foo</SecondName>
</Something>
</ItemGroup>
I would like to do something like this:
<PropertyGroup>
<propone>value</propone>
</PropertyGroup>
<PropertyGroup>
<proptwo>$(propone)</proptwo>
</PropertyGroup>
Pass one property value as another. Is there a way to do this? How?
I think you provided the answer right there in your question: yes, it is possible in just the way that you suggested.
An example:
<Project ToolsVersion="3.5" DefaultTargets="Test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SomeProperty>Some Property Value</SomeProperty>
</PropertyGroup>
<PropertyGroup>
<SomeOtherProperty>$(SomeProperty) with something added to it</SomeOtherProperty>
</PropertyGroup>
<Target Name="Test">
<Message Text="$(SomeOtherProperty)" />
</Target>
</Project>
This will print Some Property Value with something added to it.
I'm trying to set a default value for an MSBuild property. Say I start with this:
<Choose>
<When Condition="..something..">
<PropertyGroup>
...
<MySetting>true</MySetting>
<PropertyGroup>
</When>
...
</Choose>
If the condition is not true, then MySetting will be ''. So shouldn't this set it to false?
<PropertyGroup>
<MySetting Condition="'$(MySetting)'==''">false</MySetting>
</PropertyGroup>
Later on, I'd like to use MySetting in a conditional without having to test for =='true', like this:
<PropertyGroup Condition="$(MySetting)">
...
</PropertyGroup>
Yet when I load this project into Visual Studio it complains that the specified condition "$(MySetting)" evaluates to "" instead of a boolean.
So it appears that either my condition that checks for '' to assign the property to false is incorrect. What am I doing wrong?
In MSBuild, you're dealing with strings so you get the '' instead of false...if you want to default it to 'false' and override via the command line, just declare a property group above your existing condition block in the script:
<PropertyGroup>
<MySetting>false</MySetting>
</PropertyGroup>
Your condition block below can set this to true, or you could also set it via the command line, like this:
MSBuild.exe MyMSBuildFile.csproj /p:MySetting=true
If you want to declare defaults for properties better then using Chose is to do it on the property as:
<PropertyGroup>
<MySetting Condition=" '$(MySetting)'=='' ">true</MySetting>
</PropertyGroup>
Also for conditions always wrap the left and right side in '', even if you are dealing with what should be bool values. So change your second property group to look like:
<PropertyGroup Condition=" '$(MySetting)'=='true' ">
</PropertyGroup>