我想做以下事情:
(项目是WPF的用户控制库)
- 加一堆。FX(着色器源代码)文件作为资源添加到项目中(生成操作)
- 将每个转换为。PS文件(编译的着色器)。EXE实用程序
- 使用生成的文件代替输入的文件
我一直想写一个CustomTool,不幸的是,Visual Studio从未见过该工具,正如文章中提到的那样。在这篇文章中,据说有时它没有被看到,但在我的情况下,它每次都被翻译为。
我还研究了MSBuild Transforms,但我真的不确定它是否适合该任务。
这样做的目的是包含着色器文件源代码并在构建时对其进行转换,而不是从命令行手动构建它们并每次将它们放到项目中。
你知道怎样才能做到这一点吗?欢迎任何方法
编辑
感谢@Luaan:回答
public class CompileEffectTask : Task
{
public string[] Files { get; set; }
public override bool Execute()
{
if (Files != null)
{
foreach (string file in Files)
{
if (file != null)
{
Log.LogMessage(MessageImportance.High, file);
string s = @"C:Program Files (x86)Windows Kits8.1binx86fxc.exe";
string changeExtension = Path.ChangeExtension(file, "ps");
string arguments = string.Format("/T ps_3_0 /Fo "{0}"" + " " + ""{1}"", changeExtension,
file);
Log.LogMessage(MessageImportance.High, arguments);
var process = new Process
{
StartInfo = new ProcessStartInfo(s, arguments)
};
process.Start();
process.WaitForExit();
}
}
}
return true;
}
}
MSBuild部分:
<UsingTask TaskName="CompileEffectTask" AssemblyFile="D:HLSLCompiler.dll" />
<PropertyGroup>
<BuildDependsOn>
MyCustomTarget1;
$(BuildDependsOn);
</BuildDependsOn>
</PropertyGroup>
<Target Name="MyCustomTarget1">
<Message Text="CompileEffectTask started" Importance="high" />
<Message Text="Compiling FX files ..." Importance="high" />
<CompileEffectTask Files="@(CompileEffectTask)"/>
<Message Text="Adding resulting .PS files as resources ..." Importance="high" />
<ItemGroup>
<Resource Include="***.ps" />
</ItemGroup>
</Target>
<Target Name="AfterBuild">
<CreateItem Include="***.ps">
<Output TaskParameter="Include" ItemName="DeleteAfterBuild" />
</CreateItem>
<Delete Files="@(DeleteAfterBuild)" />
</Target>
(仍然需要一些清洁,但它可以工作:D)
事实上,自定义工具确实可以工作,但它们的设置相当棘手——它们是Visual Studio的COM扩展。然而,对于您的案例,更好的解决方案是自定义生成目标或预生成事件——自定义工具(代码生成器)更适合生成代码(文本),而不是二进制文件。
因此,预构建事件是一个简单的事件。这只是在项目开始构建之前运行的一些脚本。您可以在项目属性中找到它。最简单的方法是将所有.fx
文件放在一个目录中,在预构建事件中,只需对每个文件调用fxc.exe
。
现在,构建目标更酷了。它们允许您将自己的构建操作添加到文件中,以及其他操作。所以你只需要在文件的Build action
中选择CompileEffect
,神奇的事情就发生了。
目标文件可以很简单:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<AvailableItemName Include="CompileEffect"></AvailableItemName>
</ItemGroup>
</Project>
或者,您可以直接将ItemGroup
部分放在项目文件中(否则,您可能希望包含此目标文件)。
接下来,您希望将任务设置为构建的一部分:
<PropertyGroup>
<BuildDependsOn>
MyCompileTarget;
$(BuildDependsOn);
</BuildDependsOn>
</PropertyGroup>
这基本上是说"先运行我的构建目标,然后再运行任何你想要的"。
现在,对于大楼:
<Target Name="MyCompileTarget">
<CompileEffectTask
ProjectDirectory="$(ProjectDir)"
Files="@(CompileEffect)"
RootNamespace="$(RootNamespace)">
</CompileEffectTaskTask>
</Target>
Visual Studio如何知道CompileEffectTask
是什么?
<UsingTask TaskName="MyAssembly.CompileEffectTask"
AssemblyFile="C:MyAssembly.dll"/>
然后您只需要实现编译器任务本身。
现在,如果你只想调用一个可执行文件或批处理脚本,你甚至不需要这个自定义任务,因为MSBuild中有很多内置任务(MSBuild社区任务中甚至更多)。Exec
任务应该工作:
<Target Name="MyCompileTarget">
<Exec Command="fxc.exe @(CompileEffect)" />
</Target>
你可能需要在那里写一个for
循环,我不完全确定。你可以做很多事情来定制项目构建,http://msdn.microsoft.com/en-us/library/0k6kkbsd.aspx(尤其是Task refecence
部分)是一个相当好的开端。