获取Visual Studio以在每个构建上运行T4模板

时间:2009-10-29 21:14:04

标签: visual-studio tfs msbuild t4

如何获得T4模板以在每次构建时生成其输出?就像现在一样,它只在我对模板进行更改时才重新生成它。

我发现了类似的其他问题:

T4 transformation and build order in Visual Studio(未答复)

How to get t4 files to build in visual studio?(答案不够详细[虽然仍然很复杂]甚至没有完全意义)

必须有一种更简单的方法来做到这一点!

24 个答案:

答案 0 :(得分:68)

我同意GarethJ - 在VS2010中,在每个构建上重新生成tt模板要容易得多。 Oleg Sych的博客描述了如何做到这一点。简而言之:

  1. 安装Visual Studio SDK
  2. 安装Visual Studio 2010 Modeling and Visualization SDK
  3. 在文本编辑器项目文件中打开并且 添加到文件末尾但在</Project>
  4. 之前

    就是这样。打开你的项目。在每个构建中,将重新处理所有* .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" />
    

答案 1 :(得分:67)

我使用了JoelFan的回答。我更喜欢它,因为每次向项目添加新的.tt文件时都不必记住修改预构建事件。

  • 将TextTransform.exe添加到%PATH%
  • 创建了一个名为transform_all.bat的批处理文件(见下文)
  • 创建预构建事件“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

答案 2 :(得分:28)

有一个很好的NuGet包可以做到这一点:

PM> Install-Package Clarius.TransformOnBuild

有关套餐的详情可以是found here

答案 3 :(得分:19)

我使用了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模板的项目的Project Properties。进入构建活动并添加以下预构建事件命令行

$(SolutionDir)..\..\tools\RunTemplate.bat $(ProjectDir)MyTemplate $(OutDir)

MyTemplate 替换为.tt文件的文件名(即MyTemplate.tt),不带.tt扩展名。这将导致在构建项目之前扩展模板以生成MyTemplate.cs。然后实际的构建将编译MyTemplate.cs

答案 4 :(得分:14)

最近发现了这个很棒的VS插件,Chirpy

它不仅可以在构建中生成T4,而且它允许基于T4的方法缩小javascript,CSS,甚至允许您为CSS使用LESS语法!

答案 5 :(得分:12)

可能最简单的方法是安装名为AutoT4的Visual Studio扩展。

它可以自动运行构建中的所有T4模板。

答案 6 :(得分:12)

预构建可以简化为一行:

forfiles /p "$(ProjectDir)." /m "*.tt" /s /c "cmd /c echo Transforming @path && \"%CommonProgramFiles(x86)%\Microsoft Shared\TextTemplating\1.2\TextTransform.exe\" @file"

这会转换项目中的所有.tt个文件,并将它们列为构建输出。

如果您不想要构建输出,那么您必须解决一些"interesting behaviour"

forfiles /p "$(ProjectDir)." /m "*.tt" /s /c "cmd /c @\"%CommonProgramFiles(x86)%\Microsoft Shared\TextTemplating\1.2\TextTransform.exe\" @file"

当然,如果您愿意,可以将其拉出到您传递项目目录路径的批处理文件中。

NB 该路径可能需要进行一些调整。上面的路径是VS 2008在我的机器上安装它的地方;但您可能会发现TextTemplatingTextTransform.exe之间的版本号不同。

答案 7 :(得分:9)

退房 C:\ Program Files(x86)\ Common Files \ Microsoft Shared \ TextTemplating 那里有一个命令行转换exe。或者用自定义主机编写MSBuild任务并自行进行转换。

答案 8 :(得分:7)

扩展Seth RenoJoelFan's答案,我想出了这个。使用此解决方案,每次向项目添加新的.tt文件时,都不需要记住修改预构建事件。

实施程序

  • 创建名为transform_all.bat的批处理文件(见下文)
  • 使用要构建的.tt为每个项目创建预构建事件transform_all.bat "$(ProjectDir)" $(ProjectExt)

<强> 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


注意

  1. 文本转换假定T4模板中的代码与项目类型的语言相同。如果这种情况不适用于您,则必须将$(ProjectExt)参数替换为您希望代码生成的文件的扩展名。

  2. .TT个文件必须位于项目目录中,否则他们将无法构建。您可以通过指定一个不同的路径作为第一个参数(即。用包含TT文件的路径替换"$(ProjectDir)")来在项目目录之外构建TT文件。)

  3. 还要记住设置transform_all.bat批处理文件的正确路径 例如,我将它放在我的解决方案目录中,因此预构建事件如下"$(SolutionDir)transform_all.bat" "$(ProjectDir)" $(ProjectExt)

