I'm unable to copy subfolders and files with this code:
<ItemGroup>
<Compile Include="C:\Test\Folder1\text.txt"/>
<Compile Include="C:\Test\text1.txt"/>
</ItemGroup>
<Copy SourceFiles="#(Compile)" DestinationFiles="#(Compile->'C:\Destination\%(RecursiveDir)%(Filename)%(Extension)')" />
I get this error: Could not find a part of the path.
How to copy C:\Test\ files and subfolders to C:\Destination\ with msbuild ?
Thanks in advance for your help.
In order for the RecursiveDir metadata to be populated, you must specify a recursive wildcard (double asterisks) in your items' paths. The ** wildcard will mark the relative point at which the RecursiveDir should be applied. In your example, it sounds like you'd want to add the ** wildcard after C:\Test, so your code would need to look like the following example:
<ItemGroup>
<Compile Include="C:\Test\**\Folder1\text.txt"/>
<Compile Include="C:\Test\**\text1.txt"/>
</ItemGroup>
<Copy SourceFiles="#(Compile)" DestinationFiles="#(Compile->'C:\Destination\%(RecursiveDir)%(Filename)%(Extension)')" />
Adding the wildcard as shown above will copy the files to the following locations:
C:\Destination\text1.txt
C:\Destination\Folder1\text.txt
The same as in response above, but without additional list transformation:
<ItemGroup>
<Compile Include="C:\Test\**\Folder1\text.txt"/>
<Compile Include="C:\Test\**\text1.txt"/>
</ItemGroup>
<Copy SourceFiles="#(Compile)" DestinationFolder="C:\Destination\%(RecursiveDir)" />
Related
I am trying to add custom files to a specific NuGet package (basically I need all output files included in the NuGet package since it serves as a tool for Chocolatey).
After some searching, I found this potential fix:
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);GetToolsPackageFiles</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="GetToolsPackageFiles">
<ItemGroup>
<BuildOutputInPackage Include="$(OutputPath)\**\*.dll" />
<BuildOutputInPackage Include="$(OutputPath)\**\*.exe" />
</ItemGroup>
</Target>
Unfortunately, this won't work correctly for subdirectories, so I tried this:
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);GetToolsPackageFiles</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="GetToolsPackageFiles">
<ItemGroup>
<BuildOutputInPackage Include="$(OutputPath)\**\*.dll">
<TargetPath>$([MSBuild]::MakeRelative('$(OutputPath)', %(FullPath)))</TargetPath>
</BuildOutputInPackage>
<BuildOutputInPackage Include="$(OutputPath)\**\*.exe">
<TargetPath>$([MSBuild]::MakeRelative('$(OutputPath)', %(FullPath)))</TargetPath>
</BuildOutputInPackage>
</ItemGroup>
</Target>
According to the docs, I should be able to use %(FullPath), but I am getting this error:
error MSB4184: The expression "[MSBuild]::MakeRelative(C:\Sour
ce\RepositoryCleaner\output\Release\RepositoryCleaner\netcoreapp3.1\, '')" cannot be evaluated. Parameter "path" cannot have zero length.
[C:\Source\RepositoryCleaner\src\RepositoryCleaner\RepositoryCleaner.csproj]
Any idea why the well-known items don't seem to work in this scenario?
Got a fix by specifying the item group outside the target and then using that instead.
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);GetToolsPackageFiles</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<ItemGroup>
<ToolDllFiles Include="$(OutputPath)\**\*.dll" />
<ToolExeFiles Include="$(OutputPath)\**\*.exe" />
</ItemGroup>
<Target Name="GetToolsPackageFiles">
<ItemGroup>
<BuildOutputInPackage Include="#(ToolDllFiles)">
<TargetPath>$([MSBuild]::MakeRelative('$(OutputPath)', %(ToolDllFiles.FullPath)))</TargetPath>
</BuildOutputInPackage>
<BuildOutputInPackage Include="#(ToolExeFiles)">
<TargetPath>$([MSBuild]::MakeRelative('$(OutputPath)', %(ToolExeFiles.FullPath)))</TargetPath>
</BuildOutputInPackage>
</ItemGroup>
</Target>
I have the following MSBuild .proj file content:
<ItemGroup>
<Exclude Include="*2.*"></Exclude>
</ItemGroup>
<ItemGroup>
<!-- I have 3 files in the current directory: File1.cpp, File2.cpp and File3.cpp -->
<ModuleInclude Include="*.cpp" Exclude="#(Exclude)"></ModuleInclude>
<!-- I have 3 files in the Subfolder directory: eFile1.h, eFile2.h and eFile3.h -->
<ModuleInclude Include="Subfolder\*.h" Exclude="#(Exclude->'Subfolder\%(identity)')"></ModuleInclude>
</ItemGroup>
<Target Name="Default">
<Message Text="ModuleIncludes: %(ModuleInclude.identity)" />
<Message Text="Excluded Items: #(Exclude)" />
<Message Text="Excluded Subfolder Items: #(Exclude->'Subfolder\%(identity)')" />
</Target>
I see the following output:
ModuleIncludes: File1.cpp
ModuleIncludes: File3.cpp
ModuleIncludes: Subfolder\eFile1.h
ModuleIncludes: Subfolder\eFile2.h
ModuleIncludes: Subfolder\eFile3.h
Excluded Items: File2.cpp
Excluded Subfolder Items: Subfolder\File2.cpp
What I really need is to have the following Subfolder files included
ModuleIncludes: Subfolder\eFile1.h
ModuleIncludes: Subfolder\eFile3.h
The excluded subfolder items therefore should be:
Excluded Subfolder Items: Subfolder\eFile2.h
To be able to get such an output I would need the expression
Subfolder\*2.*
The syntax that I am using
#(Exclude->'Subfolder\%(identity)')
does not give me what I need.
What would the correct syntax be? Or is this not possible?
If you want to deal with wildcards as text, use properties instead of items:
<PropertyGroup>
<FileExcludes>*2.*</FileExcludes>
</PropertyGroup>
<ItemGroup>
<ModuleInclude Include="*.cpp" Exclude="$(FileExcludes)"></ModuleInclude>
<ModuleInclude Include="Subfolder\*.h" Exclude="Subfolder\$(FileExcludes)"></ModuleInclude>
</ItemGroup>
You can even use an exclude pattern here that will match regardless of the subfolder:
<PropertyGroup>
<FileExcludes>**\*2.*</FileExcludes>
</PropertyGroup>
<ItemGroup>
<ModuleInclude Include="*.cpp" Exclude="$(FileExcludes)"></ModuleInclude>
<ModuleInclude Include="Subfolder\*.h" Exclude="$(FileExcludes)"></ModuleInclude>
</ItemGroup>
If you really need it as a list to prepend non-local folders, use metadata items:
<PropertyGroup>
<FileExclude Include="2">
<Pattern>**\*2.*</Pattern>
</FileExclude>
</PropertyGroup>
<ItemGroup>
<ModuleInclude Include="*.cpp" Exclude="#(FileExclude)"></ModuleInclude>
<ModuleInclude Include="..\shared-folder\*.h" Exclude="#(FileExclude->'shared-folder\%(Pattern)')"></ModuleInclude>
</ItemGroup>
I want to remove folder from my deployment folder.
I'm using removedir task.
<ItemGroup>
<FolderToExcludefromDeploymentFolder Include="$(SourceDir)\Support" />
</ItemGroup>
<Target Name="BeforeBuild" BeforeTargets="Build">
<RemoveDir Condition="Exists('$(sourceDir)\Support')" Directories="#(FolderToExcludefromDeploymentFolder)" />
</Target>
In that case i get a folder in the solution tree.
In case of trying to delete the folder i get this error and the itemgroup element will automatically will be removed.
How can i fix this?
The only way I could fix this issue is to move all problematic properties to BeforeBuild target and set them as DefineConstants.
<Target Name="BeforeBuild">
<PropertyGroup>
<SourceDir>$(MSBuildProjectDirectory)..\..\..\Example</SourceDi>
<FolderToExclude>$(MSBuildProjectDirectory)..\..\..\Example\Support</FolderToExclude>
<DefineConstants>$(DefineConstants);SourceDir=$(SourceDir);FolderToExclude=$(FolderToExclude)</DefineConstants>
</PropertyGroup>
<RemoveDir Condition="Exists('$(sourceDir)\Support')" Directories="#(FolderToExclude)" />
</Target>
This solution worked for me but didn't find the reason behind this.
I'm trying to harvest different folders in my *.wixproj file. But HeatDirectory task is only harvesting last HarvestDirectory target. What I'm missing here?
Here is my code segment:
<ItemGroup>
<Compile Include="Components.wxs">
<Link>Components.wxs</Link>
</Compile>
<Compile Include="Product.wxs" />
</ItemGroup>
<ItemGroup>
<HarvestDirectory Include="$(SolutionDir)\WebApplication2\bin\$(Configuration)">
<AutogenerateGuids>true</AutogenerateGuids>
<ComponentGroupName>SimpleWebAppGroup</ComponentGroupName>
<DirectoryRefId>INSTALLFOLDER</DirectoryRefId>
<SuppressCom>true</SuppressCom>
<SuppressRegistry>true</SuppressRegistry>
<PreprocessorVariable>var.SourceDir</PreprocessorVariable>
<Visible>false</Visible>
</HarvestDirectory>
<HarvestDirectory Include="D:\testing\TTSVN\Program Files\TortoiseSVN\Common\TortoiseOverlays">
<AutogenerateGuids>true</AutogenerateGuids>
<ComponentGroupName>SVNOverLays</ComponentGroupName>
<DirectoryRefId>PROGFILES</DirectoryRefId>
<SuppressCom>true</SuppressCom>
<SuppressRegistry>true</SuppressRegistry>
<PreprocessorVariable>var.SourceDir</PreprocessorVariable>
<Visible>false</Visible>
</HarvestDirectory>
</ItemGroup>
<Import Project="$(WixTargetsPath)" />
<Target Name="BeforeBuild">
<HeatDirectory NoLogo="$(HarvestDirectoryNoLogo)"
SuppressAllWarnings="$(HarvestDirectorySuppressAllWarnings)"
SuppressSpecificWarnings="$(HarvestDirectorySuppressSpecificWarnings)"
ToolPath="$(WixToolPath)"
TreatWarningsAsErrors="$(HarvestDirectoryTreatWarningsAsErrors)" TreatSpecificWarningsAsErrors="$(HarvestDirectoryTreatSpecificWarningsAsErrors)"
VerboseOutput="$(HarvestDirectoryVerboseOutput)"
AutogenerateGuids="$(HarvestDirectoryAutogenerateGuids)"
GenerateGuidsNow="$(HarvestDirectoryGenerateGuidsNow)"
OutputFile="Components.wxs"
SuppressFragments="$(HarvestDirectorySuppressFragments)"
SuppressUniqueIds="true"
Transforms="%(HarvestDirectory.Transforms)"
Directory="#(HarvestDirectory)"
ComponentGroupName="%(HarvestDirectory.ComponentGroupName)"
DirectoryRefId="%(HarvestDirectory.DirectoryRefId)"
KeepEmptyDirectories="false"
PreprocessorVariable="%(HarvestDirectory.PreprocessorVariable)"
SuppressCom="%(HarvestDirectory.SuppressCom)"
SuppressRegistry="%(HarvestDirectory.SuppressRegistry)"
SuppressRootDirectory="$(HarvestDirectorySuppressRootDirectory)"
>
</HeatDirectory>
</Target>
If I omit HeatDirectory task, it would definitely not updating Component.wxs. I didn't find any example showing the use of HarvestDirectory with HeatDirectory task. While Wix documentation shows that HarvestDirectory target passes HarvestDirectory items to the HeatDirectory task to generate authoring from a file.
Any help would be really appreciated.
I dropped HarvestDirectory items and now using two HeatDirectory tasks, while generating two separate wxs files, while linking in Compile. This solved the problem....
I can build my project with the following command...
csc /reference:lib\Newtonsoft.Json.dll SomeSourceFile.cs
... but when I use this command...
msbuild MyProject.csproj
... with the following .csproj file my .dll reference isn't included. Any thoughts?
<PropertyGroup>
<AssemblyName>MyAssemblyName</AssemblyName>
<OutputPath>bin\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="SomeSourceFile.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>lib\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<Target Name="Build">
<MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
<Csc Sources="#(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
</Target>
You didn't get your Reference group hooked up to the Csc task. Also the references the way you specified could not be used directly inside the task. Tasks that ship with MSBuild include ResolveAssemblyReference, that is able to transform short assembly name and search hints into file paths. You can see how it is used inside c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets.
Without ResolveAssemblyReference, the simplest thing that you can do is to write it like this:
<PropertyGroup>
<AssemblyName>MyAssemblyName</AssemblyName>
<OutputPath>bin\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="SomeSourceFile.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="lib\Newtonsoft.Json.dll" />
</ItemGroup>
<Target Name="Build">
<MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
<Csc Sources="#(Compile)" References="#(Reference)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
</Target>
Notice that Reference item specifies direct path to the referenced assembly.
What you've done is to overload the default Build target typically imported via Microsoft.CSharp.targets. In the default Build target, it takes the item array #(Compile), in which your .cs source files are resident, and also the #(Reference) array, among other things, and composites the proper call to the C# compiler. You've done no such thing in your own minimal Build target, which effectivly ignores the declaration of #(Reference) and only supplies #(Compile) to the Csc task.
Try adding the References="#(References)" attribute to the Csc task.