让 Visual Studio 在每次构建时运行 T4 模板

Posted

技术标签:

【中文标题】让 Visual Studio 在每次构建时运行 T4 模板【英文标题】:Get Visual Studio to run a T4 Template on every build 【发布时间】:2010-12-11 10:06:06 【问题描述】:

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

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

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

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

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

【问题讨论】:

虽然我个人很想听到这个问题的答案,但您的具体情况是什么?通常,模板的输出应该只是输入的函数,因此生成更改就可以了。 我的模板使用反射来检查其他程序集,这些程序集自上次构建以来可能已更改。 这个想法怎么样:***.com/questions/1649649/… 我的模板只有一个用途,记录构建日期时间。 见docs.microsoft.com/en-us/visualstudio/modeling/… 【参考方案1】:

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

    安装Visual Studio SDK 安装Visual Studio 2010 Modeling and Visualization SDK 在文本编辑器项目文件中打开并 添加到文件末尾但在 </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" />

【讨论】:

这里是 Oleg Sych 博客文章的链接:olegsych.com/2010/04/understanding-t4-msbuild-integration 这是一个非常好的解决方案。但是,有没有一种方法可以在不需要安装 SDK 的情况下使其工作?我一直试图通过复制 .targets 文件和相关程序集来使其工作,但没有成功。 Chirpy 似乎无需下载任何 SDK 即可工作......但是,您仍然需要下载和配置 Chirpy。我仍在尝试寻找一种适用于 VS2010 默认安装的解决方案,并且可以通过源存储库获得,因此开发人员只需检查存储库即可使其工作。所有这些其他解决方案都需要开发人员过多的关注。 如果您使用 x64 版本的 MSBuild 构建项目 - 您将收到此错误:'MSB4019: The imported project "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\TextTemplating\v10 .0\Microsoft.TextTemplating.targets" 未找到。错误。解决方法 - 在项目文件中将 $(MSBuildExtensionsPath) 变量替换为 $(MSBuildExtensionsPath32)。 此外,您不需要修补 .csproj 文件。从命令行调用类似msbuild mySolution.sln /p:CustomAfterMicrosoftCommonTargets="C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\TextTemplating\Microsoft.TextTemplating.targets" /p:TransformOnBuild=true /p:TransformOutOfDateOnly=false【参考方案2】:

我使用 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

【讨论】:

不错的解决方案。我更喜欢将 TextTransform.exe ("%CommonProgramFiles%\Microsoft Shared\TextTemplating\1.2\texttransform.exe") 的完整路径放在批处理文件中,而不是将其添加到 %PATH% 更好的变量是 %COMMONPROGRAMFILES(x86)% 而不是 %COMMONPROGRAMFILES%,因为它也可以在 64 位系统上工作。 所以完整路径将是%COMMONPROGRAMFILES(x86)%\microsoft shared\TextTemplating\11.0\TextTransform.exe。用双引号括起来。 @piers7:我更新了代码以自动检测运行脚本的操作系统的“位数”。我还包括了northben 的评论以跳过obj 目录并实现了Adam Nofsinger 关于不修改%PATH% 环境变量的偏好。 恕我直言,必须提供TextTransform.exe 的路径很糟糕。您已经可以在 Visual Studio 中右键单击“运行自定义工具”,因此它已经有了工具的路径。当我从 Visual Studio 上下文构建时,为什么我必须再次完成提供它的工作?【参考方案3】:

有一个很棒的NuGet package 就是这样做的:

PM> Install-Package Clarius.TransformOnBuild

关于包的详细信息可以是found here,GitHub repo 是here。

【讨论】:

有一个“非官方”分支:nuget.org/packages/Clarius.TransformOnBuild-unofficial 支持 content 构建操作 这是一个不错的扩展,但它在命令行模式下运行 TextTransform.exe,所以 hostspecific="true" 函数将不起作用 @JenishRabadiya 将此行添加到模板顶部:&lt;#@ template language="C#" #&gt; 该软件包似乎已更新以支持 hostspecific="true" 和其他问题(8 天前) 内容构建操作现在正在使用最新版本。【参考方案4】:

