Format to use Exists Condition in MSBuild props file - msbuild

I need to check whether the given folder is available in the given path or not. If that folder is not available in the given path,then it has to take alternative folder mentioned.
So to check the existence of the given folder, i tried
I got error as error MSB4092: An unexpected token "$(D:\DK)" was found at character position 11 in condition "'(Exists('$(D:\DK)')' "
What is the correct format to use this Exists condition?

This is quite basic though it can be confusing apparently..
$(<name>) is used to refer to the property named <name> but you don't seem to have a property, just a string.
So either
<Message Condition="Exists('d:\dk')" Text="It Exists" />
or
<PropertyGroup>
<Dk>d:\dk</Dk>
</PropertyGroup>
<Message Condition="Exists($(Dk))" Text="It Exists" />

I tried the Exists condition with the following scenario and it works fine for me.
<ROOT Condition="Exists('D:\DK')">D:\DK</ROOT>
<ROOT Condition="'$(ROOT)'==''">D:\New\DK</ROOT>

Related

MSBuild GetPathOfFileAbove() returning empty

I am trying to refactor the code below to use GetPathOfFileAbove() instead.
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),global.json))\eng\Configurations.props" />
when i tried the below code, an error was thrown, file not found
<Import Project="$([MSBuild]::GetPathOfFileAbove('global.json','$(MSBuildThisFileDirectory)'))\eng\Configurations.props" />
The path of the above code result in,where "global.json" shouldn't have been here:
"C:\dotnetruntime\runtime\global.json\eng\Configurations.props"
Expected path:
"C:\dotnetruntime\runtime\eng\Configurations.props"
I having a hard time finding documentation to figured out the configuration am missing here. Can you guys give me some pointers
The correct path to use was
"<Import Project="$([MSBuild]::GetPathOfFileAbove(Configurations.props,$(MSBuildThisFileDirectory)))../../../../../eng/Configurations.props" />"
The use of "../" allows the file be searched one directory above.

In MSBuild, why isn't Item Metadata, within a property, being resolved?

Below is a portion of a MSBuild file that I'm working on:
<ItemGroup>
<Tests Include="$(SolutionDir)\**\bin\$(TestPlatform)\$(Configuration)\*.Tests.dll" />
</ItemGroup>
<PropertyGroup>
<TestProperties>/testcontainer:%(Tests.FullPath)</TestProperties>
</PropertyGroup>
I want to have a property that holds a command line switch. However, when I try to use $(TestProperties) in an Exec Command string, %(Tests.FullPath) is never resolved to the absolute path of the Tests item. Instead, it's always processed literally, as "%(Tests.FullPath)".
Am I doing something wrong or is this a standard MSBuild behavior? If the latter, is there a way for me to workaround this?
Thanks
P.S. - I realize I probably don't need to access the FullPath property since my Include value is an absolute path. However, I'd still like to understand the issue, along with how to handle it.
You have a syntax error. Item lists are referenced via the # character and item meta data is referenced via %. Reference the MSBuild Special Character Reference for details. To access the well known item metadata, you need to apply a transform inside the Property itself.
<ItemGroup>
<Tests Include="MyFile.txt" />
</ItemGroup>
<PropertyGroup>
<TestProperties>/testcontainer:#(Tests->'%(FullPath)')</TestProperties>
</PropertyGroup>
You can find more help here

Get list of dlls in a directory with MSBuild

The following gives me only 1 file, the exe:
<ItemGroup>
<AssembliesToMerge Include="$(MSBuildProjectDirectory)\App\bin\Release\*.*" Condition="'%(Extension)'=='.dll'"/>
<AssembliesTomerge Include="$(MSbuildProjectDirectory)\App\bin\Release\App.exe"/>
</ItemGroup>
If I remove the Condition attribute, AssembliesToMerge contains all the files in the directory--dlls and otherwise. What am I doing wrong?
I am testing this via the ILMerge MSBuildCommunityExtensions Task. If there is a way to directly print the items in the ItemGroup, then that might help to ensure it's an issue with the Condition attribute.
Just use a wildcard in Include to filter dll files (Items wildcard)
<ItemGroup>
<AssembliesToMerge Include="$(MSBuildProjectDirectory)\App\bin\Release\*.dll"/>
<AssembliesTomerge Include="$(MSbuildProjectDirectory)\App\bin\Release\App.exe"/>
</ItemGroup>
I think it doesn't work using the Condition attribute because Item metadatas aren't set yet during creation, so %(Extension) is empty.

Error using MSBuild tokens in PropertyGroup

