How to call second target in Msbuild - c#

I need to call the second target in the msbuild but when I'm calling it in the cmd it shows error my code is give below
MsBuild.csproj
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<alen>123456</alen>
</PropertyGroup>
<Target Name="FirstTarget">
<Message Text="Hello World $(alen)" />
</Target>
<Target Name="SecondTarget">
<Message Text="The second target" />
</Target>
</Project>
The first target called successfully but I cant load the second Target...How it is possible???

Since you have not defined it, the default target is the first target in the file, FirstTarget. To call the second target from the command line you need call it explicitly with /t:SecondTarget. You can use /t:FirstTarget;SecondTarget if you want to run both.
You could also define SecondTarget to always come after first target. Use the AfterTargets attribute like so:
<Target Name="SecondTarget" AfterTargets="FirstTarget">
Now msbuild msbuild.proj would call both targets.

I know this is a really old post, but you can also have one target call other targets.
<Target Name="Build">
<CallTarget Targets="PreBuild"/>
<CallTarget Targets="Main"/>
<CallTarget Targets="AfterBuild"/>
</Target>

Have you tried
%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe "D:\test_2\MsBuild\MsBuild\BuildScript\MsBuild.csproj" /t:SecondTarget
?

Another option is to define a default target in your build file and than define the order of targets using the DependsOnTargets:
<Project DefaultTargets="DefaultTarget" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<Target Name="DefaultTarget" DependsOnTargets="FirstTarget;SecondTarget">
<Message Text="Executing DefaultTarget" />
</Target>
<!-- your targets -->
</Project>
The targets defined in DependsOnTargets will run before the target itself is running.
Doing it this way, you do not need to set the /t: parameter in your call.

Related

Access PropertyGroup outside Target

Problem
I defined 4 custom Property at a top level PropertyGroup:
AndroidResourcesFolder
NugetFolder
BrandingFiles (uses NugetFolder)
AssemblyFile (uses BrandingFiles)
... and I want to access AndroidResourcesFolder from a Target.
When accesing AssemblyFile from a UsingTask, the Property is properly resolved, but when I access AndroidResourcesFolder from a Target, Visual Studio reports that the Property has no value:
error MSB4044: The "Mobile.Branding.Build.Task.CleanResources" task was not given a value for the required parameter "AndroidResourcesFolder".
Code
This is my .targets file:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<AndroidResourcesFolder>$(MSBuildProjectDirectory)\Resources\</AndroidResourcesFolder>
<NugetFolder>$(MSBuildThisFileDirectory)..\..\</NugetFolder>
<BrandingFiles>$(NugetFolder)MonoAndroid81\</BrandingFiles>
<AssemblyFile>$(BrandingFiles)\Amaris.Mobile.Branding.Build.dll</AssemblyFile>
</PropertyGroup>
<UsingTask
TaskName="Mobile.Branding.Build.Task.CleanResources" AssemblyFile="$(AssemblyFile)" />
<UsingTask
TaskName="Mobile.Branding.Build.Task.ReadConfig" AssemblyFile="$(AssemblyFile)" />
<Target Name="ReadConfig" >
<PropertyGroup>
<ConfigFile>$(MSBuildProjectDirectory)\branding.xml</ConfigFile>
</PropertyGroup>
<Mobile.Branding.Build.Task.ReadConfig
ConfigFile="$(ConfigFile)" />
</Target>
<Target Name="BeforeClean" DependsOnTargets="ReadConfig" >
<Mobile.Branding.Build.Task.CleanResources
AndroidResourcesFolder="$(AndroidResourcesFolder)" />
</Target>
</Project>
Question
Why were only 3 Property resolved and the rest (AndroidResourcesFolder) left out ?
Thanks!

Substring under PropertyGroup in msbuild props not working when property is passed as argument to msbuild