我使用了 MarkGr 的答案并开发了这个解决方案。首先,在主解决方案文件夹上方的单独 tools 文件夹中创建一个名为 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 是模板中 Assembly 指令引用的任何 DLL 的路径。

接下来,进入包含 T4 模板的项目的项目属性。进入 Build Events 并添加以下 Pre-build event 命令行

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

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

【讨论】:

虽然我还是有问题:***.com/questions/1669893/… 不要忘记 $(SolutionDir)..\..\tools\RunTemplate.bat 周围的引号【参考方案5】:

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

它不仅在构建时生成 T4,而且允许基于 T4 的方法来缩小 javascript、CSS,甚至允许您对 CSS 使用 LESS 语法!

【讨论】:

【参考方案6】:

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

它在构建时自动运行所有 T4 模板。

【讨论】:

同意!可配置,可与 VS 2015 配合使用。它甚至支持使用 EnvDTE 程序集(用于获取构建配置),并非所有方法都这样做。唯一的缺点是所有团队成员都必须安装扩展。【参考方案7】:

预编译可以简化为一行:

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之间的版本号是不同的。

【讨论】:

@SprintStar,如果您有 VS 2012,那么可能有更好的方法。其他答案谈论的是 VS 2010 已经存在的更好方法。 这是最好的方法,因为我不需要安装任何东西。 看到没有 1.2 但有 12.0 所以将其更改为该版本但出现此错误:System.Exception: T4MVC can only execute through the Visual Studio host 只需更新文件夹路径以使用 14.0 而不是 1.2 就可以了。 我认为这是最好的解决方案(只是如上所述更改 14.0)【参考方案8】:

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

【讨论】:

哦,虽然您可以在 2010 年执行“devenv /Command TextTransformation.TransformAllTemplates /Command File.Exit MySolution.sln”之类的操作,但它偶尔会在构建服务器上中断。最好的办法是使用自定义主机编写 MSBuild 任务。 对于桌面构建,只需创建一个执行 TransformAllTemplates 的宏,然后进行构建。【参考方案9】:

感谢 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>

如果您将模板转换为不同的编程语言,您应该添加类似 &lt;Compile Remove="**\*.vb" /&gt;&lt;Compile Include="**\*.vb" /&gt; 的内容,以便编译这些文件,即使您还没有生成文件。

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 中,您可能希望看到如下内容:

而不是这个:

所以在你的项目文件中添加这样的内容:

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

【讨论】:

我真的很喜欢您的方法,但我无法在 .Net Core 3.0+ 上运行您的项目。显然 DotNetCliToolReference 已退休,我不确定如何使用新方法运行您的解决方案。见github.com/dotnet/announcements/issues/107 @MelLeet 我会在不久的将来尝试研究它,如果你愿意,你可以在我的存储库中创建一个关于它的问题。【参考方案10】:

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

实施程序

创建一个名为 transform_all.bat 的批处理文件(见下文) 为每个项目创建一个预构建事件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)

【讨论】:

