运行 T4 模板时确定解决方案配置(调试/发布)

发布于 2024-10-30 19:15:11 字数 897 浏览 1 评论 0原文

我有一个 T4 模板,可以根据标志输出优化内容或标准内容。目前我正在根据我的需要手动更改标志。

我想做的是根据 Visual Studio 中解决方案的配置设置标志。如果设置为在调试模式下构建,我将输出标准内容。如果设置为以发布模式构建,我会优化内容。我发现另一个看起来很有希望的 T4 问题: T4 文本模板 - 是否可以从主机获取编译符号?

但是,在我的情况下,我想做如下操作:

<#@ template language="C#" hostspecific="True" 
    compilerOptions="/d:$(ConfigurationName)" #>

因为我可以在程序集指令中使用 $(SolutionDir):

<#@ assembly name="$(SolutionDir)\myreference.dll" #>

我想/d:$(ConfigurationName) 会让我到达我需要去的地方,然后我可以执行以下操作来设置我的标志:

<#
#if Debug 
 optimize = false;
#else 
 optimize = true;
#endif 
#>

唉,这似乎不起作用。我也尝试过使用:

Host.ResolveParameterValue("-", "-", "ConfigurationName");

也无济于事。有什么想法吗?

I have a T4 template that can output either optimized content or standard content based on a flag. Currently I'm manually changing the flag based on my needs.

What I'd love to do is set the flag based on the Configuration of the Solution in Visual Studio. If set to build in Debug mode, I would output standard content. If set to build in Release mode, I would optimize the content instead. I found another T4 question that looks promising: T4 Text Template - Is it possible to get compilation symbols from host?

However, in my case I would want to do something like the following:

<#@ template language="C#" hostspecific="True" 
    compilerOptions="/d:$(ConfigurationName)" #>

Since I can use $(SolutionDir) in an assembly directive:

<#@ assembly name="$(SolutionDir)\myreference.dll" #>

I would think the /d:$(ConfigurationName) would get me where I needed to go, and then I could do the following to set my flag:

<#
#if Debug 
 optimize = false;
#else 
 optimize = true;
#endif 
#>

Alas, this doesn't seem to work. I've also attempted using:

Host.ResolveParameterValue("-", "-", "ConfigurationName");

Also to no avail. Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夏末染殇 2024-11-06 19:15:11

我一问就发现这篇 MSDN 文章<的底部有一个片段< /a> 这让我到达我需要去的地方。这里的答案是使用 IServiceProvider 接口来获取 Visual Studio DTE。下面是完成此操作的代码(提前对硬编码的“调试”表示歉意):

    var serviceProvider = Host as IServiceProvider;
    var dte = serviceProvider.GetService(typeof(DTE)) as DTE;
    var configName = dte.Solution.SolutionBuild.ActiveConfiguration.Name;
    optimize = (configName != "Debug"); 

更新

此代码将检查活动项目的当前配置是否已打开优化。它仍然有一个硬编码的属性名称,但更改的可能性要小得多。另外,使用项目的优化标志对于我的场景很有意义(尝试决定是否应该在自己的代码中打开优化):

    var serviceProvider = Host as IServiceProvider;
    var dte = serviceProvider.GetService(typeof(EnvDTE.DTE)) as DTE;
    config = dte.Solution
                .FindProjectItem(Host.TemplateFile)
                .ContainingProject
                .ConfigurationManager
                .ActiveConfiguration;
    foreach(Property prop in config.Properties)
    {
        if (prop.Name == "Optimize")
        {
            optimize = (bool)prop.Value;
            break;
        }
    }

No sooner do I ask but I find a snippet at the bottom of this MSDN article that gets me where I need to be. The answer here is to use the IServiceProvider interface to get the Visual Studio DTE. Here's code that is getting it done (apologies in advance for the hard-coded "Debug"):

    var serviceProvider = Host as IServiceProvider;
    var dte = serviceProvider.GetService(typeof(DTE)) as DTE;
    var configName = dte.Solution.SolutionBuild.ActiveConfiguration.Name;
    optimize = (configName != "Debug"); 

UPDATE

