有效地将Visual Studio项目属性用于多个项目和配置


70

我一直使用GUI支持的内置Visual Studio来配置我的项目,通常使用属性表,以便几个项目将使用一个公共集。

我主要的工作之一是管理多个项目,配置和平台。如果仅使用主GUI进行所有操作(右键单击项目->属性),它很快就会变得一团糟,难以维护并且容易出现错误(例如无法正确定义某些宏或使用错误的运行时库等)。处理不同的人将依赖库放在不同位置的事实(例如,我的所有库都位于“ C:\ Libs \ [C,C ++] \ [lib-name] \”中),然后经常管理这些库的不同版本同样(发布,调试,x86,x64等)也是一个大问题,因为它极大地增加了在新系统上进行设置的时间,然后是版本控制和使每个人的路径分开的问题。 。

属性表使这更好一些,但是我不能让一个表具有针对不同配置和平台的单独设置(下拉框呈灰色),导致我有很多表,如果以正确的顺序继承这些表,可以满足我的要求( “ x86”,“ x64”,“ debug”,“ release”,“ common”,“目录”(通过定义用户宏(如BoostX86LibDir来解决前面提到的依赖性问题)等),以及是否以错误的顺序继承(例如“ x64”和“ debug”之前的“ common”)会导致诸如尝试链接不正确的库版本或错误命名输出等问题。

我想要的是一种处理所有这些分散的依赖性并设置解决方案中所有项目都使用的“规则”的方法,例如将输出库命名为“ mylib- [vc90,vc100]-[x86]”。 ,x64] [-d] .lib”,而不必为每个单独的项目,配置和平台组合执行所有这些操作,然后将它们正确同步。

我知道要转移到完全不同的系统(例如CMake)上来创建所需的文件,但是这会使其他地方的事情变得复杂,因此即使是简单的任务(例如向项目中添加新文件)也需要在其他地方进行其他更改,这不是我要做的除非对VS2010的某些集成可以跟踪这些变化,否则对它们中的任何一个都完全满意。