In my props file, i pass the BUILD_VERSION to dotnet msbuild using properties as /p:BUILD_VERSION=1.2.3.4. However, i get errors on when performing Substring operation on property BuildVersion which gets its value from : BUILD_VERSION.
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<IntermediateOutputPath>./obj/</IntermediateOutputPath>
<BuildVersion>$(BUILD_VERSION)</BuildVersion>
<InformationalVersion>$(BuildVersion)</InformationalVersion>
<BuildMajorVersion>$([System.String]::Concat($(BuildVersion.Substring(0, $(BuildVersion.IndexOf('.')))), ".0.0.0"))</BuildMajorVersion>
<AssemblyVersion>$(BuildMajorVersion)</AssemblyVersion>
<AssemblyFileVersion>$(BuildMajorVersion)</AssemblyFileVersion>
</PropertyGroup>
The error that i get is : """.Substring(0,-1)" length should be inside the string
I checked that BUILD_VERSION is present by printing in it in Message.
<Target Name="SetBuildVersions" BeforeTargets="BeforeBuild">
<Message Importance="High" Text="BUILD_VERSION=$(BUILD_VERSION)"/>
</Target>
It prints BUILD_VERSION=1.2.3.4.
If i hardcode <BuildVersion>1.2.3.4</BuildVersion> instead of <BuildVersion>$(BUILD_VERSION)</BuildVersion> below, it works.
If i use the Substring code inside a Target it works :
<Target Name="SetBuildVersions" BeforeTargets="BeforeBuild">
<PropertyGroup>
<InformationalVersion>$(BuildVersion)</InformationalVersion>
<BuildMajorVersionOnly>$([System.String]::Concat($(BuildVersion.Substring(0, $(BuildVersion.IndexOf('.')))), ".0.0.0"))</BuildMajorVersionOnly>
<AssemblyVersion>$(BuildMajorVersionOnly)</AssemblyVersion>
<AssemblyFileVersion>$(BuildMajorVersionOnly)</AssemblyFileVersion>
</PropertyGroup>
</Target>
Why can't i use the Substring inside normal PropertyGroup when passing BUILD_VERSION as property argument to msbuild ?

Change assembly name for build settings in .csproj

I have an application which I want to publish with ClickOnce via command line. I have a test and a live version. It should be allowed to have both installed at the same time, which means that I need to change the assemble name (and preferably also the product name) for one of the builds. I would like to do this in the build settings.
I have managed to make some build settings, which works fine, but I cannot figure out how to change the assembly and product name, for just one of them.
I have added the following code to my .csproj file, which I call with the command msbuild /target:Test or msbuild /target:Live. But where do I implement the assembly and product name change?
<PropertyGroup>
<ProjLocation>$(ProjectDir)</ProjLocation>
<ProjLocationReleaseDir>$(ProjLocation)\bin\Debug</ProjLocationReleaseDir>
<ProjPublishLocation>$(ProjLocationReleaseDir)\app.publish</ProjPublishLocation>
<DeploymentFolder>C:\MyProjects\Software\Publish\</DeploymentFolder>
</PropertyGroup>
<!-- Build settings for live version -->
<Target Name="Live" DependsOnTargets="Clean">
<MSBuild Projects="$(ProjLocation)\$(ProjectName).csproj"
Properties="$(DefaultBuildProperties)"
Targets="Publish"/>
<ItemGroup>
<SetupFiles Include="$(ProjPublishLocation)\*.*"/>
<UpdateFiles Include="$(ProjPublishLocation)\Application Files\**\*.*"/>
</ItemGroup>
<Copy SourceFiles="#(SetupFiles)" DestinationFolder="$(DeploymentFolder)\Live\" />
<Copy SourceFiles="#(UpdateFiles)" DestinationFolder="$(DeploymentFolder)\Live\Application Files\%(RecursiveDir)"/>
</Target>
<!-- Build settings for test version -->
<Target Name="Test" DependsOnTargets="Clean">
<MSBuild Projects="$(ProjLocation)\$(ProjectName).csproj"
Properties="$(DefaultBuildProperties)"
Targets="Publish"/>
<ItemGroup>
<SetupFiles Include="$(ProjPublishLocation)\*.*"/>
<UpdateFiles Include="$(ProjPublishLocation)\Application Files\**\*.*"/>
</ItemGroup>
<Copy SourceFiles="#(SetupFiles)" DestinationFolder="$(DeploymentFolder)\Public Test\" />
<Copy SourceFiles="#(UpdateFiles)" DestinationFolder="$(DeploymentFolder)\Public Test\Application Files\%(RecursiveDir)"/>
</Target>
You can add "AssemblyName" property to the PropertyGroup. like this:
<PropertyGroup>
<AssemblyName>YourAppName</AssemblyName>
</PropertyGroup>
or you can use the MSBuild command line switch. like this :
msbuild /property:AssemblyName=YourAppName
I had almost the same task (need to distinguish between Staging and Production) and I solved it with the following MSBuild-Target:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- call "nuget restore Deployment\packages.config" before executing this script -->
<Import Project="..\packages\MSBuildTasks.1.5.0.235\build\MSBuildTasks.targets" />
<PropertyGroup>
<Configuration>Release</Configuration>
<ClientProject>..\MyProject\MyProject.vbproj</ClientProject>
<ClientPublishDir Condition="$(Environment) == 'Staging'">\\deployment-staging\MyProject\</ClientPublishDir>
<ClientPublishDir Condition="$(Environment) == 'Production'">\\deployment\MyProject\</ClientPublishDir>
</PropertyGroup>
<ItemGroup>
<ClientModifiedAppConfig Include="$(ClientProject)\..\App.$(Environment).config" />
</ItemGroup>
<Target Name="DeployClient">
<Error Condition="$(Environment) == ''" Text="The Property 'Environment' has not been set." />
<Error Condition="$(Environment) != 'Staging' AND $(Environment) != 'Production'" Text="The Property 'Environment' has not been set properly. Valid values are 'Staging' and 'Production'." />
<!-- Sets different assembly names for INT and PRD applications. Due to this, both INT and PRD applications with the
same version number can be installed on the same system. -->
<XmlUpdate Condition="$(Environment) == 'Staging'" Prefix="n" Namespace="http://schemas.microsoft.com/developer/msbuild/2003" XmlFileName="$(ClientProject)" Xpath="/n:Project/n:PropertyGroup/n:AssemblyName" Value="MyProjectStaging" />
<XmlUpdate Condition="$(Environment) == 'Staging'" Prefix="n" Namespace="http://schemas.microsoft.com/developer/msbuild/2003" XmlFileName="$(ClientProject)" Xpath="/n:Project/n:PropertyGroup/n:ProductName" Value="MyProject Staging" />
<XmlUpdate Condition="$(Environment) == 'Production'" Prefix="n" Namespace="http://schemas.microsoft.com/developer/msbuild/2003" XmlFileName="$(ClientProject)" Xpath="/n:Project/n:PropertyGroup/n:AssemblyName" Value="MyProject" />
<XmlUpdate Condition="$(Environment) == 'Production'" Prefix="n" Namespace="http://schemas.microsoft.com/developer/msbuild/2003" XmlFileName="$(ClientProject)" Xpath="/n:Project/n:PropertyGroup/n:ProductName" Value="MyProject" />
<!-- Overwrites the original App.config with the environment-dependent App.config.
Reason: ClickOnce only uses App.config and does not apply transformations, as it is done in Web Projects. -->
<Copy
SourceFiles="#(ClientModifiedAppConfig)"
DestinationFiles="$(ClientProject)\..\App.config"
OverwriteReadOnlyFiles="true"
/>
<!-- Publish -->
<MSBuild
Projects="$(ClientProject)"
Targets="Publish"
Properties="
PublishDir=$(ClientPublishDir);
Configuration=$(Configuration);
Platform=x86" />
</Target>
</Project>
To make this work, you have to restore the NuGet package MSBuildTasks.
Finally, all I have to call is msbuild Deployment.targets /t:DeployClient /p:Environment=Staging
Hope that helps!

How can I set the LIB environment variable inside a csproj file?

I'm operating on a system where the environment variable LIB is set to "--must-override--". I cannot change the value of the variable on the system itself.
In Visual Studio, the LIB variable is checked during compilation. Because it's set to a junk value, I get a warning in the build:
Invalid search path '--must-override--' specified in 'LIB environment variable' -- 'The system cannot find the path specified.
I'd like to get rid of this warning. To do so, I need to override the value of the LIB environment variable that VS uses, either to NULL or to some value pointing to a real path.
Since I can't change the value of the variable in the environment, I need to do it within the csproj file itself. I've tried setting it in a property group to no avail:
<PropertyGroup>
<Lib></Lib>
</PropertyGroup>
Any ideas on how this variable can be set? Or if it's even possible?
You can mangle it in using the Exec Task, or you can write your own Task to set them - here's the "Let's mangle away with Exec" route:
<PropertyGroup>
<!--
need the CData since this blob is just going to
be embedded in a mini batch file by studio/msbuild
-->
<LibSetter><![CDATA[
set Lib=C:\Foo\Bar\Baz
set AnyOtherEnvVariable=Hello!
]]></LibSetter>
</PropertyGroup>
<Exec Command="$(LibSetter)" />
EDIT:
So I just threw this csproj together with the basics - I've confirmed they do set properly when I run them - I've added in the inline-Task approach as well.
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask
TaskName="EnvVarSet"
TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<VarName ParameterType="System.String" Required="true"/>
<VarValue ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Code Type="Fragment" Language="cs">
<![CDATA[
Console.WriteLine("Setting var name {0} to {1}...", VarName, VarValue);
System.Environment.SetEnvironmentVariable(VarName, VarValue);
Console.WriteLine("{0}={1}", VarName, VarValue);
]]>
</Code>
</Task>
</UsingTask>
<Target Name="ThingThatNeedsEnvironmentVars">
<CallTarget Targets="FiddleWithEnvironmentVars"/>
<Message Text="LIB environment var is now: $([System.Environment]::GetEnvironmentVariable('LIB'))"/>
</Target>
<Target Name="FiddleWithEnvironmentVars">
<Message Text="LIB environment var is now: $([System.Environment]::GetEnvironmentVariable('LIB'))"/>
<EnvVarSet VarName="LIB" VarValue="C:\temp"/>
<Message Text="LIB environment var is now: $([System.Environment]::GetEnvironmentVariable('LIB'))"/>
</Target>
</Project>

How to integrate conditional logic in postbuild events

Hi I have a visual studio project which includes postbuildevents in the following form:
MyTool.exe $(ProjectDir)somesrcfile.txt $(TargetDir)sometargetfile.bin
Now I want to add some logic saying that these steps are taking place only if the files have changed. In peudocode:
if (somesrcfile.txt is newer than sometargetfile.bin)
{
MyTool.exe $(ProjectDir)somesrcfile.txt $(TargetDir)sometargetfile.bin
}
Can I do this with MsBuild?
EDIT:
I just tried it with a simple copy command but it seems not to work. Also the message is not displayed when I build the solution.
<ItemGroup>
<MyTextFile Include="*.txt" />
</ItemGroup>
<Target Name="Build" Inputs="#(MyTextFile)" Outputs="#(MyTextFile->'%(Filename).bin')">
<CustomBuild>
<Message>Encoding files...</Message>
<Command>
copy %(Identity) %(Filename).bin
</Command>
<Outputs>$(OutDir)%(Identity)</Outputs>
</CustomBuild>
</Target>
Yes, it is possible by using the Inputs and Outputs attributes on your target.
See: How to: Build incrementally
In your case, it would look something like this:
<Target Name="AfterBuild" DependsOnTargets="Test">
</Target>
<ItemGroup>
<MyTextFile Include="*.txt" />
</ItemGroup>
<Target Name="Test" Inputs="#(MyTextFile)" Outputs="#(MyTextFile->'%(FileName).bin')">
<Message Text="Copying #(MyTextFile)" Importance="high"/>
<Copy SourceFiles="#(MyTextFile)" DestinationFiles="#(MyTextFile->'%(FileName).bin')" />
</Target>
This target will only run if input files are newer than output files.

Categories