Cannot reference dependency assemblies in T4 template when using TransformOnBuild
Asked Answered
C

4

2

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:

  1. The template needs to load our existing assembly and use objects from a namespace in that assembly.
  2. The transformation needs to run on every build on every development machine and build server without any additional installations.
  3. (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?)

Coble answered 4/5, 2011 at 16:49 Comment(1)
Are you about to assist with this? I'm curious about step 2. It looks like you were using #4672564 T4Toolbox as well, but I don't see that above.Rhianna
G
2

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.

Ghost answered 4/5, 2011 at 19:11 Comment(3)
Thanks! That was really helpful. I used a custom task to set an environment variable and used that in my templates. However, now I get the dreaded "Unable to copy file '...dll'" problem, despite the fact that I'm using VS 2010 SP1. Any idea why that could be happening?Coble
We'd need a more detailed repro to have much chance of helping - it's generally meant to work cleanly from the build.Ghost
for the unable to copy dll - think you need to use volatileassembly reference, not assembly. For the custom task - would you mind sharing how you did that as we have the same issue with targetdir, and a simple p[rebuild that set %envvar% = $targetdir would be perfectContrapose
H
1

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.

Hindsight answered 19/12, 2013 at 18:8 Comment(0)
W
0

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.

Wrought answered 7/5, 2011 at 0:45 Comment(0)
W
0

If you want to reference dependency assemblies within a T4 script using macros and have text templating succeed during build-time, then you have to use project properties.

Within your project:

  <Import Project="$(ProgramFiles)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\VisualStudio\v15.0\TextTemplating\Microsoft.TextTemplating.targets" />
  <PropertyGroup>
    <T4ProjectDir>$(ProjectDir)</T4ProjectDir>
  </PropertyGroup>
  <ItemGroup>
   <T4ParameterValues Include="T4ProjectDir">
    <Value>$(T4ProjectDir)</Value>
    <Visible>false</Visible>
   </T4ParameterValues>
  </ItemGroup>

Where the path to your text templating environment may be different.

Then use $(T4ProjectDir) as you would use any other macro in your text template.

Or you could also simply refer to existing properties:

  <ItemGroup>
   <T4ParameterValues Include="ProjectDir">
    <Value>$(ProjectDir)</Value>
    <Visible>false</Visible>
   </T4ParameterValues>
  </ItemGroup>
Wriggle answered 18/6, 2020 at 14:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.