MSBuild:如何在构建时创建和使用任务来转换内容项目? [英] MSBuild: How do I create and use a Task to convert Content items at build time?

查看:14
本文介绍了MSBuild:如何在构建时创建和使用任务来转换内容项目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类似这样的 Silverlight 3 项目:

<Content Include="Contentimage1.png"></内容></项目组>

基本上,我已将一个 PNG 文件添加到我的项目中,并将其构建操作设置为内容".这很好用.

现在我想做的是能够将不同格式的图像添加到我的项目中,并让它们在构建时转换为 PNG - 所以最终结果就像我首先将一个 PNG 图像(作为内容)添加到项目中一样.

换句话说 - 我希望图像以 PNG 格式显示在我的 XAP 包中.

理想情况下,我希望这样做可以与 Visual Web Developer 2008 Express 一起使用(因此我可以通过将图像文件拖到 IDE 中并可能更改它们的构建操作来将图像文件添加到我的项目中),并且没有进行任何系统范围的更改.

我想转换的特定格式是 XCF - 我已经有了 .NET 代码来转换为 PNG.我假设我必须创建一个 MSBuild 任务.

我真的没有多少 MSBuild 经验,我想知道如何将这样的东西组合在一起.

<小时>

基于我对 MSBuild 工作原理的粗略理解,我认为我需要知道:

  • 如何根据项目的文件扩展名,通过(重新)从 @(Content)(或其他)集合中移动它们来创建项目集合?
    • 或者:创建一个我可以在 Visual Web Developer 2008 Express 中使用的自定义构建操作
  • 如何接收Task中输入项的路径?
  • 在何处(.NET 或 MSBuild?)以及如何指定由 Task 生成的输出文件的位置?
  • 如何确保在输入文件发生更改时重建文件?
  • 在哪里(可能是BeforeBuild?)以及如何将转换后的项目重新注入@(Content)?(或者我应该使用其他一些集合吗?)
    • 或:让他们进入 XAP 的其他方式?

如果这看起来是一种合理的做事方式,或者我遗漏了什么?

解决方案

为了实现您的总体目标,您提出了特定的子问题,我想您想了解 MSBuild,而不是死记硬背整体任务(由于您的赏金,这是您将从许多其他人那里得到的),因此我将回答您的个人问题,然后尝试将它们全部汇总成一个解决方案.

假设您想将所有 .jpg 文件转换为 .png.

根据扩展名从内容项列表中创建子列表:

<Sublist Include="@(Content)" Condition=" '%(Extension)' == '.jpg' "/></项目组>

<块引用>

接收任务中物品的路径.

两种方式 - 取决于您的任务可以接受的输入.这种方式就像对子列表中的每个项目进行foreach",我倾向于将它与 Exec 任务一起使用:

<块引用>

指定输出路径还取决于 .exe 或您所在的任务以及输出路径对特定任务的意义:

它是一个目录,还是只是一个具有不同扩展名的文件名.但我假设您想输出名称相同但扩展名不同的文件:

<Exec Command="convert.exe &quot;%(Sublist.FullPath)" &quot;%(Sublist.RootDir)%(Sublist.Directory)%(Sublist.Filename).png""/>

<块引用>

如果 jpg 更改(或被清理),如何重建 png.

嗯,这是使用包含目标元素的 Inputs 和 Outputs 属性,在其中执行我们的转换命令.输入指定源文件是什么,输出指定目标将产生什么.然后 MSBuild 将输入的日期时间与输出的日期时间进行比较,如果它们已过期,则将重建输出

  • 输入表示我们要使用内容"项组
  • Condition 属性确保我们只处理以 .jpg 扩展名结尾的内容项
  • 输出属性表示我们正在处理的输入中,我们将生成具有相似路径和文件名但以 .png 扩展名结尾的文件

最后,您正确地发现您需要将生成的 .png 文件重新注入到 @Content 项目组中 - 嗯,这很简单,您只需将它们包含到内容项目中即可.回想一下子列表包含 .jpg 文件 - 我们想要这些文件,但以 .png 结尾.一旦生成了 png,我们也不希望内容项组中的 .jpg 文件

<Content Include="@(Sublist -> '%(RootDir)%(Directory)%(Filename).png')"/>

总而言之,我相信您的目标看起来像这样:

<Content Remove="@(Sublist)"/><Content Include="@(Sublist -> '%(RootDir)%(Directory)%(Filename).png')"/></目标>

顺便说一下,ImageMagik 有一个命令行工具,可以将 jpg 转换为 png...

I have a Silverlight 3 project with something like this:

<ItemGroup>
  <Content Include="Contentimage1.png">
  </Content>
