我正在尝试做一些非常简单的事情,但是尽管我花了几个小时在互联网上搜索并拼命输入我能找到的每一个微小的示例片段,但我确实不能让 VS 做我想做的事。在这里感到非常沮丧!
这就是我想要的:
- 当我进行构建时,我希望 VS 找到项目中的每个
*.fubar
文件。 - 对于每个
*.fubar
文件,我希望 VS 以输入文件作为参数执行fubar.exe
。 - 我希望 VS 像往常一样编译生成的
*.cs
文件。
我该死的相信一定有可能完成这个微不足道的简单任务。我只需要弄清楚怎么做。
这就是问题所在。让我解释一下我到目前为止的研究。
看来你可以通过实现一些COM接口(interface)来写一个VS扩展。但这需要您编辑注册表 以告诉 VS 插件在哪里。显然,这是完全不能接受的;我应该不必为了运行命令行工具而重新配置操作系统!
看来 MSBuild 应该是这种 super 可配置的构建管理工具,您可以在其中定义任意一组构建步骤及其相互依赖性。在运行 fubar.exe
生成源代码的构建 C# 编译步骤之前添加一个额外的任务似乎应该是微不足道的。然而,经过几个小时的尝试,我无法显示单个 C# 文件。
一些文档讨论了特殊的构建前和构建后步骤。但是当构建步骤的数量和顺序本来应该是任意的时,需要一个特殊的钩子(Hook)似乎很愚蠢。不管怎样,我试过了,还是不行。
要清楚:使用项目文件会使 VS 显示项目属性略有不同,并且不会导致构建失败。但它也不会显示任何 C# 文件。 (至少,我在磁盘上的任何地方都找不到它们。我不知道我的工具是否真的在运行——我怀疑“没有”。)
任何人 都可以告诉我如何让这个微不足道、微不足道的事情发挥作用吗? 一定有办法!
最佳答案
我同意 T4 可能是一个更漂亮的解决方案,但下面的 MsBuild 代码有效。
您可以创建一个执行调用的自定义目标文件,我创建了一个只复制文件的文件,但调用您的可执行文件的过程应该类似。
确保将 FuBar 文件设置为 BuildAction“Fubars”。构建操作已使用“AvailableItemName”属性在目标文件中定义。
您可能需要使用几个条件和存在检查来扩展下面的脚本,以确保它在需要时运行。我叫它convert.targets
并将其放在项目目录中。
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Ensure Visual Studio puts the FuBars item in the Build Action dropdown -->
<ItemGroup>
<AvailableItemName Include="FuBars" />
</ItemGroup>
<!-- Execute action on all items matching FuBar (only if output is missing or input has changed) -->
<Target Name="GenerateCodeFubar" Inputs="@(Fubars)" Outputs="$(MSBuildProjectDirectory)/obj/$(Configuration)/Fubars/%(Fubars.Identity).g.cs" >
<MakeDir Directories="$(MSBuildProjectDirectory)/obj/$(Configuration)/Fubars/%(Fubars.RelativeDir)" />
<Exec Command="cmd /c copy "%(FuBars.FullPath)" "$(MSBuildProjectDirectory)/obj/$(Configuration)/Fubars/%(FuBars.Identity).g.cs""/>
</Target>
<!-- Pick up generated code in the Compile group. Separated from the execute action so that the previous action only runs when files have changes -->
<Target Name="IncludeCodeFubarInCompile">
<ItemGroup>
<GeneratedFubars Include="$(MSBuildProjectDirectory)/obj/$(Configuration)/Fubars/%(FuBars.Identity).g.cs"/>
</ItemGroup>
<CreateItem Include="%(GeneratedFubars.FullPath)">
<Output TaskParameter="Include" ItemName="Compile" />
</CreateItem>
</Target>
<!-- Clean up for Rebuild or Clean -->
<Target Name="DeleteCodeFubar">
<RemoveDir Directories="$(MSBuildProjectDirectory)/obj/$(Configuration)/Fubars/" />
<Delete Files="$(MSBuildProjectDirectory)/obj/$(Configuration)/fubars/**/*.g.cs" />
</Target>
<!-- Instruct MsBuild when to call target on Build-->
<PropertyGroup>
<BuildDependsOn>
GenerateCodeFubar;
IncludeCodeFubarInCompile;
$(BuildDependsOn);
</BuildDependsOn>
</PropertyGroup>
<!-- Instruct MsBuild when to call target on Clean-->
<PropertyGroup>
<CleanDependsOn>
DeleteCodeFubar;
$(CleanDependsOn);
</CleanDependsOn>
</PropertyGroup>
</Project>
将其包含在您的 .csproj
中导入最后一个目标文件后:
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- IMPORT HERE -->
<Import Project="convert.targets" />
<!-- END: IMPORT HERE -->
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
您可能需要 tell Visual Studio to turn off the Host Compiler ,因为 Visual Studio 缓存 <Compile>
的内容性能组。尽管快速测试表明可能不需要这样做。
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<!-- The first property group should not have any condition on it -->
<PropertyGroup>
<!-- Include below item in the first PropertyGroup item:
<UseHostCompilerIfAvailable>FALSE</UseHostCompilerIfAvailable>
</PropertyGroup>
关于c# - 让VisualStudio运行命令生成C#代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29147715/