This code will check to see if the active project's current configuration has optimizations turned on. It still has a hard-coded property name, but one that's much less likely to change. Also, using the project's optimization flag makes a lot of sense for my scenario (trying to decide if I should turn on optimizations in my own code):

    var serviceProvider = Host as IServiceProvider;
    var dte = serviceProvider.GetService(typeof(EnvDTE.DTE)) as DTE;
    config = dte.Solution
                .FindProjectItem(Host.TemplateFile)
                .ContainingProject
                .ConfigurationManager
                .ActiveConfiguration;
    foreach(Property prop in config.Properties)
    {
        if (prop.Name == "Optimize")
        {
            optimize = (bool)prop.Value;
            break;
        }
    }
风月客 2024-11-06 19:15:11

对于那些试图在设计时(文件保存)以及构建时 (F5/F6),需要两种方法。

Emil 描述了设计时方法。对于构建时,您首先必须在项目文件中指定 T4 参数:

<ItemGroup>
  <T4ParameterValues Include="BuildConfiguration">
    <Value>$(Configuration)</Value>
    <Visible>false</Visible>    
  </T4ParameterValues>
</ItemGroup>

然后您必须在 .tt 顶部引用它:

<#@ parameter type="System.String" name="BuildConfiguration" #>

然后查找恰好提供的其中一个:

string configurationName = Host.ResolveParameterValue("-", "-", "BuildConfiguration");
if (string.IsNullOrWhiteSpace(configurationName))
{
    var serviceProvider = (IServiceProvider)Host;
    var dte = (DTE)serviceProvider.GetService(typeof(DTE));
    configurationName = dte.Solution.SolutionBuild.ActiveConfiguration.Name;
}

有必要包含如果您希望模板在两种情况下都能工作,则这两种情况都有逻辑。设计时方法在构建时不起作用(DTE 主机不提供解决方案),并且构建时方法在设计时不起作用(MSBuild 不提供参数)。

For people trying to get this work at design-time (file save) as well as at build-time (F5/F6), two methods are necessary.

Emil describes the design-time method. For build-time, you first have to specify a T4 parameter in your project file:

<ItemGroup>
  <T4ParameterValues Include="BuildConfiguration">
    <Value>$(Configuration)</Value>
    <Visible>false</Visible>    
  </T4ParameterValues>
</ItemGroup>

Then you have to reference it at the top of your .tt:

<#@ parameter type="System.String" name="BuildConfiguration" #>

And then look for whichever of them happens to be provided:

string configurationName = Host.ResolveParameterValue("-", "-", "BuildConfiguration");
if (string.IsNullOrWhiteSpace(configurationName))
{
    var serviceProvider = (IServiceProvider)Host;
    var dte = (DTE)serviceProvider.GetService(typeof(DTE));
    configurationName = dte.Solution.SolutionBuild.ActiveConfiguration.Name;
}

It is necessary to include the logic for both if you want your template to work in both scenarios. The design-time method does not work at build-time (the DTE Host is not around to provide the Solution), and the build-time method does not work at design-time (MSBuild is not around to provide the parameter).

看春风乍起 2024-11-06 19:15:11

如果尝试在 VS2017 ASP.Net Core 项目中执行此操作,那么以下是一个对我有用的解决方案,其中包含我的帖子此处。

Jeremy 的 MSDN 博客Kuhne 和这个Thomas Levesque 的博客 以及其他几个链接,例如此 MSDN 文档 帮助让它在 VS2017 中工作。

我不必在 .csproj 文件的开头添加任何内容,因为 VS2017 默认情况下已包含这些文件。

在 Visual Studio 2017 中,文本模板转换组件是
作为 Visual Studio 扩展的一部分自动安装
开发工作量。您也可以从个人安装
Visual Studio 安装程序的“组件”选项卡,位于“代码工具”下
类别。从个人安装建模 SDK 组件
组件选项卡。