</ItemGroup>

Basically I've added a PNG file to my project and set its build action to "Content". This works nicely.

Now what I'd like to do is be able to add images in a different format to my project, and have them converted to PNG at build time - so that the end result is as if I had added a PNG image to the project (as Content) in the first place.

In other words - I want the image to appear, in PNG format, in my XAP package.

Ideally I would like to do this in such a way that it will work with Visual Web Developer 2008 Express (so I can add image files to my project by dragging them into the IDE and maybe changing their build action), and without making any system-wide changes.

The specific format I want to convert is XCF - I already have the .NET code to do the conversion to PNG. I am assuming that I must create a MSBuild Task.

I don't really have much MSBuild experience, and I'd like to know how to put such a thing together.


Based on my rough understanding of how MSBuild works, I think that I need to know:

  • How to create a collection of items by (re)moving them from the @(Content) (or some other) collection, based on their file extension?
    • OR: Create a custom Build Action I can use in Visual Web Developer 2008 Express
  • How to recieve the path of input items in a Task?
  • Where (.NET or MSBuild?) and How to specify the location of output files generated by a Task?
  • How to ensure that a file is rebuilt if its input file changes?
  • Where (probably BeforeBuild?) and How to reinject the converted items into @(Content)? (Or should I use some other collection?)
    • OR: Some other way of getting them into the XAP?

And if this seems like a reasonable way to do things or if I've missed anything?

解决方案

You have asked specific sub-questions with a view to achieving your overall goal, I presume you want to learn about MSBuild, rather than get a rote answer to your overall task (which is what you are gonna get from many other people due to your bounty), so I will answer your individual questions and then attempt to roll them all up into a solution.

So let's say you want to convert all .jpg files to .png.

Create a sub-list from the content item list based on extension:

<ItemGroup>
    <Sublist Include="@(Content)" Condition=" '%(Extension)' == '.jpg' " />
</ItemGroup>

Receive the path of the item in a task.

Two ways - depends on the input that your task can accept. This way is like a "foreach" over each item in Sublist, and I would tend to use it with an Exec task:

<Exec Command="convert.exe /Input:%(Sublist.FullPath)" />

Specifying an output path also depends on the .exe or the task that you are and what an output path means to a particular task:

is it a directory, or just a filename with a different extension. But I'll assume you want to output files with the same name, but a different extension:

<Exec Command="convert.exe &quot;%(Sublist.FullPath)&quot;  &quot;%(Sublist.RootDir)%(Sublist.Directory)%(Sublist.Filename).png&quot;" />    

How to rebuild the png if the jpg changes (or is cleaned).

Well, this is using the Inputs and Outputs attribute of the containing target element where our convert command is executed. Inputs specifies what the source files are, and outputs specifies what the target will produce. MSBuild then compares the datetime of the Inputs with the datetime of the output and if they are out of date, then the outputs get rebuilt

<Target Name="ConvertJpg"  
        Inputs="@(Content)"
        Outputs="@(Content -> '%(RootDir)%(Directory)%(Filename).png' )"
        Condition=" '%(Extension)' == '.jpg' "

  • Inputs says that we want to use the "Content" itemgroup
  • The Condition attribute ensures that we are only working with Content items that end in the .jpg extension
  • The Outputs attribute says that of the inputs that we are working with, we'll be generating files that have similar path and filename, but end with the .png extension

Lastly, you correctly have spotted that you need to re-inject the generated .png files back into the @Content item group - well, that's easy, you just Include them into the Content item. Recall that Sublist contains .jpg files - we want those files but with a .png ending. We also do NOT want the .jpg files in the Content item group once a png has been generated

<Content Remove="@(Sublist)" />
<Content Include="@(Sublist -> '%(RootDir)%(Directory)%(Filename).png' )" />

So summing up, your target would looks something like this I believe:

<Target Name="ConvertJpg"  
        Inputs="@(Content)"
        Outputs="@(Content -> '%(RootDir)%(Directory)%(Filename).png' )"
        Condition=" '%(Extension)' == '.jpg' "
    <ItemGroup>
        <Sublist Include="@(Content)" Condition=" '%(Extension)' == '.jpg' " />
    </ItemGroup>

    <Exec Command="convert.exe /Input:%(Sublist.FullPath) Output=%(Sublist.RootDir)%(Sublist.Directory)%(Sublist.Filename).png" />

    <Content Remove="@(Sublist)" />
    <Content Include="@(Sublist -> '%(RootDir)%(Directory)%(Filename).png' )" />
</Target>

By the way, ImageMagik has a command line tool that will convert jpg to png...

这篇关于MSBuild:如何在构建时创建和使用任务来转换内容项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