Pass list item to Properties when calling reusable msbuild target

坚强是说给别人听的谎言 提交于 2019-12-24 03:07:28

问题


I'm trying to create a reusable Target in msbuild, following the basic model outlined in How to invoke the same msbuild target twice?

I'm stuck trying to pass a property that I want interpreted as a list. I haven't found an example online that deals with this situation. As I understand it, the problem is that Properties is already treated as a list item, so it doesn't like having a list item passed in as well. Is there a way to get msbuild to pack and unpack the list correctly here?

Msbuild is complaining with:

error MSB4012: The expression "FilesToZip=@(Scripts)" 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.

Here's an example caller:

<Target Name="BuildMigrationZip">

   <MSBuild Projects="BuildZip.msbuild"
      Targets="BuildZip"
      Properties="FilesToZip=@(Scripts);OutputZipFile=$(MigrationPackageFilePath);OutputFolder=$(MigrationPackagePath);Flatten=true"/>

  <Message Text="Created database migration zip: $(MigrationPackageFilePath)" Importance="high"/>

</Target>

And the base target:

<Target Name="BuildZip">

  <MakeDir Directories="$(OutputFolder)"/>

  <Zip Files="@(FilesToZip)" 
  ZipFileName="$(OutputZipFile)"
  Flatten="$(Flatten)"
  ParallelCompression="false" />

</Target>

I'm basically at the point of just going back to cut and paste for these, although I want to package up a number of zips here.

UPDATE: The same issue applies to setting Inputs on the reusable target. My question up to this point addresses the raw functionality, but it would be nice to keep dependencies working. So for example:

<Target Name="BuildZip"
   Inputs="@(FilesToZip)"
   Outputs="$(OutputZipFile)">

  <MakeDir Directories="$(OutputFolder)"/>

  <Zip Files="@(FilesToZip)" 
  ZipFileName="$(OutputZipFile)"
  Flatten="$(Flatten)"
  ParallelCompression="false" />

</Target>

回答1:


They key is to pass the list around as a property. So when your Scripts list is defined as

<ItemGroup>
  <Scripts Include="A"/>
  <Scripts Include="B"/>
  <Scripts Include="C"/>
</ItemGroup>

then you first convert it into a property (which just makes semicolon seperated items, but msbuild knows how to pass this via the Properties of the MSBuild target) then pass it to the target:

<Target Name="BuildMigrationZip">
  <PropertyGroup>
    <ScriptsProperty>@(Scripts)</ScriptsProperty>
  </PropertyGroup>

  <MSBuild Projects="$(MSBuildThisFile)" Targets="BuildZip"
           Properties="FilesToZip=$(ScriptsProperty)" />
</Target>

(note I'm using $(MSBuildThisFile) here: you don't necessarily need to create seperate build files for every single target, in fact for small targets like yours it's much more convenient to put it in the same file)

Then in your destination target you turn the property into a list again:

<Target Name="BuildZip">
  <ItemGroup>
    <FilesToZipList Include="$(FilesToZip)"/>
  </ItemGroup>
  <Message Text="BuildZip: @(FilesToZipList)" />
</Target>

Output:

BuildZip: A;B;C

Update

When working with Inputs, you cannot pass @(FilesToZip) since that expands to nothing because is not a list: it's a property - which happens to be a number of semicolon-seperated strings. And as such, it is usable for Inputs you just have to expand it as the property it is i.e. $(FilesToZip):

<Target Name="BuildZip"
        Inputs="$(FilesToZip)"
        Outputs="$(OutputZipFile)">
  ...
</Target>

Output of second run:

BuildZip:
Skipping target "BuildZip" because all output files are up-to-date with respect to the input files.


来源:https://stackoverflow.com/questions/24587436/pass-list-item-to-properties-when-calling-reusable-msbuild-target

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!