我最终在文件末尾进行了以下 .csproj 更改:

  <PropertyGroup>
    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
    <!-- Run the Transform task at the start of every build -->
    <TransformOnBuild>true</TransformOnBuild>
    <!-- -->
    <OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
    <!-- Transform every template every time -->
    <TransformOutOfDateOnly>false</TransformOutOfDateOnly>
  </PropertyGroup>

  <!-- add AFTER import for $(MSBuildToolsPath)\Microsoft.CSharp.targets -->
  <Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />

    <ItemGroup>
    <T4ParameterValues Include="BuildConfiguration">
        <Value>$(Configuration)</Value>
        <Visible>False</Visible>
    </T4ParameterValues>
  </ItemGroup>

    <Target Name="CreateT4ItemListsForMSBuildCustomTool" BeforeTargets="CreateT4ItemLists" AfterTargets="SelectItemsForTransform">
    <ItemGroup>
        <T4Transform Include="@(CreateT4ItemListsInputs)" Condition="'%(CreateT4ItemListsInputs.Generator)' == 'MSBuild:TransformAll'" />
    </ItemGroup>
  </Target>

这在 T4 模板中:

<#@ template hostspecific="true" language="C#" #>
<#@ output extension=".txt" #>
<#@ assembly name="EnvDTE" #>
<#  
    //Build time
    string configName = Host.ResolveParameterValue("-", "-", "BuildConfiguration");
    if (string.IsNullOrWhiteSpace(configName))
    {
        try
        {
            //Design time.
            var serviceProvider = (IServiceProvider)Host;
            EnvDTE.DTE dte = (EnvDTE.DTE)serviceProvider.GetService(typeof(EnvDTE.DTE));
            configName = dte.Solution.SolutionBuild.ActiveConfiguration.Name;
        }
        catch(Exception ex)
        {
            configName = ex.Message;
        }
    }
#>
<#=configName#>

.tt 文件上的以下属性设置:

Build Action: None
Copy to Output Directory: Do Not Copy
Custom Tool: MSBuild:TransformAll

If trying to do this in a VS2017 ASP.Net Core project then following is a solution that worked for me with highlights from my post here.

This MSDN blog by Jeremy Kuhne and this blog by Thomas Levesque and several other links such as this MSDN doc helped get it working in VS2017.

I did not have to add anything to the beginning of the .csproj file since VS2017 has the files already included by default.

In Visual Studio 2017, the Text Template Transformation component is
automatically installed as part of the Visual Studio extension
devlopment workload. You can also install it from the Individual
components tab of Visual Studio Installer, under the Code tools
category. Install the Modeling SDK component from the Individual
components tab.

I ended up with the following .csproj changes at the end of the file:

  <PropertyGroup>
    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
    <!-- Run the Transform task at the start of every build -->
    <TransformOnBuild>true</TransformOnBuild>
    <!-- -->
    <OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
    <!-- Transform every template every time -->
    <TransformOutOfDateOnly>false</TransformOutOfDateOnly>
  </PropertyGroup>

  <!-- add AFTER import for $(MSBuildToolsPath)\Microsoft.CSharp.targets -->
  <Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />

    <ItemGroup>
    <T4ParameterValues Include="BuildConfiguration">
        <Value>$(Configuration)</Value>
        <Visible>False</Visible>
    </T4ParameterValues>
  </ItemGroup>

    <Target Name="CreateT4ItemListsForMSBuildCustomTool" BeforeTargets="CreateT4ItemLists" AfterTargets="SelectItemsForTransform">
    <ItemGroup>
        <T4Transform Include="@(CreateT4ItemListsInputs)" Condition="'%(CreateT4ItemListsInputs.Generator)' == 'MSBuild:TransformAll'" />
    </ItemGroup>
  </Target>

This in the T4 Template:

<#@ template hostspecific="true" language="C#" #>
<#@ output extension=".txt" #>
<#@ assembly name="EnvDTE" #>
<#  
    //Build time
    string configName = Host.ResolveParameterValue("-", "-", "BuildConfiguration");
    if (string.IsNullOrWhiteSpace(configName))
    {
        try
        {
            //Design time.
            var serviceProvider = (IServiceProvider)Host;
            EnvDTE.DTE dte = (EnvDTE.DTE)serviceProvider.GetService(typeof(EnvDTE.DTE));
            configName = dte.Solution.SolutionBuild.ActiveConfiguration.Name;
        }
        catch(Exception ex)
        {
            configName = ex.Message;
        }
    }
#>
<#=configName#>

The following property settings on the .tt file:

Build Action: None
Copy to Output Directory: Do Not Copy
Custom Tool: MSBuild:TransformAll
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文