如何创建仅在必要时 运行 的 MSBuild 目标
How to create a MSBuild Target that will only run if necessary
我一直在尝试使用 MSBuild 创建自定义目标。我目前正在尝试添加对使用 JAWS 脚本编译器编译文件的支持。这是我目前所拥有的。
Scripts.props
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DEVDOCS_DIR>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\..\..\..\DevDocs'))</DEVDOCS_DIR>
<BUILTIN_MASTER>$(DEVDOCS_DIR)\jsd\enu\builtin_master.jsd</BUILTIN_MASTER>
<TOOLBOX_DIR>$(DEVDOCS_DIR)\Toolbox</TOOLBOX_DIR>
<JAWS_VER>17.0</JAWS_VER>
<!-- If perl.exe is not in your path, set the following variable to the full path and file name of perl.exe.
Optionally you could set the PERL_EXE environment variable. -->
<PERL_EXE Condition="'$(PERL_EXE)'==''">perl.exe</PERL_EXE>
<!-- If scompile.exe is not in your path, set the following variable to the full path and file name of scompile.exe.
Optionally you could set the SCOMPILE_EXE environment variable. -->
<SCOMPILE_EXE Condition="'$(SCOMPILE_EXE)'==''">scompile.exe</SCOMPILE_EXE>
</PropertyGroup>
</Project>
Scripts.targets
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="GenerateBuiltinJSD">
<Exec Command=""$(PERL_EXE)" compilejsd.pl -v Jaws/$(JAWS_VER) -o "$(MSBuildProjectDirectory)\builtin.jsd" "$(BUILTIN_MASTER)"" WorkingDirectory="$(TOOLBOX_DIR)" />
</Target>
<Target Name="CompileScripts">
<Exec Command=""$(SCOMPILE_EXE)" /d "%(ScriptSourceFiles.FullPath)"" Outputs="%(ScriptSourceFiles.RootDir)%(ScriptSourceFiles.Directory)%(ScriptSourceFiles.Filename).jsb" WorkingDirectory="$(MSBuildProjectDirectory)" />
</Target>
<Target Name="Clean">
<ItemGroup>
<JSBFiles Include="$(MSBuildProjectDirectory)\*.jsb" />
</ItemGroup>
<Delete Files="@(JSBFiles)" />
</Target>
<Target Name="Build">
<CallTarget Targets="GenerateBuiltinJSD;CompileScripts" />
</Target>
</Project>
Scripts.vcxproj
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ScriptSourceFiles Include="Default.jss" />
</ItemGroup>
<ItemGroup>
<ScriptMessageFiles Include="Default.jsm" />
</ItemGroup>
<ItemGroup>
<ScriptHeaderFiles Include="HJConst.jsh" />
</ItemGroup>
<ItemGroup>
<ScriptDocumentationFiles Include="default.jsd" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B2C4363D-D228-425D-AB04-38997EA229C0}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="Scripts.props" />
</ImportGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(MSBuildProjectDirectory)\Scripts.targets" />
</Project>
这在一定程度上有效。问题是,当我进行构建时,它会重建所有脚本文件,即使相关的源文件没有更改。
我的问题是如何修改它以便仅在必要时构建每个文件?
您询问的功能称为 Incremental Build,希望 MSBuild 实用程序支持它。如果没有更改源文件,您所要做的就是为您计划跳过的目标指定输入和输出。
To specify inputs and outputs for a target: Use the Inputs and Outputs attributes of the Target element. For example:
<Target Name="Build"
Inputs="@(CSFile)"
Outputs="hello.exe">
MSBuild can compare the timestamps of the input files with the timestamps of the output files and determine whether to skip, build, or partially rebuild a target.
要成功完成任务,您必须正确生成目标的 Inputs 和 Outputs。这可以通过使用特殊目标来实现,它将填充所需的项目,或者您可以显式使用转换:
<Target Name="CompileScripts"
Inputs="@(ScriptSourceFiles)"
Outputs="@(ScriptSourceFiles->'%(RootDir)%(Directory)%(FileName).jsb')">
<Exec Command=""$(SCOMPILE_EXE)" /d "%(ScriptSourceFiles.FullPath)"" Outputs="%(ScriptSourceFiles.RootDir)%(ScriptSourceFiles.Directory)%(ScriptSourceFiles.Filename).jsb" WorkingDirectory="$(MSBuildProjectDirectory)" />
</Target>
(另请注意,您应该使用 $(OutDir)
属性 而不是引用 %(RootDir)
项目元数据,因为它更直接,但您应该确保此 属性指定并在执行目标时存在)。
我一直在尝试使用 MSBuild 创建自定义目标。我目前正在尝试添加对使用 JAWS 脚本编译器编译文件的支持。这是我目前所拥有的。
Scripts.props
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DEVDOCS_DIR>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\..\..\..\DevDocs'))</DEVDOCS_DIR>
<BUILTIN_MASTER>$(DEVDOCS_DIR)\jsd\enu\builtin_master.jsd</BUILTIN_MASTER>
<TOOLBOX_DIR>$(DEVDOCS_DIR)\Toolbox</TOOLBOX_DIR>
<JAWS_VER>17.0</JAWS_VER>
<!-- If perl.exe is not in your path, set the following variable to the full path and file name of perl.exe.
Optionally you could set the PERL_EXE environment variable. -->
<PERL_EXE Condition="'$(PERL_EXE)'==''">perl.exe</PERL_EXE>
<!-- If scompile.exe is not in your path, set the following variable to the full path and file name of scompile.exe.
Optionally you could set the SCOMPILE_EXE environment variable. -->
<SCOMPILE_EXE Condition="'$(SCOMPILE_EXE)'==''">scompile.exe</SCOMPILE_EXE>
</PropertyGroup>
</Project>
Scripts.targets
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="GenerateBuiltinJSD">
<Exec Command=""$(PERL_EXE)" compilejsd.pl -v Jaws/$(JAWS_VER) -o "$(MSBuildProjectDirectory)\builtin.jsd" "$(BUILTIN_MASTER)"" WorkingDirectory="$(TOOLBOX_DIR)" />
</Target>
<Target Name="CompileScripts">
<Exec Command=""$(SCOMPILE_EXE)" /d "%(ScriptSourceFiles.FullPath)"" Outputs="%(ScriptSourceFiles.RootDir)%(ScriptSourceFiles.Directory)%(ScriptSourceFiles.Filename).jsb" WorkingDirectory="$(MSBuildProjectDirectory)" />
</Target>
<Target Name="Clean">
<ItemGroup>
<JSBFiles Include="$(MSBuildProjectDirectory)\*.jsb" />
</ItemGroup>
<Delete Files="@(JSBFiles)" />
</Target>
<Target Name="Build">
<CallTarget Targets="GenerateBuiltinJSD;CompileScripts" />
</Target>
</Project>
Scripts.vcxproj
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ScriptSourceFiles Include="Default.jss" />
</ItemGroup>
<ItemGroup>
<ScriptMessageFiles Include="Default.jsm" />
</ItemGroup>
<ItemGroup>
<ScriptHeaderFiles Include="HJConst.jsh" />
</ItemGroup>
<ItemGroup>
<ScriptDocumentationFiles Include="default.jsd" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B2C4363D-D228-425D-AB04-38997EA229C0}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="Scripts.props" />
</ImportGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(MSBuildProjectDirectory)\Scripts.targets" />
</Project>
这在一定程度上有效。问题是,当我进行构建时,它会重建所有脚本文件,即使相关的源文件没有更改。
我的问题是如何修改它以便仅在必要时构建每个文件?
您询问的功能称为 Incremental Build,希望 MSBuild 实用程序支持它。如果没有更改源文件,您所要做的就是为您计划跳过的目标指定输入和输出。
To specify inputs and outputs for a target: Use the Inputs and Outputs attributes of the Target element. For example:
<Target Name="Build"
Inputs="@(CSFile)"
Outputs="hello.exe">
MSBuild can compare the timestamps of the input files with the timestamps of the output files and determine whether to skip, build, or partially rebuild a target.
要成功完成任务,您必须正确生成目标的 Inputs 和 Outputs。这可以通过使用特殊目标来实现,它将填充所需的项目,或者您可以显式使用转换:
<Target Name="CompileScripts"
Inputs="@(ScriptSourceFiles)"
Outputs="@(ScriptSourceFiles->'%(RootDir)%(Directory)%(FileName).jsb')">
<Exec Command=""$(SCOMPILE_EXE)" /d "%(ScriptSourceFiles.FullPath)"" Outputs="%(ScriptSourceFiles.RootDir)%(ScriptSourceFiles.Directory)%(ScriptSourceFiles.Filename).jsb" WorkingDirectory="$(MSBuildProjectDirectory)" />
</Target>
(另请注意,您应该使用 $(OutDir)
属性 而不是引用 %(RootDir)
项目元数据,因为它更直接,但您应该确保此 属性指定并在执行目标时存在)。