diff --git a/Mono.TextTemplating.Build/Messages.resx b/Mono.TextTemplating.Build/Messages.resx index 14e8328..a7213a0 100644 --- a/Mono.TextTemplating.Build/Messages.resx +++ b/Mono.TextTemplating.Build/Messages.resx @@ -193,4 +193,7 @@ Skipping transform template '{0}': output '{1}' is up to date + + Regenerating all preprocessed templates: target runtime has changed from '{0}' to '{1}' + \ No newline at end of file diff --git a/Mono.TextTemplating.Build/T4.BuildTools.targets b/Mono.TextTemplating.Build/T4.BuildTools.targets index 65e6336..3839b1b 100644 --- a/Mono.TextTemplating.Build/T4.BuildTools.targets +++ b/Mono.TextTemplating.Build/T4.BuildTools.targets @@ -91,6 +91,7 @@ UseLegacyPreprocessingMode="$(UseLegacyT4Preprocessing)" IntermediateDirectory="$(_T4IntermediateTemplateOutputDir)" TransformOutOfDateOnly="$(TransformOutOfDateOnly)" + PreprocessTargetRuntimeIdentifier="$(TargetFrameworkIdentifier)" > diff --git a/Mono.TextTemplating.Build/TemplateBuildState.cs b/Mono.TextTemplating.Build/TemplateBuildState.cs index c042afd..6a2a1ab 100644 --- a/Mono.TextTemplating.Build/TemplateBuildState.cs +++ b/Mono.TextTemplating.Build/TemplateBuildState.cs @@ -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; @@ -39,6 +39,8 @@ public class TemplateBuildState public List TransformTemplates { get; set; } [Key (9)] public List Parameters { get; set; } + [Key(10)] + public string PreprocessTargetRuntimeIdentifier { get; set; } internal (List transforms, List preprocessed) GetStaleAndNewTemplates ( TemplateBuildState previousBuildState, bool preprocessOnly, Func getFileWriteTime, TaskLoggingHelper logger) @@ -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; @@ -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)); diff --git a/Mono.TextTemplating.Build/TextTransform.cs b/Mono.TextTemplating.Build/TextTransform.cs index 65e5e9e..32558e4 100644 --- a/Mono.TextTemplating.Build/TextTransform.cs +++ b/Mono.TextTemplating.Build/TextTransform.cs @@ -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; } @@ -71,7 +73,8 @@ public override bool Execute () var buildState = new TemplateBuildState { IntermediateDirectory = IntermediateDirectory, - DefaultNamespace = DefaultNamespace + DefaultNamespace = DefaultNamespace, + PreprocessTargetRuntimeIdentifier = PreprocessTargetRuntimeIdentifier }; success &= AddParameters (buildState); diff --git a/Mono.TextTemplating.Build/TextTransformProcessor.cs b/Mono.TextTemplating.Build/TextTransformProcessor.cs index 065a76b..e0eb29b 100644 --- a/Mono.TextTemplating.Build/TextTransformProcessor.cs +++ b/Mono.TextTemplating.Build/TextTransformProcessor.cs @@ -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); @@ -206,6 +208,8 @@ static MSBuildTemplateGenerator CreateGenerator (TemplateBuildState buildState) } } + generator.UseRelativeLinePragmas = true; + return generator; } diff --git a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/ParameterDirectiveProcessor.cs b/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/ParameterDirectiveProcessor.cs index 14a497a..403ec76 100644 --- a/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/ParameterDirectiveProcessor.cs +++ b/Mono.TextTemplating/Microsoft.VisualStudio.TextTemplating/ParameterDirectiveProcessor.cs @@ -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; @@ -147,12 +148,8 @@ public override void ProcessDirective (string directiveName, IDictionary ($"_{name}Acquired", Expression.False, out var acquiredVariableRef); if (hasAcquiredCheck) { postStatements.Add (acquiredVariable); @@ -214,16 +211,17 @@ public override void ProcessDirective (string directiveName, IDictionary (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 (data.VariableName, callContextType.InvokeMethod ("LogicalGetData", namePrimitive), out _), + Statement.If (data.IsNotNull (), + Then: checkCastThenAssignVal) + })); + } } void IRecognizeHostSpecific.SetProcessingRunIsHostSpecific (bool hostSpecific) @@ -231,9 +229,13 @@ 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; } } } diff --git a/Mono.TextTemplating/Mono.TextTemplating/CodeGenerationOptions.cs b/Mono.TextTemplating/Mono.TextTemplating/CodeGenerationOptions.cs new file mode 100644 index 0000000..a29f592 --- /dev/null +++ b/Mono.TextTemplating/Mono.TextTemplating/CodeGenerationOptions.cs @@ -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; + +/// +/// Controls what code is generated by the template. +/// Internal for now, until we have a better idea of what the API should look like. +/// +class CodeGenerationOptions +{ + /// + /// Whether to use System.Runtime.Remoting.Messaging.CallContext + /// + public bool UseRemotingCallContext { get; set; } +} diff --git a/Mono.TextTemplating/Mono.TextTemplating/ISupportCodeGenerationOptions.cs b/Mono.TextTemplating/Mono.TextTemplating/ISupportCodeGenerationOptions.cs new file mode 100644 index 0000000..ac77caf --- /dev/null +++ b/Mono.TextTemplating/Mono.TextTemplating/ISupportCodeGenerationOptions.cs @@ -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; + +/// +/// Implemented by directives that support code generation options. +/// Internal for now, until we have a better idea of what the API should look like. +/// +interface ISupportCodeGenerationOptions +{ + void SetCodeGenerationOptions (CodeGenerationOptions options); +} diff --git a/Mono.TextTemplating/Mono.TextTemplating/TemplateSettings.cs b/Mono.TextTemplating/Mono.TextTemplating/TemplateSettings.cs index 423e85a..769285f 100644 --- a/Mono.TextTemplating/Mono.TextTemplating/TemplateSettings.cs +++ b/Mono.TextTemplating/Mono.TextTemplating/TemplateSettings.cs @@ -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 diff --git a/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.cs b/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.cs index b3a0e84..7a00f75 100644 --- a/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.cs +++ b/Mono.TextTemplating/Mono.TextTemplating/TemplatingEngine.cs @@ -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": @@ -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) @@ -548,6 +550,10 @@ public static TemplateSettings GetSettings (ITextTemplatingEngineHost host, Pars settings.RelativeLinePragmas = relativeLinePragmas; +#if FEATURE_APPDOMAINS + settings.CodeGenerationOptions.UseRemotingCallContext = true; +#endif + return settings; }