I have defined several AfterBuild - Tasks in my Visual Studio project with different conditions:
<Target Name="AfterBuild" Condition="'$(Configuration)'=='FinalBuilder'">
<Message Importance="high" Text="--- AfterBuild for FinalBuilder ---" />
</Target>
<Target Name="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
<Message Importance="high" Text="--- AfterBuild for MvcBuildViews ---" />
</Target>
But only the last one is executed if the condition match. If I choose the FinalBuilder-Configuration, the AfterBuild tasks is ignored and not executed. If I change the order of the Targets in the project files (Condition="'$(Configuration)'=='FinalBuilder'" as last one), the AfterBuild for FinalBuilder-Configuration is executed but the one for MvcBuildViews is ignored.
Is the order of the target important? Is only the last AfterBuild task taken into account? Or how can I define different AfterBuild tasks with different Conditions?
Thanks
Konrad
The only second one is executed because it was redefined. See MSDN (Declaring targets in the project file chapter).
You should use only one AfterBuild target in your project file like this:
<Target Name="AfterBuild" >
<Message Condition="'$(MvcBuildViews)'=='true'" Importance="high" Text="--- AfterBuild for MvcBuildViews ---" />
<Message Condition="'$(Configuration)'=='FinalBuilder'" Importance="high" Text="--- AfterBuild for FinalBuilder ---" />
</Target>
EDIT:
Or use CallTarget task:
<Target Name="AfterBuild" >
<CallTarget Condition="'$(MvcBuildViews)'=='true'" Targets="MvcBuildTarget" />
<CallTarget Condition="'$(Configuration)'=='FinalBuilder'" Targets="FinalBuilderTarget" />
</Target>
<Target Name="MvcBuildTarget">
<Message Importance="high" Text="--- AfterBuild for MvcBuildViews ---" />
</Target>
<Target Name="FinalBuilderTarget" >
<Message Importance="high" Text="--- AfterBuild for FinalBuilder ---" />
</Target>
If you really need to run multiple AfterBuild tasks (this may be the case for example if you need different Input and Output sets for each task) you can use DependsOnTarget to simply make AfterBuild depend upon all of them:
<Target Name="AfterBuild1"
Inputs="stuff"
Outputs="stuff">
<Message Text="Running first after build task." Importance="high" />
<Exec Command="stuff" />
</Target>
<Target Name="AfterBuild2"
Inputs="other stuff"
Outputs="other stuff">
<Message Text="Running other after build task." Importance="high" />
<Exec Command="stuff" />
</Target>
<Target Name="AfterBuild" DependsOnTargets="AfterBuild1;AfterBuild2" />
If you need to constrain their order, just make AfterBuild2 depend on AfterBuild1 with DependsOnTargets="AfterBuild1".
Related
I have a WinForms NET4.8 desktop app that I publish using ClickOnce. I have a dll file in a project subfolder that I need published to the same directory as the main app. I have the following in my csproj file:
<PropertyGroup>
<UnreferencedDlls>lib\twaindsm.dll</UnreferencedDlls>
</PropertyGroup>
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
<Target Name="AfterBuild">
<Message Text="Copying unreferenced DLLs to bin" Importance="High" />
<CreateItem Include="$(UnreferencedDlls)">
<Output TaskParameter="Include" ItemName="_UnReferencedDLLs" />
</CreateItem>
<Copy SourceFiles="#(_UnReferencedDLLs)" DestinationFolder="$(OutputPath)\%(RecursiveDir)" SkipUnchangedFiles="true" />
</Target>
<Target Name="CustomCollectFiles">
<Message Text="Publishing unreferenced DLLs" Importance="High" />
<ItemGroup>
<_CustomFiles Include="$(UnreferencedDlls)" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>$(OutputPath)\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
The file is published to the subfolder.
I change this line:
<DestinationRelativePath>$(OutputPath)\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
to:
<DestinationRelativePath>$(OutputPath)\%(Filename)%(Extension)</DestinationRelativePath>
But it still doesn't work.
How can I force the file to be published to the same folder as the app?
I don't know if it can help you: %(RecursiveDir)
If the Include attribute contains the wildcard **, this metadata
specifies the part of the path that replaces the wildcard.
Maybe you can try to change the path of the dll. I put it into ProjectDir\lib\Debug\ and here is my code:
<PropertyGroup>
<UnreferencedDlls>lib\**\ClassLibrary1.dll</UnreferencedDlls>
</PropertyGroup>
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
<Target Name="AfterBuild">
<Message Text="Copying unreferenced DLLs to bin" Importance="High" />
<CreateItem Include="$(UnreferencedDlls)">
<Output TaskParameter="Include" ItemName="_UnReferencedDLLs" />
</CreateItem>
<Copy SourceFiles="#(_UnReferencedDLLs)" DestinationFolder="bin\%(RecursiveDir)" SkipUnchangedFiles="true" />
</Target>
<Target Name="CustomCollectFiles">
<Message Text="Publishing unreferenced DLLs" Importance="High" />
<ItemGroup>
<_CustomFiles Include="$(UnreferencedDlls)" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>bin\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
You can also refer to this page hope it can help you.
I am looking for a way to run my defined Target only once per build process and not for every project that gets build.
I have defined the following in Directory.Build.props
<Target Name="MyTarget" AfterTargets="AfterBuild" >
<Message Text="Hello World!!!" Importance="High" />
</Target>
Should only run once no matter how many projects the msbuild process is building, currently it happens for each project.
It shouldn't matter if I hit (Re-)Build Soltution or (Re-)Build [ProjectName] or hit F5 in Visual Studio, as long any build happens I want to exectue MyTarget only once.
Just answer this situation:
If my guess is right, pure msbuild function is not enough and you have to use a external file to help it work.
create a file called test.txt on the solution folder and write 0 in the txt file.
Then, modify your Directory.Build.props like this:
<Project>
<PropertyGroup>
<Record></Record>
</PropertyGroup>
<ItemGroup>
<File Include="..\test.txt"></File>
</ItemGroup>
<Target Name="GetConditionValue" BeforeTargets="PrepareForBuild">
<ReadLinesFromFile File="#(File)">
<Output TaskParameter="Lines" PropertyName="Record"/>
</ReadLinesFromFile>
</Target>
<Target Name="MyTarget" AfterTargets="Build" Condition="'$(Record)'=='0'">
<WriteLinesToFile File="#(File)" Lines="2" Overwrite="true"></WriteLinesToFile>
<Message Text="Hello World!!!" Importance="High" />
</Target>
</Project>
When you start a new build process, you should clear the test.txt file to 0 to make a new start.
I've seen some answers to a similar question but not exactly the same and not with positive luck trying to use suggested solutions... so I'm trying something like this:
<project>
<target name="foo" Condition="'$(Configuration)' == 'Debug' ">
<Message Text="=== RUNNING FOO DEBUG TARGET ===" />
</target>
<target name="foo" Condition="'$(Configuration)' == 'Release' ">
<Message Text="=== RUNNING FOO RELEASE TARGET ===" />
</target>
</project>
... but I'm finding that it doesn't appear to be possible to have two targets with the same name working properly under these conditions. One will negate the other.
How can I do this?
Provide a wrapper target, that depends on both targets.
The both will be called, but only the one matching the
condition will actually do something.
<Project>
<Target Name="foo" DependsOnTargets="_fooDebug;_fooRelease"/>
<Target Name="_fooDebug" Condition="'$(Configuration)' == 'Debug' ">
<Message Text="=== RUNNING FOO DEBUG TARGET ===" />
</Target>
<Target Name="_fooRelease" Condition="'$(Configuration)' == 'Release' ">
<Message Text="=== RUNNING FOO RELEASE TARGET ===" />
</Target>
</Project>
In Visual Studio am creating a post-build event for Deploying using
md "$(SolutionDir)Deploy\bin"
which created the bin folder inside Deploy folder, inside my Solution.
How do I point this to the folder in some remote machine (where I have the web server)?
$(SolutionDir) to some other folder on a remote machine?
It may look simple to you. :) This is the first time am trying this stuff.
Thanks
The easiest way is to replace $(SolutionDir) with \\server\share
Just as an alternative, I like to keep my .sln and .csproj files "clean".
Then use a second (mini) .msbuild ( which is just a .xml file) to build the .sln, and then do these copy type events as a second action.
Here is a basic example:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="AllTargetsWrapper">
<PropertyGroup>
<WorkingCheckout>.</WorkingCheckout>
<WorkingOutputs>m:\working\outputs</WorkingOutputs>
</PropertyGroup>
<Target Name="AllTargetsWrapper">
<CallTarget Targets="Clean" />
<CallTarget Targets="Build" />
<CallTarget Targets="CopyItUp" />
</Target>
<Target Name="Clean">
<RemoveDir Directories="$(WorkingOutputs)" />
<MakeDir Directories="$(WorkingOutputs)" />
<Message Text="Cleaning done" />
</Target>
<Target Name="Build">
<MSBuild Projects="$(WorkingCheckout)\MySolution.sln" Targets="Build" Properties="Configuration=$(Configuration)">
<Output TaskParameter="TargetOutputs" ItemName="TargetOutputsItemName"/>
</MSBuild>
<Message Text="Build completed" />
</Target>
<!-- -->
<Target Name="CopyItUp" >
<ItemGroup>
<MyExcludeFiles Include="$(WorkingCheckout)\**\SuperSecretStuff.txt" />
<MyExcludeFiles Include="$(WorkingCheckout)\**\SuperSecretStuff.doc" />
</ItemGroup>
<ItemGroup>
<MyIncludeFiles Include="$(WorkingCheckout)\MyCsProject\bin\$(Configuration)\**\*.*" Exclude="#(MyExcludeFiles)"/>
</ItemGroup>
<Copy
SourceFiles="#(MyIncludeFiles)"
DestinationFiles="#(MyIncludeFiles->'$(WorkingOutputs)\%(RecursiveDir)%(Filename)%(Extension)')"
/>
</Target>
</Project>
I have this in my Visual Studio Project
<Target Name="BeforeBuild">
<Message Text="Compiling TypeScript files" />
<Message Text="Executing tsc$(TypeScriptSourceMap) #(TypeScriptCompile ->'"%(fullpath)"', ' ')" />
<Exec Command="tsc$(TypeScriptSourceMap) #(TypeScriptCompile ->'"%(fullpath)"', ' ')" IgnoreExitCode="true" />
</Target>
I want to execute the stuff within the <Target Name="BeforeBuild"></Target> if the Configuration is Debug and the Platform is AnyCPU. Is this possible and if so how is it done?
Try the following
<Target Name="BeforeBuild" Condition="'$(Configuration)' == 'Debug' And '$(Platform)' == 'AnyCPU'">
Slightly more fancy version
<Target Name="BeforeBuild" Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">