1
我感到您的痛苦:我们的产品中有600多个vcproj。:(
C约翰逊

Answers:


79

我只是发现了一些我认为不可能的事情(GUI并未公开),这有助于使属性表更加有用。项目属性文件中许多标签的“ Condition”属性,也可以在.props文件中使用它!

我只是整理了以下内容作为测试,效果很好,并完成了5个(普通,x64,x86,调试,发行)单独的属性表的任务!

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Label="UserMacros">
    <!--debug suffix-->
    <DebugSuffix Condition="'$(Configuration)'=='Debug'">-d</DebugSuffix>
    <DebugSuffix Condition="'$(Configuration)'!='Debug'"></DebugSuffix>
    <!--platform-->
    <ShortPlatform Condition="'$(Platform)' == 'Win32'">x86</ShortPlatform>
    <ShortPlatform Condition="'$(Platform)' == 'x64'">x64</ShortPlatform>
    <!--toolset-->
    <Toolset Condition="'$(PlatformToolset)' == 'v90'">vc90</Toolset>
    <Toolset Condition="'$(PlatformToolset)' == 'v100'">vc100</Toolset>
  </PropertyGroup>
  <!--target-->
  <PropertyGroup>
    <TargetName>$(ProjectName)-$(Toolset)-$(ShortPlatform)$(DebugSuffix)</TargetName>
  </PropertyGroup>
</Project>

唯一的问题是属性GUI无法处理它,使用上述属性表的项目仅报告目标的默认继承值,例如“ $(ProjectName)”。


是的,在VS2k10中,属性表的功能要强大得多。遗憾的是,这些都没有通过IDE公开。我做了类似的事情,它确实简化了事情。
jalf

4
如果您需要更高级的String函数,则可以使用System.String方法:msdn.microsoft.com/en-us/library/…示例:`<ShortHasRelPos> $(Configuration.ToLower()。LastIndexOf('rel')) )</ ShortHasRelPos>
奥利弗·曾德尔2014年

如何应用此解决方案?我应该把它放在哪里,如何让Visual Studio知道我希望它以默认方式使用?
user2023370

1
我从来没有将它作为“全局默认值”来做,因为它可能会与非我自己的项目(例如,第三方库和示例项目)相混淆,尽管有默认属性表存储在某个地方(您可以编辑)。这样,我将它们放在解决方案目录中,然后在Visual Studio“属性管理器”窗口中,您可以使用“添加现有属性表”(也可以在其中创建新属性表),但是GUI仍然无法提供任何方法属性表上的基本平台/配置条件)。这也可以正确地与多个开发人员/源代码控制一起使用。
Fire Lancer

28

我做了一些改进,可能对某人有用

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Label="UserMacros">
    <!--IsDebug: search for 'Debug' in Configuration-->
    <IsDebug>$([System.Convert]::ToString( $([System.Text.RegularExpressions.Regex]::IsMatch($(Configuration), '[Dd]ebug'))))</IsDebug>

    <!--ShortPlatform-->
    <ShortPlatform Condition="'$(Platform)' == 'Win32'">x86</ShortPlatform>
    <ShortPlatform Condition="'$(Platform)' == 'x64'">x64</ShortPlatform>

    <!--build parameters-->
    <BUILD_DIR>$(registry:HKEY_CURRENT_USER\Software\MyCompany\@BUILD_DIR)</BUILD_DIR>
  </PropertyGroup>

  <Choose>
    <When Condition="$([System.Convert]::ToBoolean($(IsDebug)))">
      <!-- debug macroses -->
      <PropertyGroup Label="UserMacros">
        <MyOutDirBase>Debug</MyOutDirBase>
        <DebugSuffix>-d</DebugSuffix>
      </PropertyGroup>
    </When>
    <Otherwise>
      <!-- other/release macroses -->
      <PropertyGroup Label="UserMacros">
        <MyOutDirBase>Release</MyOutDirBase>
        <DebugSuffix></DebugSuffix>
      </PropertyGroup>
    </Otherwise>
  </Choose>

  <Choose>
    <When Condition="Exists($(BUILD_DIR))">
      <PropertyGroup Label="UserMacros">
        <MyOutDir>$(BUILD_DIR)\Bin\$(MyOutDirBase)_$(ShortPlatform)\</MyOutDir>
        <MyIntDir>$(BUILD_DIR)\Build\$(Configuration)_$(ShortPlatform)_$(PlatformToolset)\$(ProjectGuid)\</MyIntDir>
      </PropertyGroup>
    </When>
    <Otherwise>
      <PropertyGroup Label="UserMacros">
        <MyOutDir>$(SolutionDir)\Bin\$(MyOutDirBase)_$(ShortPlatform)\</MyOutDir>
        <MyIntDir>$(SolutionDir)\Build\$(Configuration)_$(ShortPlatform)_$(PlatformToolset)\$(ProjectGuid)\</MyIntDir>
      </PropertyGroup>
    </Otherwise>
  </Choose>

  <PropertyGroup>
    <OutDir>$(MyOutDir)</OutDir>
    <IntDir>$(MyIntDir)</IntDir>
<!-- some common for projects
    <CharacterSet>Unicode</CharacterSet>
    <LinkIncremental>false</LinkIncremental>
--> 
  </PropertyGroup>
</Project>

玩得开心!


什么时候进行评估?加载项目时?我想将自定义生成后复制规则添加到属性表中,以便仅复制实际上已链接到项目的DLL。您认为这可能吗?
Bim

Bim,我认为它是在构建之前进行评估的,因为它从注册表中读取变量(请参见$(registry:key))。
lunicon '16

12

以前,我对公司的产品(200多个项目)有同样的痛苦。我解决的方法是建立属性表的良好层次结构。

项目通过其输出类型(例如x64.Debug.Dynamic.Library.vsprops)继承属性表。这个vsprops文件仅使用InheritedPropertySheets属性继承了其他属性表

<VisualStudioPropertySheet
    ProjectType="Visual C++"
    Version="8.00"
    Name="x64.Debug.Dynamic.Binary"
    InheritedPropertySheets=".\Common.vsprops;.\x64.vsprops;.\Debug.vsprops;.\Runtime.Debug.Dynamic.vsprops;.\Output.x64.Library.vsprops"
    >

您还可以在属性表中使用变量(即UserMacro,其值可以是绝对值甚至是环境变量)来根据需要自定义很多内容。例如,在Debug.vsprops中定义BIN变量

<UserMacro name="BIN" Value="Debug" />

然后当您在一系列vsprops中设置输出名称时,例如Output.x64.Library.vsprops

<VisualStudioPropertySheet
    ProjectType="Visual C++"
    Version="8.00"
    OutputDirectory="$(BIN)"
>

$(BIN)变量将扩展为已设置的值(在本例中为Debug)。使用此技术,您可以轻松地构建一个不错的属性表层次结构来满足您的需求。

现在,您可能还要做一件事:使用属性表集构建自己的项目模板。真正困难的部分是强制正确使用模板和属性表。我的个人经验是,即使一切都已设置,仍然有人会忘记使用模板来创建新项目...


5

可以为每个配置创建单独的属性表。去做这个:

  1. 创建特定于配置的属性表
  2. 打开物业经理
  3. 右键单击配置要修改(不是项目)
  4. 点击“添加现有属性表”并添加您的表

这使您不必将条件插入到多个配置的单张纸中。如果您要在配置之间共享某些公共属性,请创建一个层次结构。顶层工作表可用于所有配置,并且嵌套工作表将仅包含特定于配置的属性


完善!谢谢。因此,您还可以在每个配置节点中创建新页面。易于陷入编辑共享页面的陷阱,即使在每个配置节点下都可以访问它,也会影响所有配置。
贾斯汀

4

就输出库而言,您可以选择所有项目,然后调出属性页面,选择“所有配置”,“所有平台”,然后将“目标名称”设置为:

$(ProjectName)-$(PlatformToolset)-$(PlatformShortName)-$(Configuration)

这将给出类似于mylib-v100-x86-Debug.lib的输出

我们也对“其他库目录”进行了类似的操作,使用$(PlatformName)#(Configuration)选择了正确的库路径,尽管这确实意味着对库的初始设置会产生一些麻烦。例如,我们已经将其库升压安装到boost/lib.Win32boost/lib.x64


关于库,以及将它们安装在不同位置的人们,有两种选择。如果您有一个非常强大的源代码管理系统,则可以将所有内容放入源代码管理中,位于源代码旁边的libs文件夹中。如果您使用多个库,或者它们很大,那可能就行不通了。

想到的另一个选择是在每个用户计算机上设置一个指向其库文件夹根目录的环境变量,例如LIB_ROOT=c:\libraries,然后可以在Visual Studio中以方式访问该变量$(LIB_ROOT)


我已经做了一些类似的事情,但是有些库的名称中使用了其他名称(例如,opt而不是release,-d而不是-Debug)等,这仍然需要很多特殊规则(我的调试) .props和release.props设置用户宏,以帮助common.props实际设置include / lib路径来解决此问题。没有考虑过带有boost的好主意(如果自动链接包括为x86和x64构建使用相同的名称,而是boost.build人们似乎不认为这是个问题,那就更好了)
Fire Lancer

我猜你的PlatformShortName来自必须正确继承的x86.props和x64.props或某些东西,或者仅仅是未记录的?
Fire Lancer 2010年

@Fire Lancer:说实话,我不确定PlatformShortName的来源。我认为它必须是内置的,因为我们的属性表中没有任何特殊的内容。
ngoozeff

1
@FireLancer:我们修改了boost build脚本,将该平台包含在lib-name中。它确实需要我们有一个自定义,boost_version.h但是自动链接的工作方式就像一个超级按钮,我们只需要将boost.props文件添加到项目中就可以了。我们当然知道道具文件中的条件,这可能是更好的选择。.绝对不那么痛苦..
Andreas Magnusson

0

听起来可能值得一试构建工具-在我这里,我们使用一个定制的工具,该工具可以监视文件和项目中的更改并确定依赖性和编译顺序。添加新文件没什么大不了的-编译是通过msbuild完成的。

如果我不得不编译多个项目,那么我会使用类似nant的东西:http : //nant.sourceforge.net/

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.