我正在尝试使用这种方法,但我不断收到错误消息,'\Common 在这个时候是意外的。'在我的输出中。它发生在这一行: for /f "delims=" %%d in (t4list.txt) do... 知道我错过了什么吗? @MichaelLewis:我已经多次浏览批处理文件,但没有发现可能导致错误的原因。请尝试the method proposed by Seth Reno 看看它是否会产生相同的错误。同时,您能否将您的t4list.txt 文件发布到PasteBin,以便我尝试查看您的错误是否来自那里? 我在同样的问题上尝试了 Seth 的方法('\Common 在这个时候是出乎意料的')。 t4list.txt 文件因公司限制无法发布,但只有一行,路径中没有出现\Common。 @MichaelLewis:不幸的是,如果您的错误发生在for /f "delims=" %%d in (t4list.txt) do ( 并且公司限制阻止您发布您的t4list.txt 文件,那么恐怕我无能为力帮助您。我真的很想帮助解决这个问题,但看起来这将是不可能的,因为我没有数据可以继续。祝您解决问题好运,成功后请记得发布您的解决方案。 tt 包含 (this.Host as IServiceProvider).GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE; 时是否可以这样做?不幸的是,当我从 Visual Studio 之外运行 tt 时,我得到 null 引用异常【参考方案11】:

如果您使用的是 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

【讨论】:

【参考方案12】:

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

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

【讨论】:

【参考方案13】:

Dynamo.AutoTT 将满足您的需求。您可以将其配置为通过正则表达式监视文件或在构建时生成。它还允许您指定要触发的 T4 模板。

您可以从这里下载:https://github.com/MartinF/Dynamo.AutoTT

只需构建它,将 dll 和 AddIn 文件复制到

C:\Users\Documents\Visual Studio 2012\Addins\

你走了。

如果你想让它在 VS2012 中运行,你需要修改 Dynamo.AutoTT.AddIn 文件并在 AddIn 文件中将版本设置为 11.0;

【讨论】:

【参考方案14】:

你只需要将这个命令添加到项目的预构建事件中:

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

检查配置 = 调试,确保不会在发布模式下重新生成代码,例如在 TFS 构建服务器上进行构建时。

【讨论】:

很好,但如果 T4MVC 不仅是项目中的 tt 并且我们不想运行所有内容,那么转换所有内容可能会很危险...... 我在 v11.0 文件夹中没有 TextTemplating。你从哪里得到的?【参考方案15】:

在 Visual Studio 2017(可能还有下一个版本)中,您应该在 Pre-build 事件中添加这个:

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

附言如果模板不在根项目目录中,请更改模板的路径。

【讨论】:

【参考方案16】:

这是我的解决方案 - 类似于接受的答案。 我们的源代码控制存在问题。目标 .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)"

【讨论】:

【参考方案17】:

在 Visual Studio 2013 中,右键单击 T4 模板并将构建属性上的转换设置为 true。

【讨论】:

我无法在右键菜单中找到此选项,但根据 MSDN,可以通过在 VS 2012 和 2013 中编辑项目文件来实现,请参阅 msdn.microsoft.com/en-us/library/ee847423.aspx 或 @987654322 @了解详情 这似乎是一个仅随有形 T4 工具一起提供的选项,而不是 Visual Studio 中的默认选项。 是的,这仅在 T4 Toolbox 的 pro 版本中。【参考方案18】:

这就是我的做法。 Link。基本上建立在一个伟大的博客之上( 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,添加程序集 name="$(SolutionDir)path\to\other\project\output\foo.dll 并将转换和结果设置为符合预期

    从 .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, '&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>
    

    &lt;_TextTransform Include="$(ProjectDir)**\*.tt" /&gt;this 创建项目和子目录中所有 tt 文件的列表

    &lt;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>
    

    这里&lt;InProject&gt;False&lt;/InProject&gt;从解决方案视图中隐藏了这些项目

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

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

【讨论】:

请将解决方案本身添加到您的答案中以提供更多上下文。链接不是问题的解决方案,当其他用户稍后返回此问题时,链接可能已失效。【参考方案19】:

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

【讨论】:

【参考方案20】:

您只需安装 NuGet 包:Clarius.TransformOnBuild

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

【讨论】:

【参考方案21】:

这是一个仅使用 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)”等宏在模板中可用。

【讨论】:

如果您的解决方案路径中有空格,则需要在上面的 $(SolutionPath) 周围加上引号。否则,我喜欢这个解决方案,因为它只是一个构建事件并且没有其他依赖项。缺点是您必须提前指定要转换的每个文件。谢谢!【参考方案22】:

Some guy 为此构建了一个nuget package。

旁注:我从 TextTemplate.exe 和该包(因为该包调用 TextTemplate.exe)都收到编译错误,但不是来自 Visual Studio。所以显然行为是不一样的;抬头。

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

【讨论】:

以上是关于让 Visual Studio 在每次构建时运行 T4 模板的主要内容,如果未能解决你的问题,请参考以下文章

使用docker-compose和https时如何让Visual Studio启动正确的URL

编译时自动增加exe版本,Visual Studio

如何在不是Visual Studio c中的依赖项的构建中包含项目#

每次我尝试运行性能分析时,Visual Studio 都会崩溃

如何将 Qt 的 windeployqt 集成为 Visual Studio 构建工作流的一部分?

Visual Studio 2010:在单个文件上运行自定义构建工具时指定工作目录