Skip to content

Commit

Permalink
Take TFM into account in build tasks
Browse files Browse the repository at this point in the history
When preprocessing templates in VS and targeting .NET Core,
generate code that doesn't use remoting APIs.

This is a quick and dirty approach so the APIs are internal for
now. We need a more thorough overhaul of codegen amd runtime
options at some point.
  • Loading branch information
mhutch committed Oct 3, 2023
1 parent b6468f1 commit 7534ccf
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 19 deletions.
3 changes: 3 additions & 0 deletions Mono.TextTemplating.Build/Messages.resx
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,7 @@
<data name="SkippingTransformUpToDate" xml:space="preserve">
<value>Skipping transform template '{0}': output '{1}' is up to date</value>
</data>
<data name="RegeneratingAllPreprocessedTargetRuntimeChanged" xml:space="preserve">
<value>Regenerating all preprocessed templates: target runtime has changed from '{0}' to '{1}'</value>
</data>
</root>
1 change: 1 addition & 0 deletions Mono.TextTemplating.Build/T4.BuildTools.targets
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
UseLegacyPreprocessingMode="$(UseLegacyT4Preprocessing)"
IntermediateDirectory="$(_T4IntermediateTemplateOutputDir)"
TransformOutOfDateOnly="$(TransformOutOfDateOnly)"
PreprocessTargetRuntimeIdentifier="$(TargetFrameworkIdentifier)"
>
<Output TaskParameter="TransformTemplateOutput" ItemName="GeneratedTemplates" />
<Output TaskParameter="PreprocessedTemplateOutput" ItemName="PreprocessedTemplates" />
Expand Down
10 changes: 9 additions & 1 deletion Mono.TextTemplating.Build/TemplateBuildState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Mono.TextTemplating.Build
[MessagePackObject]
public class TemplateBuildState
{
public const int CurrentFormatVersion = 0;
public const int CurrentFormatVersion = 1;

[Key (0)]
public int FormatVersion { get; set; } = CurrentFormatVersion;
Expand All @@ -39,6 +39,8 @@ public class TemplateBuildState
public List<TransformTemplate> TransformTemplates { get; set; }
[Key (9)]
public List<Parameter> Parameters { get; set; }
[Key(10)]
public string PreprocessTargetRuntimeIdentifier { get; set; }

internal (List<TransformTemplate> transforms, List<PreprocessedTemplate> preprocessed) GetStaleAndNewTemplates (
TemplateBuildState previousBuildState, bool preprocessOnly, Func<string, DateTime?> getFileWriteTime, TaskLoggingHelper logger)
Expand Down Expand Up @@ -105,6 +107,7 @@ public class TemplateBuildState
{
(bool, bool) regenAll = (true, true);
(bool, bool) regenTransforms = (true, false);
(bool, bool) regenPreprocessed = (false, true);

if (lastSession == null) {
return regenAll;
Expand All @@ -115,6 +118,11 @@ public class TemplateBuildState
return regenAll;
}

if (lastSession.PreprocessTargetRuntimeIdentifier != session.PreprocessTargetRuntimeIdentifier) {
logger.LogMessageFromResources (MessageImportance.Low, nameof (Messages.RegeneratingAllPreprocessedTargetRuntimeChanged), lastSession.PreprocessTargetRuntimeIdentifier, session.PreprocessTargetRuntimeIdentifier);
return regenPreprocessed;
}

// this is probably impossible as the previous session is loaded from the intermediate directory, but let's be safe
if (lastSession.IntermediateDirectory != session.IntermediateDirectory) {
logger.LogMessageFromResources (MessageImportance.Low, nameof(Messages.RegeneratingAllIntermediateDirChanged));
Expand Down
5 changes: 4 additions & 1 deletion Mono.TextTemplating.Build/TextTransform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public TextTransform () : base (Messages.ResourceManager) { }
public bool UseLegacyPreprocessingMode { get; set; }
public bool TransformOutOfDateOnly { get; set; }

public string PreprocessTargetRuntimeIdentifier { get; set; }

[Required]
public string IntermediateDirectory { get; set; }

Expand Down Expand Up @@ -71,7 +73,8 @@ public override bool Execute ()

var buildState = new TemplateBuildState {
IntermediateDirectory = IntermediateDirectory,
DefaultNamespace = DefaultNamespace
DefaultNamespace = DefaultNamespace,
PreprocessTargetRuntimeIdentifier = PreprocessTargetRuntimeIdentifier
};

success &= AddParameters (buildState);
Expand Down
4 changes: 4 additions & 0 deletions Mono.TextTemplating.Build/TextTransformProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ public static bool Process (TaskLoggingHelper taskLog, TemplateBuildState previo
var pt = LoadTemplate (generator, inputFile, out var inputContent);
TemplateSettings settings = TemplatingEngine.GetSettings (generator, pt);
settings.CodeGenerationOptions.UseRemotingCallContext = buildState.PreprocessTargetRuntimeIdentifier == ".NETFramework";
// FIXME: make these configurable, take relative path into account
settings.Namespace = buildState.DefaultNamespace;
settings.Name = Path.GetFileNameWithoutExtension (preprocess.InputFile);
Expand Down Expand Up @@ -206,6 +208,8 @@ static MSBuildTemplateGenerator CreateGenerator (TemplateBuildState buildState)
}
}

generator.UseRelativeLinePragmas = true;

return generator;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@
using System.ComponentModel;
using System.IO;

using Mono.TextTemplating;
using Mono.TextTemplating.CodeDomBuilder;

namespace Microsoft.VisualStudio.TextTemplating
{
public sealed class ParameterDirectiveProcessor : DirectiveProcessor, IRecognizeHostSpecific
public sealed class ParameterDirectiveProcessor : DirectiveProcessor, IRecognizeHostSpecific, ISupportCodeGenerationOptions
{
CodeDomProvider provider;

Expand Down Expand Up @@ -147,12 +148,8 @@ public override void ProcessDirective (string directiveName, IDictionary<string,
var namePrimitive = Expression.Primitive (name);
var session = Expression.This.Property ("Session");

#if FEATURE_APPDOMAINS
bool hasAcquiredCheck = true;
var callContextType = TypeReference.Default ("System.Runtime.Remoting.Messaging.CallContext");
#else
bool hasAcquiredCheck = hostSpecific;
#endif
bool hasAcquiredCheck = hostSpecific || CodeGenerationOptions.UseRemotingCallContext;

var acquiredVariable = Declare.Variable<bool> ($"_{name}Acquired", Expression.False, out var acquiredVariableRef);
if (hasAcquiredCheck) {
postStatements.Add (acquiredVariable);
Expand Down Expand Up @@ -214,26 +211,31 @@ public override void ProcessDirective (string directiveName, IDictionary<string,
}));
}

#if FEATURE_APPDOMAINS
// try to acquire parameter value from call context
postStatements.Add (
Statement.If (acquiredVariableRef.IsFalse (),
Then: new CodeStatement[] {
Declare.Variable<object> (data.VariableName, callContextType.InvokeMethod ("LogicalGetData", namePrimitive), out _),
Statement.If (data.IsNotNull (),
Then: checkCastThenAssignVal)
}));
#endif
if (CodeGenerationOptions.UseRemotingCallContext) {
var callContextType = TypeReference.Default ("System.Runtime.Remoting.Messaging.CallContext");
postStatements.Add (
Statement.If (acquiredVariableRef.IsFalse (),
Then: new CodeStatement[] {
Declare.Variable<object> (data.VariableName, callContextType.InvokeMethod ("LogicalGetData", namePrimitive), out _),
Statement.If (data.IsNotNull (),
Then: checkCastThenAssignVal)
}));
}
}

void IRecognizeHostSpecific.SetProcessingRunIsHostSpecific (bool hostSpecific)
{
this.hostSpecific = hostSpecific;
}

void ISupportCodeGenerationOptions.SetCodeGenerationOptions (CodeGenerationOptions options) => CodeGenerationOptions = options;

public bool RequiresProcessingRunIsHostSpecific {
get { return false; }
}

CodeGenerationOptions CodeGenerationOptions { get; set; }
}
}

