Get Visual Studio to run a T4 Template on every bu

2018-12-31 10:29发布

How do I get a T4 template to generate its output on every build? As it is now, it only regenerates it when I make a change to the template.

I have found other questions similar to this:

T4 transformation and build order in Visual Studio (unanswered)

How to get t4 files to build in visual studio? (answers are not detailed enough [while still being plenty complicated] and don't even make total sense)

There has got to be a simpler way to do this!

19条回答
唯独是你
2楼-- · 2018-12-31 11:04

Dynamo.AutoTT will do what you need. You can configure it to watch files via a regex or generate on build. It also allows you to specify which T4 templates you want it to trigger.

You can download it from here : https://github.com/MartinF/Dynamo.AutoTT

Just build it, copy the dll and AddIn files into

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

and away you go.

If you want to get it going in VS2012 you will need to modify the a Dynamo.AutoTT.AddIn file and set the Version to 11.0 inside the AddIn file;

查看更多
公子世无双
3楼-- · 2018-12-31 11:05

Here is how I tacked it. Link. Basically building on top of a great blog( blogs.clariusconsulting.net/kzu/how-to-transform-t4-templates-on-build-without-installing-a-visual-studio-sdk/ can't post more that 2 links :( ) I came up with This .targets file for use with visual studio proj files.

It's useful when you are using other dll-s inside of your .tt and you want the result to change as the dll-s are changing.

How it works:

  1. Create the tt, add the assembly name="$(SolutionDir)path\to\other\project\output\foo.dll and set up the transformation and result to be as expected
  2. Remove the assembly references from .tt

  3. Inside the proj file use this code to set up transform on 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>
    
    • First part Locates TextTransform.exe

    • $(IncludeForTransform) will be equal to c:\path\to\dll\foo.dll' -r c:\path\to\dll\bar.dll because that's the way to add references for the TextTransform on the command line

       <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" />this creates a list of all tt files inside the project and subdirectories

    • <Exec Command="... produces a line for each of the found .tt files that looks like "C:\path\to\Transform.exe" "c:\path\to\my\proj\TransformFile.tt" -r"c:\path\to\foo.dll" -r "c:\path\to\bar.dll"

  4. The only thing left to do is add the paths to the dlls inside of:

        <ItemGroup>
          <DllsToInclude Include="$(ProjectDir)path\to\foo.dll">
            <InProject>False</InProject>
          </DllsToInclude>
          <DllsToInclude Include="$(ProjectDir)path\to\bar.dll">
            <InProject>False</InProject>
          </DllsToInclude>
        </ItemGroup>
    

    Here <InProject>False</InProject> hides these items from the Solution View

So now you should be able to generate your code on build and on change of dll-s.

You can remove the custom tool (from properties inside of Visual Studio) so the VS does not try to transform and fail miserably every time. Because we removed the assembly references in step 2

查看更多
骚的不知所云
4楼-- · 2018-12-31 11:05

Some guy built a nuget package for this.

Side note: I get compile errors from both TextTemplate.exe and that package (because that package calls TextTemplate.exe) but not from Visual Studio. So apparently the behavior is not the same; heads up.

EDIT: This ended up being my problem.

查看更多
残风、尘缘若梦
5楼-- · 2018-12-31 11:06

Recently found this great VS plugin, Chirpy.

Not only does it generate your T4 on a build, but it allows T4-based approach to minification of javascript, CSS, and even lets you use LESS syntax for your CSS!

查看更多
流年柔荑漫光年
6楼-- · 2018-12-31 11:08

Here is my solution - similar to the accepted answer. We had a problem with our source control. The target .cs files are read-only and the T4 was failing. Here is the code, that runs T4 in temp folder, compares target files, and copies it only in case of same change. It does not fix the problem with read.only files, but at least it does not occur very often:

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

You can try to add your check-out command on a line (:: You can try ....)

In your project set this as a prebuild action:

Path-To-Transform.bat "$(ProjectDir)"
查看更多
像晚风撩人
7楼-- · 2018-12-31 11:08

I agree with GarethJ - in VS2010 it is much easier to regenerate tt templates on each build. Oleg Sych's blog describes how to do it. In short:

  1. Install Visual Studio SDK
  2. Install Visual Studio 2010 Modeling and Visualization SDK
  3. Open in text editor project file and add to the end of file but before </Project>

That's it. Open your project. On each build all *.tt templates will be reprocessed

<!-- 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" />
查看更多
登录 后发表回答