答案 9 :(得分:6)

如果您使用的是Visual Studio 2010,则可以使用Visual Studio Modeling and Visualization SDK: http://code.msdn.microsoft.com/vsvmsdk

这包含在构建时执行T4模板的msbuild任务。

请查看Oleg的博客以获得更多解释: http://www.olegsych.com/2010/04/understanding-t4-msbuild-integration

答案 10 :(得分:4)

嘿 我的脚本也可以解析输出扩展名

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文件都将自动转换。

答案 11 :(得分:3)

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;

答案 12 :(得分:2)

关于此问题的另一篇好文章:Code Generation in a Build Process

2012建模与可视化SDK下载链接:

https://www.microsoft.com/en-us/download/details.aspx?id=30680

答案 13 :(得分:2)

请参阅mhutch的回答https://stackoverflow.com/a/1395377/9587

恕我直言,这是最好的构建服务器和开发环境友好选项。

答案 14 :(得分:1)

这是我的解决方案 - 类似于接受的答案。 我们的源代码控制存在问题。目标.cs文件是只读的,T4失败。 下面是代码,它在临时文件夹中运行T4,比较目标文件,并仅在相同更改的情况下复制它。它不能解决read.only文件的问题,但至少它不会经常发生:

Transform.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)"

答案 15 :(得分:1)

您只需将此命令添加到项目的预构建事件中:

if $(ConfigurationName) == Debug $(MSBuildToolsPath)\Msbuild.exe  /p:CustomBeforeMicrosoftCSharpTargets="$(ProgramFiles)\MSBuild\Microsoft\VisualStudio\v11.0\TextTemplating\Microsoft.TextTemplating.targets"  $(ProjectPath) /t:TransformAll 

检查configuration = debug,确保在TFS构建服务器上进行构建时,不要在发布模式下重新生成代码。

答案 16 :(得分:1)

在visual studio 2013中,右键单击T4模板并将build属性的转换设置为true。

答案 17 :(得分:1)

以下是我如何添加它。 Link。基本上建立在一个伟大的博客之上(blogs.clariusconsulting.net/kzu/how-to-transform-t4-templates-on-build-without-installing-a-visual-studio-sdk/不能发布更多的2链接:()我想出了这个.targets文件,用于visual studio proj文件。

当您在.tt中使用其他dll-s时,它非常有用,并且您希望在dll-s发生变化时更改结果。

工作原理:

  1. 创建tt,将程序集名称=“$(SolutionDir)path \”添加到\ other \ project \ output \ foo.dll并设置转换并将结果设置为预期
  2. 从.tt

  3. 中删除程序集引用
  4. 在proj文件中使用此代码在build:

    上设置转换
    <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, '&amp;quot; -r &amp;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="&quot;$(_TransformExe)&quot; &quot;@(_TextTransform)&quot; -r &quot;$(IncludeForTransform)&quot;" 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"

  5. 唯一要做的就是添加以下内容的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>会隐藏解决方案视图

  6. 中的这些项目

    所以现在你应该能够在构建和更改dll-s时生成代码。

    您可以删除自定义工具(来自Visual Studio中的属性),这样VS就不会每次都尝试转换并失败。因为我们删除了第2步中的程序集引用

答案 18 :(得分:1)

感谢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" />之类的内容,以便即使尚未生成文件也可以编译这些文件。

RemoveInclude技巧仅在第一次生成时才需要,或者您可以像这样使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中,您可能希望看到以下内容:

enter image description here

代替此:

enter image description here

因此在您的项目文件中添加以下内容:

  <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(包括从单个模板生成多个文件)。

答案 19 :(得分:0)

Some guy为此构建了nuget package

附注:我从TextTemplate.exe和该软件包中获得编译错误(因为该软件包调用TextTemplate.exe),但不是来自Visual Studio。显然这种行为是不一样的;抬头。

编辑:This最终成了我的问题。

答案 20 :(得分:0)

T4Executer针对VS2019执行此操作。您可以指定要在构建时忽略的模板,并且在构建后有一个执行选项。

答案 21 :(得分:0)

您只需安装NuGet软件包: Clarius.TransformOnBuild

然后,每次单击重建项目(或解决方案),您的 .tt 文件将运行

答案 22 :(得分:0)

在Visual Studio 2017中(可能也是下一版本),您应该在Pre-build事件中添加它:

"$(DevEnvDir)TextTransform.exe" -out "$(ProjectDir)YourTemplate.cs" "$(ProjectDir)YourTemplate.tt"

p.s。如果模板不在根项目目录中,请更改其路径。

答案 23 :(得分:0)

这是仅使用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)”之类的宏。