【问题标题】:Setting the OutputPath property of a project via Visual Studio Automation通过 Visual Studio 自动化设置项目的 OutputPath 属性
【发布时间】:2013-12-15 19:04:13
【问题描述】:

我正在编写一个 VSIX 包,以允许用户在当前加载的解决方案中批量编辑项目的所有活动配置的 OutputPath 属性(请参阅令人难以置信的烦人步骤 #4 here)。

我遇到了一个非常具体的问题:将属性设置为包含宏的值时(例如"$(SolutionDir)\bin\Debug",写入 .csproj 的值如下转义:

<OutputPath>%24%28SolutionDir%29\bin\Debug\</OutputPath>

与其让 MSBuild 扩展宏,不如创建一个名为 $(SolutionDir) 的实际物理文件夹。我想以某种方式绕过这种转义。

毫无疑问,该领域缺少 MSDN 文档。

我的初始代码如下:

private void MenuItemCallback(object sender, EventArgs e)
{
    SolutionWideOutputDialogWindow dialog = new SolutionWideOutputDialogWindow();
    dialog.ShowModal();
    if (!dialog.DialogResult.HasValue || !dialog.DialogResult.Value)
    {
        return;
    }

    string requestedOutputPath = dialog.outputPathTextBox.Text;
    Solution2 solution = _dte2.Solution as Solution2;
    if (solution == null)
    {
        return;
    }

    Projects projects = solution.Projects;
    foreach (Project project in projects)
    {
        Property outputPath = project.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath");
        outputPath.Value = requestedOutputPath;
        project.Save();
    }
}

非常感谢任何人的帮助。

【问题讨论】:

  • 使用 IDE 执行此操作时会发生完全相同的事情。 IDE 也没有给出任何支持宏的提示。假设您无法完成这项工作,这是非常安全的。请改用相对路径,例如 ..\bin\debug
  • 嗯,MSBuild 确实支持它,但这让我只能直接编辑底层项目文件
  • “为所有项目执行 x”的 msbuild/VS 方式是使用在所有项目中导入的通用文件。您可以通过在每个项目中添加该文件来手动(或编写脚本)执行此操作,也可以使用全局文件(例如在$(VCTargetsPath)\Platforms\Win32\ImportBefore 中)。在全局中设置 OutputPath 就完成了。我真的建议使用通用文件来定义几乎所有内容(编译器/链接器/工具选项和所有路径),毕竟这是 DRY 的问题。
  • 这实际上是我已经完成的,但是当我想在每个解决方案配置的基础上使输出路径全局化时遇到了一个问题(即 $(SolutionDir)bin\$(SolutionConfigurationName) \$(解决方案平台名称))。 MSBuild 导出的宏是基于每个项目的,因此如果您的项目平台没有完全统一命名,则无法正常工作。我最终找到了一个 Visual Studio 插件,可以从 IDE 中为我导出这些内容。我不得不稍微调整一下,让它更早地导出它们而不破坏 VS 功能,但我现在很满意。

标签: c# visual-studio-2012 msbuild envdte


【解决方案1】:

这是我最终做的:

我试图解决的问题不是重复自己 (DRY) 并指定解决方案范围的输出目录(在具有大量项目的解决方案中) - 也就是说,在编译解决方案时,所有项目都会有它们的输出目录设置为 $(SolutionDir)bin\Debug$(SolutionDir)bin\Release。值得一提的是,有些项目包含在多个存储库中,并且包含在多个解决方案中。

起初,我创建了一个 MSBuild 文件(&lt;Project&gt; XML - 称之为 MySolution.sln.targets)。在其中,我定义了一个 &lt;PropertyGroup&gt;,它覆盖了 &lt;OutputPath&gt; 属性:

$(SolutionDir)bin\$(Platform)\$(Configuration)

然后我在构建目标导入之前将以下导入添加到所有相关项目中:

<Import Project="$(SolutionPath).targets" />

这样,每个解决方案都有一个随附的 .targets 文件,定义了我希望在解决方案范围内使用的内容。

这很好,但后来我遇到了以下问题:上述$(Platform)$(Configuration) 宏指的是项目的 属性,而不是解决方案范围的属性。如果我的解决方案的 Debug/Any CPU 配置仍然在其 Release 配置中构建了一些非常具体的项目,会发生什么?据我所知,在彻底检查文档后,没有导出具有解决方案范围粒度的此类宏。

我发现 ceztko's Visual Studio extension 使 Visual Studio 准确地导出了我正在寻找的宏 - 但经过一些实验和摆弄后,我发现这个扩展设置它们为时已晚 - 只有在构建解决方案时。这导致 Visual Studio 的增量构建功能出现问题 - 它一直认为项目已过时,因为它在错误的位置查找 - 它不知道变量,但 MSBuild.exe 是。

我开始摆弄IVsUpdateSolutionEventsinterface,跟踪每个方法何时被调用 - 然后发现IVsUpdateSolutionEvents.OnActiveProjectCfgChange 在新的 Visual Studio 中打开一个 1 项目解决方案时被调用了两次,或者在更改解决方案的从 Debug 到 Release 的配置。进一步摆弄发现,如果我在两种解决方案配置中都将项目设置为在 Release 中编译,那么在更改解决方案配置时,这个方法现在被调用一次而不是两次。

我分叉了扩展的存储库并通过将宏设置逻辑移动到上述方法来修改问题。你可以找到它here

免责声明:这可能无法与 IDE 中的批量构建操作很好地交互,并且需要您在从 MSBuild.exe 的命令行构建时自己导出这些属性。

祝你旅途愉快。

【讨论】:

  • 很棒的工作(原来的项目现在似乎工作了)
【解决方案2】:

不幸的是,在从项目属性进行编辑时,Visual Studio 会转义特殊字符。

要解决此问题,请直接在文本编辑器中编辑 .csproj 文件。

例如,改变:

<OutputPath>%24%28SolutionDir%29\bin\Debug\</OutputPath>

到:

<OutputPath>$(SolutionDir)\bin\Debug\</OutputPath>

【讨论】:

  • 建议:如果您使用文本编辑器,请将&lt;OutputPath&gt; 设置为$(SolutionDir)\bin\Debug,它将在Visual Studio 2013..\..\..\bin\Debug /i>。好消息是,宏观将保持不变。正如预期的那样,如果您在 Visual Studio... 中对 Output Path: 进行任何更改...那么宏将被删除。仅供参考 - Microsoft 使用此网站来帮助确定功能请求的优先级:UserVoice.com
猜你喜欢
  • 2018-04-29
  • 2012-08-26
  • 1970-01-01
  • 2014-01-20
  • 2012-02-23
  • 1970-01-01
  • 1970-01-01
  • 2019-10-26
相关资源
最近更新 更多