如何获得 T4 模板以在每次构建时生成其输出?就像现在一样,它只会在我对模板进行更改时重新生成它。
我发现了其他类似的问题:
Visual Studio 中的 T4 转换和构建顺序(未回答)
如何获取 t4 文件以在 Visual Studio 中构建?(答案不够详细[虽然仍然很复杂],甚至没有完全意义)
必须有一个更简单的方法来做到这一点!
如何获得 T4 模板以在每次构建时生成其输出?就像现在一样,它只会在我对模板进行更改时重新生成它。
我发现了其他类似的问题:
Visual Studio 中的 T4 转换和构建顺序(未回答)
如何获取 t4 文件以在 Visual Studio 中构建?(答案不够详细[虽然仍然很复杂],甚至没有完全意义)
必须有一个更简单的方法来做到这一点!
我同意 GarethJ - 在 VS2010 中,在每个构建中重新生成 tt 模板要容易得多。Oleg Sych 的博客描述了如何做到这一点。简而言之:
</Project>
而已。打开你的项目。在每次构建时,所有 *.tt 模板都将被重新处理
<!-- This line could already present in file. If it is so just skip it -->
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- process *.tt templates on each build -->
<PropertyGroup>
<TransformOnBuild>true</TransformOnBuild>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TextTemplating\v10.0\Microsoft.TextTemplating.targets" />
我用 JoelFan 的回答来提出这个问题。我更喜欢它,因为您不必记住每次向项目添加新的 .tt 文件时都修改预构建事件。
%PATH%
transform_all ..\..
”transform_all.bat
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
:: set the working dir (default to current dir)
set wdir=%cd%
if not (%1)==() set wdir=%1
:: set the file extension (default to vb)
set extension=vb
if not (%2)==() set extension=%2
echo executing transform_all from %wdir%
:: create a list of all the T4 templates in the working dir
dir %wdir%\*.tt /b /s > t4list.txt
echo the following T4 templates will be transformed:
type t4list.txt
:: transform all the templates
for /f %%d in (t4list.txt) do (
set file_name=%%d
set file_name=!file_name:~0,-3!.%extension%
echo: \--^> !file_name!
TextTransform.exe -out !file_name! %%d
)
echo transformation complete
我使用了 MarkGr 的答案并开发了这个解决方案。首先,在主解决方案文件夹上方的单独工具文件夹中创建一个名为RunTemplate.bat的批处理文件。批处理文件只有一行:
"%CommonProgramFiles%\Microsoft Shared\TextTemplating\1.2\texttransform.exe" -out %1.cs -P %2 -P "%ProgramFiles%\Reference Assemblies\Microsoft\Framework\v3.5" %1.tt
此批处理文件采用 2 个参数... %1是不带 .tt 扩展名的 .tt 文件的路径。 %2是模板中汇编指令引用的任何 DLL 的路径。
接下来,进入包含 T4 模板的项目的项目属性。进入构建事件并添加以下预构建事件命令行:
$(SolutionDir)..\..\tools\RunTemplate.bat $(ProjectDir)MyTemplate $(OutDir)
将MyTemplate替换为不带 .tt 扩展名的 .tt 文件(即 MyTemplate.tt)的文件名。这将产生在构建项目之前扩展模板以生成 MyTemplate.cs 的结果。然后实际构建将编译 MyTemplate.cs
最近发现了这个很棒的 VS 插件,Chirpy。
它不仅在构建时生成 T4,而且允许基于 T4 的方法来缩小 javascript、CSS,甚至允许您对 CSS 使用 LESS 语法!
可能最简单的方法是安装一个名为AutoT4的 Visual Studio 扩展。
它在构建时自动运行所有 T4 模板。
预构建可以简化为一行:
forfiles /p "$(ProjectDir)." /m "*.tt" /s /c "cmd /c echo Transforming @path && \"%CommonProgramFiles(x86)%\Microsoft Shared\TextTemplating\1.2\TextTransform.exe\" @file"
这会转换.tt
项目中的所有文件并将它们列出到构建输出中。
如果您不想要构建输出,那么您必须解决一些“有趣的行为”:
forfiles /p "$(ProjectDir)." /m "*.tt" /s /c "cmd /c @\"%CommonProgramFiles(x86)%\Microsoft Shared\TextTemplating\1.2\TextTransform.exe\" @file"
当然,如果您愿意,您可以将其提取到一个批处理文件中,您可以将项目目录路径传递给该批处理文件。
注意路径可能需要一些调整。上面的路径是 VS 2008 在我的机器上安装它的位置;但你可能会发现TextTemplating
和之间的版本号TextTransform.exe
不同。
查看 C:\Program Files (x86)\Common Files\Microsoft Shared\TextTemplating 那里有一个命令行转换 exe。或者,使用自定义主机编写 MSBuild 任务并自己进行转换。
感谢GitHub.com/Mono/T4,目前您可以通过将以下内容添加到.csproj
文件中来为 .NET Core 和 Visual Studio 构建执行此操作:
<ItemGroup>
<DotNetCliToolReference Include="dotnet-t4-project-tool" Version="2.0.5" />
<TextTemplate Include="**\*.tt" />
</ItemGroup>
<Target Name="TextTemplateTransform" BeforeTargets="BeforeBuild">
<ItemGroup>
<Compile Remove="**\*.cs" />
</ItemGroup>
<Exec WorkingDirectory="$(ProjectDir)" Command="dotnet t4 %(TextTemplate.Identity)" />
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
</Target>
如果您将模板转换为不同的编程语言,您应该添加类似的内容<Compile Remove="**\*.vb" />
,<Compile Include="**\*.vb" />
以便编译这些文件,即使您还没有生成文件。
Remove
并且Include
仅在第一次生成时需要技巧,或者您可以像这样使 XML 更短:
<ItemGroup>
<DotNetCliToolReference Include="dotnet-t4-project-tool" Version="2.0.5" />
<TextTemplate Include="**\*.tt" />
</ItemGroup>
<Target Name="TextTemplateTransform" BeforeTargets="BeforeBuild">
<Exec WorkingDirectory="$(ProjectDir)" Command="dotnet t4 %(TextTemplate.Identity)" />
</Target>
并且只需运行两次构建(第一次)。如果您已经生成了提交到存储库的文件,那么这两个示例的重建都不会出现问题。
在 Visual Studio 中,您可能希望看到如下内容:
而不是这个:
因此,将这样的内容添加到您的项目文件中:
<ItemGroup>
<Compile Update="UInt16Class.cs">
<DependentUpon>UInt16Class.tt</DependentUpon>
</Compile>
<Compile Update="UInt32Class.cs">
<DependentUpon>UInt32Class.tt</DependentUpon>
</Compile>
<Compile Update="UInt64Class.cs">
<DependentUpon>UInt64Class.tt</DependentUpon>
</Compile>
<Compile Update="UInt8Class.cs">
<DependentUpon>UInt8Class.tt</DependentUpon>
</Compile>
</ItemGroup>
此处的完整示例:GitHub.com/Konard/T4GenericsExample(包括从单个模板生成多个文件)。
扩展Seth Reno和JoelFan 的答案,我想出了这个。使用此解决方案,您无需记住每次将新的 .tt 文件添加到项目时都修改预构建事件。
transform_all.bat "$(ProjectDir)" $(ProjectExt)
使用要构建的 .tt 为每个项目创建预构建事件transform_all.bat
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
:: set the correct path to the the app
if not defined ProgramFiles(x86). (
echo 32-bit OS detected
set ttPath=%CommonProgramFiles%\Microsoft Shared\TextTemplating\1.2\
) else (
echo 64-bit OS detected
set ttPath=%CommonProgramFiles(x86)%\Microsoft Shared\TextTemplating\1.2\
)
:: set the working dir (default to current dir)
if not (%1)==() pushd %~dp1
:: set the file extension (default to vb)
set ext=%2
if /i %ext:~1%==vbproj (
set ext=vb
) else if /i %ext:~1%==csproj (
set ext=cs
) else if /i [%ext%]==[] (
set ext=vb
)
:: create a list of all the T4 templates in the working dir
echo Running TextTransform from %cd%
dir *.tt /b /s | findstr /vi obj > t4list.txt
:: transform all the templates
set blank=.
for /f "delims=" %%d in (t4list.txt) do (
set file_name=%%d
set file_name=!file_name:~0,-3!.%ext%
echo: \--^> !!file_name:%cd%=%blank%!
"%ttPath%TextTransform.exe" -out "!file_name!" "%%d"
)
:: delete T4 list and return to previous directory
del t4list.txt
popd
echo T4 transformation complete
笔记
文本转换假定 T4 模板中的代码与您的项目类型使用相同的语言。如果这种情况不适用于您,那么您必须将$(ProjectExt)
参数替换为您希望代码生成的文件的扩展名。
.TT
文件必须在项目目录中,否则它们将无法构建。您可以通过指定不同的路径作为第一个参数(即替换"$(ProjectDir)"
为包含 TT 文件的路径)在项目目录之外构建 TT 文件。
还要记住为transform_all.bat
批处理文件设置正确的路径。
例如,我将它放在我的解决方案目录中,因此预构建事件如下"$(SolutionDir)transform_all.bat" "$(ProjectDir)" $(ProjectExt)
如果您使用的是 Visual Studio 2010,则可以使用 Visual Studio 建模和可视化 SDK: http ://code.msdn.microsoft.com/vsvmsdk
这包含用于在构建时执行 T4 模板的 msbuild 任务。
查看 Oleg 的博客以获得更多解释: http ://www.olegsych.com/2010/04/understanding-t4-msbuild-integration
嘿,我的脚本也可以解析输出扩展
for /r %1 %%f in (*.tt) do (
for /f "tokens=3,4 delims==, " %%a in (%%f) do (
if %%~a==extension "%CommonProgramFiles%\Microsoft Shared\TextTemplating\1.2\texttransform.exe" -out %%~pnf.%%~b -P %%~pf -P "%ProgramFiles%\Reference Assemblies\Microsoft\Framework\v3.5" %%f
)
)
echo Exit Code = %ERRORLEVEL%
只需创建transform_all.bat $(SolutionDir)
预构建事件,您的解决方案中的所有 *.tt 文件都会自动转换。
Dynamo.AutoTT 将满足您的需求。您可以将其配置为通过正则表达式监视文件或在构建时生成。它还允许您指定要触发的 T4 模板。
你可以从这里下载:https ://github.com/MartinF/Dynamo.AutoTT
只需构建它,将 dll 和 AddIn 文件复制到
C:\Users\Documents\Visual Studio 2012\Addins\
你走了。
如果你想让它在 VS2012 中运行,你需要修改 Dynamo.AutoTT.AddIn 文件并将 AddIn 文件中的 Version 设置为 11.0;
您只需将此命令添加到项目的预构建事件中:
if $(ConfigurationName) == Debug $(MSBuildToolsPath)\Msbuild.exe /p:CustomBeforeMicrosoftCSharpTargets="$(ProgramFiles)\MSBuild\Microsoft\VisualStudio\v11.0\TextTemplating\Microsoft.TextTemplating.targets" $(ProjectPath) /t:TransformAll
例如,当您在 TFS 构建服务器上进行构建时,对 configuration = debug 的检查确保您不会在发布模式下重新生成代码。
在 Visual Studio 2017(也可能是下一个版本)中,您应该在 Pre-build 事件中添加它:
"$(DevEnvDir)TextTransform.exe" -out "$(ProjectDir)YourTemplate.cs" "$(ProjectDir)YourTemplate.tt"
ps 如果模板不在根项目目录中,请更改模板的路径。
这是我的解决方案 - 类似于接受的答案。我们的源代码控制存在问题。目标 .cs 文件是只读的,并且 T4 失败。这是在临时文件夹中运行 T4 的代码,比较目标文件,并仅在相同更改的情况下复制它。它不能解决 read.only 文件的问题,但至少它不会经常发生:
变换.bat
ECHO Transforming T4 templates
SET CurrentDirBackup=%CD%
CD %1
ECHO %1
FOR /r %%f IN (*.tt) DO call :Transform %%f
CD %CurrentDirBackup%
ECHO T4 templates transformed
goto End
:Transform
set ttFile=%1
set csFile=%1
ECHO Transforming %ttFile%:
SET csFile=%ttFile:~0,-2%cs
For %%A in ("%ttFile%") do Set tempTT=%TEMP%\%%~nxA
For %%A in ("%csFile%") do Set tempCS=%TEMP%\%%~nxA
copy "%ttFile%" "%tempTT%
"%COMMONPROGRAMFILES(x86)%\microsoft shared\TextTemplating\11.0\TextTransform.exe" "%tempTT%"
fc %tempCS% %csFile% > nul
if errorlevel 1 (
:: You can try to insert you check-out command here.
"%COMMONPROGRAMFILES(x86)%\microsoft shared\TextTemplating\11.0\TextTransform.exe" "%ttFile%"
) ELSE (
ECHO no change in %csFile%
)
del %tempTT%
del %tempCS%
goto :eof
:End
您可以尝试在一行中添加您的签出命令(:: 您可以尝试....)
在您的项目中将此设置为预构建操作:
Path-To-Transform.bat "$(ProjectDir)"
在 Visual Studio 2013 中,右键单击 T4 模板并将构建属性上的转换设置为 true。
您只需安装 NuGet 包:Clarius.TransformOnBuild
然后,每次单击重建项目(或解决方案)时,您的.tt文件都会运行
这是我如何解决的。链接。基本上建立在一个伟大的博客之上( blogs.clariusconsulting.net/kzu/how-to-transform-t4-templates-on-build-without-installing-a-visual-studio-sdk/ can't post more that 2链接:()我想出了这个.targets文件用于 Visual Studio proj 文件。
当您在 .tt 中使用其他 dll-s 并且您希望结果随着 dll-s 的变化而变化时,它很有用。
这个怎么运作:
从 .tt 中删除程序集引用
在 proj 文件中,使用此代码在构建时设置转换:
<PropertyGroup>
<!-- Initial default value -->
<_TransformExe>$(CommonProgramFiles)\Microsoft Shared\TextTemplating\10.0\TextTransform.exe</_TransformExe>
<!-- If explicit VS version, override default -->
<_TransformExe Condition="'$(VisualStudioVersion)' != ''">$(CommonProgramFiles)\Microsoft Shared\TextTemplating\$(VisualStudioVersion)\TextTransform.exe</_TransformExe>
<!-- Cascading probing if file not found -->
<_TransformExe Condition="!Exists('$(_TransformExe)')">$(CommonProgramFiles)\Microsoft Shared\TextTemplating\10.0\TextTransform.exe</_TransformExe>
<_TransformExe Condition="!Exists('$(_TransformExe)')">$(CommonProgramFiles)\Microsoft Shared\TextTemplating\11.0\TextTransform.exe</_TransformExe>
<_TransformExe Condition="!Exists('$(_TransformExe)')">$(CommonProgramFiles)\Microsoft Shared\TextTemplating\12.0\TextTransform.exe</_TransformExe>
<!-- Future proof 'til VS2013+2 -->
<_TransformExe Condition="!Exists('$(_TransformExe)')">$(CommonProgramFiles)\Microsoft Shared\TextTemplating\13.0\TextTransform.exe</_TransformExe>
<_TransformExe Condition="!Exists('$(_TransformExe)')">$(CommonProgramFiles)\Microsoft Shared\TextTemplating\14.0\TextTransform.exe</_TransformExe>
<_TransformExe Condition="!Exists('$(_TransformExe)')">$(CommonProgramFiles)\Microsoft Shared\TextTemplating\15.0\TextTransform.exe</_TransformExe>
<IncludeForTransform>@(DllsToInclude, '&quot; -r &quot;')</IncludeForTransform>
</PropertyGroup>
第一部分找到 TextTransform.exe
$(IncludeForTransform)
将等于,c:\path\to\dll\foo.dll' -r c:\path\to\dll\bar.dll
因为这是在命令行上为 TextTransform 添加引用的方式
<Target Name="TransformOnBuild" BeforeTargets="BeforeBuild">
<!--<Message Text="$(IncludeForTransform)" />-->
<Error Text="Failed to find TextTransform.exe tool at '$(_TransformExe)." Condition="!Exists('$(_TransformExe)')" />
<ItemGroup>
<_TextTransform Include="$(ProjectDir)**\*.tt" />
</ItemGroup>
<!-- Perform task batching for each file -->
<Exec Command=""$(_TransformExe)" "@(_TextTransform)" -r "$(IncludeForTransform)"" Condition="'%(Identity)' != ''" />
</Target>
<_TextTransform Include="$(ProjectDir)**\*.tt" />
这将创建项目和子目录中所有 tt 文件的列表
<Exec Command="...
为每个找到的 .tt 文件生成一行,如下所示"C:\path\to\Transform.exe" "c:\path\to\my\proj\TransformFile.tt" -r"c:\path\to\foo.dll" -r "c:\path\to\bar.dll"
剩下要做的就是将路径添加到其中的 dll 中:
<ItemGroup>
<DllsToInclude Include="$(ProjectDir)path\to\foo.dll">
<InProject>False</InProject>
</DllsToInclude>
<DllsToInclude Include="$(ProjectDir)path\to\bar.dll">
<InProject>False</InProject>
</DllsToInclude>
</ItemGroup>
这里<InProject>False</InProject>
从解决方案视图中隐藏了这些项目
所以现在您应该能够在构建和更改 dll-s 时生成代码。
您可以删除自定义工具(从 Visual Studio 内部的属性中),这样 VS 就不会每次都尝试转换和失败。因为我们在步骤 2 中删除了程序集引用
T4Executer为 VS2019 执行此操作。您可以指定要在构建时忽略的模板,并且有一个构建后执行选项。
这是仅使用 Microsoft 工具和标准路径的预构建事件。在 vs2019/netcore3.1 中测试过。
将“AppDbContext.tt”替换为您的项目相对文件路径:
"$(MSBuildBinPath)\msbuild" $(SolutionPath) /t:$(ProjectName):Transform /p:TransformFile="AppDbContext.tt" /p:CustomAfterMicrosoftCommonTargets="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TextTemplating\Microsoft.TextTemplating.targets"
Microsoft 还提供了一个指南,通过在项目文件中使用T4ParameterValues使模板中的“$(SolutionDirectory)”等宏可用。