6

Background:

I have an open source game library written in C# which is highly tuned for performance, using unsafe code, pointer arithmetic etc. I've recently ported the library to Windows Phone. Unfortunately Windows Phone does not support unsafe code at all, so I have had to litter my source code with preprocessor directives such as this:

#if WINDOWS || XBOX
public unsafe struct Foo
#elif WINDOWS_PHONE
public struct Foo
#endif

Due to the amount of these directives the codebase has become quite unreadable and difficult to maintain, so I've been exploring other options - one of which is text templates using T4.

The Question:

What I need to know before going too far down the T4 route is wether or not it is possible to get compilation symbols from within a text template? I have looked into template parameters but it didn't seem very easy to modify them from the outside world. Ideally what I'd like to see is something a bit like this:

<# if (Host.CompilationSymbols.Contains("WINDOWS_PHONE") { #>
public struct Foo
<# { #>

If anyone could shed some light on wether or not this is possible I'd be grateful!

MattDavey
  • 8,897
  • 3
  • 31
  • 54
  • Curious - assuming you remove the unsafe declaration attribute using T4, what do you do with the actual unsafe code? – tgiphil Jan 02 '11 at 04:14
  • Obviously it's not the *only* place where the template would alter things - other examples would be Foo* bar changes to ref Foo bar, or bar->foo() changes to bar.foo() – MattDavey Feb 01 '11 at 13:45

1 Answers1

6

Matt, They're not available, no as the compilation for your project and the compilation for the templates are completely isolated as of VS2010.

However I have a (somewhat clumsy) workaround for you.

If you include a stub file that contains your template directive, then you can set compiler options with the appropriate symbol for compilation.

e.g. a simple stub containing the following, named Define.t4:

<#@ template compilerOptions="/d:XBOX" debug="false" hostspecific="false" language="C#" #>

Put this in a subdirectory named XBOX and put a similar one in a directory named PHONE

<#@ template compilerOptions="/d:PHONE" debug="false" hostspecific="false" language="C#" #>

Note the compiler symbol definitions.

Now set an environment variable to be either XBOX or PHONE - let's say ARCHITECTURE

Now instead of the template directive in your templates, include the Define.t4 file and you will be able to use regular C#/VB condition syntax. Don't forget to put the #if on their own line. Here's an example:

<#@ include file="$(ProjectDir)%ARCHITECTURE%\Define.t4" #>
<#@ output extension=".txt" #>
<#
#if XBOX #>
public unsafe struct Foo
<#
#else #>
public struct Foo
<#
#endif #>

Hope this gets you moving.

GarethJ
  • 6,496
  • 32
  • 42
  • Thank you Gareth! I had a workaround where I was parsing the .csproj file from within my template and looking for an node, but your way is much cleaner :) – MattDavey Dec 31 '10 at 14:00
  • 1
    NOTE: that currently there seems to be a bug in Microsoft.VisualStudio.TextTemplating 15.0 meaning that pre-processor symbols defined in "compilerOptions" in the template directive are *not* passed to the compiler via the TextTemplating CompilerBridge see: [https://developercommunity.visualstudio.com/content/problem/173946/t4-template-compileroptionsdefine-doesnt-work-in-v.html](https://developercommunity.visualstudio.com/content/problem/173946/t4-template-compileroptionsdefine-doesnt-work-in-v.html) – James Close Jun 15 '18 at 13:35