问题
We're trying to use T4 with Visual Studio 2010 (SP1) to build scripts for another language that are based upon some of our existing C# classes. I'm hoping for the following:
- The template needs to load our existing assembly and use objects from a namespace in that assembly.
- The transformation needs to run on every build on every development machine and build server without any additional installations.
- (1) and (2) need to work together.
(1) was fairly straightforward:
<#@ assembly name="$(TargetDir)RequiredProject.dll" #>
<#@ import namespace="RequiredProject.RequiredNamespace" #>
Using the $(TargetDir)
macro allowed me to reference the dll with a fully qualified UNC path (per the instructions found here).
(2) is a bit roundabout, but I think I've got it solved: I installed the required text transformation SDKs on a different machine and copied the required .targets and .dlls into a folder in my solution and then updated my .csproj file to reference the local .targets file.
(3) is where I run into problems. It seems like the <TransformOnBuild>true</TransformOnBuild>
property doesn't play nicely when a referenced assembly needs to be built prior to the transformation. Everytime I enable transform on build with referenced assemblies, I get the following error:
Compiling transformation: Metadata file '$(TargetDir)RequiredProject.dll' could not be found.
However, I'm using the same assembly instruction that I was using in (1) to reference the assembly. In fact, going to the .tt template directly and saving it still produces the expected output -- it just doesn't work during the "build" step. Am I doing something wrong, or is there a way to ensure that the template transformations occur after the assemblies they depend on are built? (Or, more simply, that template transformations occur last?)
回答1:
Unfortunately, the msbuild T4 host doesn't yet support embedded macro or msbuild variables in assembly names.
However, it does support Windows environment variables "%foo%", so although it means some machine-level setup, you can get something that works across in-IDE and build time transforms.
回答2:
My understanding is that Visual Studio 2013 will finally solve this problem, but that doesn't do me much good as I'm still on Visual Studio 2012. After a lot of effort I finally ran across a solution.
In the project that has the template you wish to run, add the following as a pre-build step on the Build Events tab of the project properties page.
set textTransformPath="%CommonProgramFiles(x86)%\Microsoft Shared\TextTemplating\$(VisualStudioVersion)\TextTransform.exe"
if %textTransformPath%=="\Microsoft Shared\TextTemplating\$(VisualStudioVersion)\TextTransform.exe" set textTransformPath="%CommonProgramFiles%\Microsoft Shared\TextTemplating\$(VisualStudioVersion)\TextTransform.exe"
set ProjectDir=$(ProjectDir)
%textTransformPath% "%ProjectDir%StringGenerator.tt"
The first two lines take care of the differences between locating TextTransform.exe
on 32-bit and 64-bit systems. The third line is the key. I need the path to the project location inside my template, so I set a local environment variable equal to the value of the build's $(ProjectDir)
property. Inside my template, just use the following:
var projectDir = Environment.GetEnvironmentVariable("ProjectDir");
This has solved my issue.
回答3:
I created a seperate solution that contained my needed referenced assemblies. The I had my buildscript build the reference solution first, then transform the templates, then build the solution containing the generated code.
来源:https://stackoverflow.com/questions/5886938/cannot-reference-dependency-assemblies-in-t4-template-when-using-transformonbuil