16 changes: 16 additions & 0 deletions Mono.TextTemplating/Mono.TextTemplating/CodeGenerationOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Mono.TextTemplating;

/// <summary>
/// Controls what code is generated by the template.
/// Internal for now, until we have a better idea of what the API should look like.
/// </summary>
class CodeGenerationOptions
{
/// <summary>
/// Whether to use System.Runtime.Remoting.Messaging.CallContext
/// </summary>
public bool UseRemotingCallContext { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Mono.TextTemplating;

/// <summary>
/// Implemented by directives that support code generation options.
/// Internal for now, until we have a better idea of what the API should look like.
/// </summary>
interface ISupportCodeGenerationOptions
{
void SetCodeGenerationOptions (CodeGenerationOptions options);
}
2 changes: 2 additions & 0 deletions Mono.TextTemplating/Mono.TextTemplating/TemplateSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public TemplateSettings ()
public bool InternalVisibility { get; set; }
public Type HostType { get; set; }
public string GetFullName () => string.IsNullOrEmpty (Namespace) ? Name : Namespace + "." + Name;

internal CodeGenerationOptions CodeGenerationOptions { get; } = new CodeGenerationOptions ();
}

public class CustomDirective
Expand Down
8 changes: 7 additions & 1 deletion Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,6 @@ public static TemplateSettings GetSettings (ITextTemplatingEngineHost host, Pars
var settings = new TemplateSettings ();

bool relativeLinePragmas = host.GetHostOption ("UseRelativeLinePragmas") as bool? ?? false;

foreach (Directive dt in pt.Directives) {
switch (dt.Name.ToLowerInvariant ()) {
case "template":
Expand Down Expand Up @@ -520,6 +519,9 @@ public static TemplateSettings GetSettings (ITextTemplatingEngineHost host, Pars
kv.Value.SetProcessingRunIsHostSpecific (settings.HostSpecific);
if (kv.Value is IRecognizeHostSpecific hs)
hs.SetProcessingRunIsHostSpecific (settings.HostSpecific);
if (kv.Value is ISupportCodeGenerationOptions opt) {
opt.SetCodeGenerationOptions (settings.CodeGenerationOptions);
}
}

if (settings.Name == null)
Expand Down Expand Up @@ -548,6 +550,10 @@ public static TemplateSettings GetSettings (ITextTemplatingEngineHost host, Pars

settings.RelativeLinePragmas = relativeLinePragmas;

#if FEATURE_APPDOMAINS
settings.CodeGenerationOptions.UseRemotingCallContext = true;
#endif

return settings;
}

Expand Down

0 comments on commit 7534ccf

Please sign in to comment.