VS2010,MSBuild和环境变量

3
我有一个关于MSBuild.exe和环境变量的问题。首先,这是开发环境:
代码主要由C++和一些C#组成。有超过5000个类、340个项目和200个解决方案,排列在深层源树中。在树的根部和其他各个点处都有解决方案。我们使用TFS并维护多个活动分支以进行一系列未来的发布。每个开发人员都使用本地视图来修改和测试代码。有些开发人员同时在多个分支上工作。有时开发人员会同时从不同的TFS分支构建解决方案。
我们使用约70个环境变量来定位共享的头文件、库等。在VS2008中,我们使用与解决方案文件相同的基本名称和扩展名为.slnenv的文件来定义环境变量。所有变量都是相对于源树的基础定义的。这个.slnenv文件是由一个自定义的VS2008 AddIn读取的,它在VS2008进程空间中创建环境变量,即:
  MyProjectDir=$(SolutionDir)\..\..
  MyRoot=$(MyProjectDir)\..\..
  MyInstallDir=$(MyRoot)\Install
  MySourceDir=$(MyRoot)\Source
  MyUnmanagedSourceDir=$(MySourceDir)\My\Unmanaged
  MyIncludeDirs=$(MyProjectDir);$(MyUnmanagedSourceDir)

这个插件在VS2010中不能正常工作,因为MSBuild没有继承解决方案加载后创建的环境变量。

我的问题是如何将这些环境变量传递给MSBuild?我找到了两种方法,但它们不像我们之前使用的插件那么方便。

第一种方法是使用命令脚本启动VS2010,在进程空间中首先设置环境变量,然后启动VS2010。MSBuild会继承这些环境变量。这种方法很不理想,因为脚本需要根据解决方案加载的各个点进行自定义。

我尝试的第二种方法是将环境变量定义为属性,并在属性表和.vcxproj文件中使用。我们有一个基础属性表,所有的.vcxproj文件都会加载它。在那个属性表中:

  <PropertyGroup>
    <MyRoot>$(MyProjectDir)\..\..</MyRoot>
    <MyInstallDir>$(MyRoot)\Install</MyInstallDir>
    <MySourceDir>$(MyRoot)\Source</MySourceDir>
    <MyUnmanagedSourceDir>$(MySourceDir)\My\Unmanaged</MyUnmanagedSourceDir>
    <MyIncludeDirs>$(MyProjectDir);$(MyUnmanagedSourceDir)</MyIncludeDirs>
  </PropertyGroup>

然后我可以在每个.vcxproj文件中定义基础目录:

  <PropertyGroup>
    <MyProjectDir>..\..</MyProjectDir>
  </PropertyGroup>

此方法使用相对路径名,其中AddIn将所有环境变量解析为绝对路径名。我不想编辑340个.vcxproj文件,因为"MyProjectDir"的定义会根据项目文件位于源根目录的距离而变化。到目前为止,我只在一个项目中尝试了这种方法。
我尝试修改AddIn以创建属性而不是环境变量。我尝试使用ENV2.get_Properties(),但那似乎只适用于在VS2010中定义的属性,而不适用于我定义的属性。
谢谢, 丹·凯瑞

你尝试过定制流程模板吗? - frennky
谢谢你的建议,frennky。我会进行调查。 - Dan Kary
非常有趣的问题。您能否澄清一下您如何依赖所有这些环境变量?它仅用于构建过程,还是用于某种开发活动?对于第一种情况,您可以将那些变量条件嵌入到msbuild文件中。但是,如果您使用TFS构建解决方案(我的意思是您没有为每个项目集编写专用的msbuild脚本),可能会更加麻烦。 - Alexey Shcherbak
Frennky - 我们不使用TFS Build,也不想使用,因此流程模板对我们不可用。 - Dan Kary
Alexey - VC++ Directories 中使用了一些环境变量。例如,Include Directories 变成了 $(MyIncludeDirs);$(IncludePath)。其他的则用于构建事件,例如查找当前项目依赖的项目构建的可执行文件或库的路径。 - Dan Kary
据我所知,这应该是在您点击“构建”按钮之前或在打开解决方案时(对于正确的开发而言,而不仅仅是为了构建东西)。我们能否将讨论转移到邮件中?评论并不适合获取信息 =)。请给我发送邮件 centur-gmail-com。 - Alexey Shcherbak
1个回答

1

经过邮件讨论,我们弄清楚了Dan的需求,并且以下信息可以帮助他解决问题。他同意这对其他SO成员也有帮助:

啊哈,我现在明白了。

正如我从那个主题中所理解的 - 你只需要所有这些东西来构建步骤(包括子句的路径、用于解决dll\exe依赖项的构建工具路径),而且没有常规开发人员活动依赖于它。 这很好,因为我们不需要与VStudio争论关于在第一次加载后不重新初始化环境变量的问题。我们只需要以某种方式编辑并实现您的解决方案,适用于大量的proj文件 ;) 任务变得更加容易:D

小免责声明 - 我正在路上写这篇文章,无法访问完整的开发环境来检查和完善所有进一步的建议,因此提前为我可能犯的任何错误道歉;)

我想引起您对一些msbuild功能的注意: http://msdn.microsoft.com/en-us/library/ms164309.aspx

您有预定义的属性,适用于所有脚本和项目,看起来这将有助于您解决第一个问题 - 绝对路径而不是相对路径。这是来自链接的小节,供进一步参考。

$(MSBuildProjectDirectory) - 
The absolute path of the directory where the project file is located, for example, C:\MyCompany\MyProduct.

$(MSBuildProjectFile) - 
The complete file name of the project file, including the file name extension, for example, 
MyApp.proj.

$(MSBuildProjectExtension)
The file name extension of the project file, including the period, for example, .proj.

$(MSBuildProjectFullPath)
The absolute path and complete file name of the project file, for example, C:\MyCompany\MyProduct\MyApp.proj.

$(MSBuildProjectName)
The file name of the project file without the file name extension, for example, MyApp.

因此,您应该能够在属性表中使用这些定义的属性。 现在,使用msbuild 4.0工具集(由根脚本元素上的属性ToolsVersion=""定义的工具集)有一个有趣的技巧 Microsoft.Common.Targets定义了两个变量,以有条件地在自身之前或之后导入自定义的msbuild脚本 CustomBeforeMicrosoftCommonTargetsCustomAfterMicrosoftCommonTargets 您可以按以下方式使用它(我认为它可能会帮助您避免编辑所有proj文件,或者至少将编辑简化为非常简单的复制粘贴部分) 使用相对路径定义它,以包含您的属性表文件

<CustomBeforeMicrosoftCommonTargets>$(MSBuildProjectFile)\ConcreteProjectCustomProperties.propz</CustomBeforeMicrosoftCommonTargets>

请注意,CustomBeforeMicrosoftCommonTargets 应该是全局作用域属性,以便被所有次要项目继承。
如果您正确定义了 ConcreteProjectCustomProperties.propz,我认为您可以实现所需的功能。 “正确”是指您将全局属性文件(使用相对或绝对路径)包含在其中,然后定义所有项目级属性。

NB: 还要注意,稍后定义的属性无法引用早期定义的属性。 您的示例使用 $(MyProjectDir) 引用 $(MyIncludeDirs),但是 $(MyProjectDir) 的声明和定义稍晚一些。 这可能是由于“示例”和快速编写代码造成的,但是如果您在生产中以同样的方式定义变量,则可能会导致微妙的错误。

我希望我正确理解了您的问题,并且我的解释将帮助您快速将所有属性从自定义插件移动到更简单和本地的 msbuild 脚本中 ;)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接