I am trying to setup some properties that I use multiple times in my MSBuild script. I have the following property section:
<PropertyGroup>
<BuildDependsOn>$(BuildDependsOn); MyAfterBuild </BuildDependsOn>
<SubstitutionsFilePath>$(ProjectDir)app.config.substitutions.xml </SubstitutionsFilePath>
<AppConfig>$(TargetPath).config</AppConfig>
<HostConfig>$(TargetDir)$(TargetName).vshost.exe.config</HostConfig>
</PropertyGroup>
When I run this I get the following error:
The expression "#(TargetPath).config" cannot be used in this context. Item lists cannot be concatenated with other strings where an item list is expected. Use a semicolon to separate multiple item lists.
I don't understand this error, as the use of the $(BuildDependsOn) and $(ProjectDir) work fine. And I know the $(TargetXXX) values generate properly as when I put them directly into the Tasks section below, they work fine.
The reason for this problem is that TargetDir is defined as an item list, not a property; presumably to cater to the scenario where your outputs are distributed amongst several output directories?
I came up against this same problem and managed to work around it by using the $(OutDir) property instead of $(TargetDir).
(The OutDir property is defined in Microsoft.Common.Targets (lines 100-102) as a normalised version of the OutputPath defined in your project file.)
First try running your build with the /v:diag option, which will output a lot more information and give you a clue as to what part of the build is failing.
A clue might be in the Microsoft.Common.targets file (located in %SystemRoot%\Microsoft.NET\Framework\v2.0.50727) in the PrepareForBuild target:
<!--
These CreateProperty calls are required because TargetDir and TargetPath are defined
to contain an item list. We want that item list to be expanded so that it can be used
as a regular property value and not as an item-list-with-transform.
-->
<CreateProperty Value="$(TargetDir)">
<Output TaskParameter="Value" PropertyName="TargetDir" />
</CreateProperty>
<CreateProperty Value="$(TargetPath)">
<Output TaskParameter="Value" PropertyName="TargetPath" />
</CreateProperty>
To me this looks like a bug, you can report it at https://connect.microsoft.com/feedback/Search.aspx?SiteID=210.

How do I check if any file in an item list exist using msbuild?

I would like to run a task if any file in an item list is missing. How do I do that?
My current script has a list of "source" files #(MyComFiles) that I translate another list of "destination" files #(MyInteropLibs), using the following task:
<CombinePath BasePath="$(MyPath)\interop"
Paths="#(MyComFiles->'%(filename).%(extension)')">
<Output TaskParameter="CombinedPaths"
ItemName="MyInteropLibs" />
</CombinePath>
I want to check if any of the files in #(MyInteropLibs) is missing and run a task that will create them.
If you only need to create the missing files, and not get a list of the files that were missing you can you the touch task, which will create if the files don't exist.
<Touch Files="#(MyInteropLibs)" AlwaysCreate="True" />
If you only want to create the missing files, and avoid changing timestamps of the existing files, then batching can help
<Touch Files="%(MyInteropLibs.FullPath)" AlwaysCreate="True"
Condition=" ! Exists(%(MyInteropLibs.FullPath)) "/>
If you want a list of the files created then
<Touch Files="%(MyInteropLibs.FullPath)" AlwaysCreate="True"
Condition=" ! Exists(%(MyInteropLibs.FullPath)) ">
<Output TaskParameter="TouchedFiles" ItemName="CreatedFiles"/>
</Touch>
<Message Text="Created files = #(CreatedFiles)"/>
I am not very experienced with MSBuild so there may be better solutions than this but you could write a FilesExist task that takes the file list and passes each file to File.Exists returning true if they do exist and false otherwise and thenn react based on the result
Sorry I can't provide code to help out, my knowlege of MSBuild sytax is not strong
You can find out pretty easily using Exec.
To test if ALL of a set of files exists: The DOS FOR /D command accepts a semicolon-separated list of files - i.e. a flattened item array.
<!-- All exist -->
<Exec
Command="for /D %%i in (#(MyFiles)) do if not exist %%i exit 1"
IgnoreExitCode="true">
<Output TaskParameter="ExitCode" PropertyName="ExistExitCode"/>
</Exec>
To test if ANY of a set of files exists: The DOS DIR command accepts a semicolon-separated list of files. It sets the %ERRORLEVEL% to 0 if it finds any files in the list, nonzero if it finds none. (This is the simpler case, but it does not address the original question...)
<!-- Any exists -->
<Exec Command="dir /B #(MyFiles)" IgnoreExitCode="true">
<Output TaskParameter="ExitCode" PropertyName="DirExitCode"/>
</Exec>
Then most likely you will want to define a boolean property based on the output.
EDIT: BTW this is a code smell. Usually when you find yourself wanting to do this, it's an indication that you should set the Outputs property of the target so it will loop over the items.