对多个项目和配置有效使用 Visual Studio 项目属性

发布于 2024-09-14 20:38:41 字数 883 浏览 1 评论 0原文

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

我对此的主要抱怨之一是管理多个项目、配置和平台。如果您只是使用主 GUI 执行所有操作(右键单击项目 -> 属性),它很快就会变得一团糟,难以维护并且容易出现错误(例如未能正确定义某些宏,或使用错误的运行时库等) 。处理不同的人将依赖库放在不同的位置的事实(例如我的依赖库都位于“C:\Libs\[C,C++]\[lib-name]\”),然后经常管理这些库的不同版本不同的方式(发布、调试、x86、x64 等)也是一个大问题,因为它使在新系统上设置它的时间变得非常复杂,然后存在版本控制和保持每个人的路径分离的问题。 属性表使这变得更好一点,但

我不能让一张表针对不同的配置和平台进行单独的设置(下拉框呈灰色),导致我有很多表,如果以正确的顺序继承,则可以执行我想要的操作。 (“x86”、“x64”、“debug”、“release”、“common”、“directories”(通过定义像 BoostX86LibDir 这样的用户宏来处理前面提到的依赖问题)等)并且如果以错误的顺序继承(例如“x64”和“debug”之前的“common”)会导致诸如尝试链接不正确的库版本或错误地命名输出之类的问题...

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

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

I have always used Visual Studios built in GUI support for configuring my projects, often using property sheets so that several projects will use a common set.

One of my main gripes with this is managing multiple projects, configurations and platforms. If you just do everything with the main GUI (right click the project -> properties) it quickly becomes a mess, difficult to maintain and prone to bugs (like failing to correctly define some macro, or using the wrong runtime library, etc). Dealing with the fact that different people put there dependency libraries in different places (eg mine all live in "C:\Libs\[C,C++]\[lib-name]\") and then often manage the different versions of those libraries differently as well (release, debug, x86, x64, etc) is also a large problem since it vastly complicates the time to set it up on a new system, and then there is issues with version-control and keeping everyone's paths separate...

Property sheets make this a bit better, but I cant have one sheet have separate settings for different configurations and platforms (the drop down boxes a greyed out), resulting in me having many sheets which if inherited in the correct order do what I want ("x86", "x64", "debug", "release", "common", "directories" (deals with the previously mentioned dependency issue by defining user macros like BoostX86LibDir), etc) and if inherited in the wrong order (eg "common" before "x64" and "debug") lead to issues like trying to link an incorrect library version, or incorrectly naming the output...

What I want is a way of dealing with all these scattered dependencies and setting up a set of "rules" which are used by all my projects in the solution, like naming an output library as "mylib-[vc90,vc100]-[x86,x64][-d].lib", without having to do all this for each individual project, configuration and platform combination, and then keep them all correctly in sync.

I am aware of moving to entirely different systems like CMake that create the needed files, however this then complicates things elsewhere by making it so even simple tasks like adding a new file to the project then requires additional changes elsewhere, which is not something I am entirely happy with either, unless there is some with VS2010 integration which can keep track of these sorts of changes.

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

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

发布评论

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

评论(7

长亭外,古道边 2024-09-21 20:38:41

我刚刚发现了一些我认为不可能的事情(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)”。

I just found out somthing I didnt think was possible (it is not exposed by the GUI) that helps make property sheet far more useful. The "Condition" attribute of many of the tags in the project property files and it can be used in the .props files as well!

I just put together the following as a test and it worked great and did the task of 5 (common,x64,x86,debug,release) separate property sheets!

<?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>

Only issue is the properties GUI cant handle it, a project that uses the above property sheet just reports default inherited values like "$(ProjectName)" for the target.

陌路黄昏 2024-09-21 20:38:41

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

<?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>

玩得开心很有用!

I made some improvements, may be useful for somebody

<?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>

have fun!

我偏爱纯白色 2024-09-21 20:38:41

我以前对我公司的产品(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) 变量将扩展为已设置的内容(在本例中) , 调试)。使用这种技术,您可以轻松构建良好的属性表层次结构来满足您的需求。

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

I had same pain for the product of my company (200+ projects) before. The way I solved it is to build a nice hierarchy of the property sheets.

The projects inherits the property sheet by its output type, say x64.Debug.Dynamic.Library.vsprops. This vsprops file simply inherits other property sheets using the InheritedPropertySheets attribute

<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"
    >

You can also use variables (i.e. UserMacro, whose value can be absolute or even environment variables) in property sheets to customize a lot of things based on your need. For example, defining a BIN variable in Debug.vsprops

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

then when you set the output name in the series of vsprops, say, Output.x64.Library.vsprops

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

The $(BIN) variable will be expanded to what's been set (in this case, Debug). Use this technique you can easily construct a nice hierarchy of property sheets to meet your demand.

Now there's one more thing you might want to do: build your own project templates that uses your property sheet set. The real difficult part is to enforce proper usage of the templates and property sheets. My personal experience is that even if everything is setup, somebody will still forget to use the template to create new projects ...

好菇凉咱不稀罕他 2024-09-21 20:38:41

可以为每个配置创建单独的属性表。要执行此操作:

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

这可以缓解您无需将条件插入到单个工作表中以进行多种配置。如果您希望在配置之间共享一些通用属性,请创建层次结构。顶部工作表可用于所有配置,嵌套工作表将仅包含特定于配置的属性

It is possible to create a separate property sheet for each configuration. To do this:

  1. Create a configuration-specific property sheet
  2. Open the Property Manager
  3. Right click the configuration (not the project) that you would like to modify
  4. Click "Add Existing Property Sheet" and add your sheet

This relieves you from inserting conditions into a single sheet for multiple configurations. If you have some common attributes that you would like to share between configurations, then create a hierarchy. The top sheet can be used in all configurations and the nested sheets will only contain the configuration-specific attribut

耶耶耶 2024-09-21 20:38:41

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

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

会给出类似 mylib-v100-x86-Debug.lib 的输出

我们也使用 $(PlatformName) 和 #(Configuration) 来选择正确的库路径,尽管这确实意味着对库的初始设置进行一些混乱。例如,我们将 boost 安装其库到 boost/lib.Win32boost/lib.x64


关于库以及将它们安装在不同地方的人们,有几种选择。如果您有一个非常强大的源代码管理系统,您可以将所有内容都放在源代码管理中,位于源代码旁边的 libs 文件夹中。如果您使用多个库,或者它们特别大,那么这可能不起作用。

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

As far as the output library goes, you can select all your projects, then bring up the property pages, select All Configurations, All Platforms and then set the Target Name to:

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

which would give an output like mylib-v100-x86-Debug.lib

We do something similar to this for Additional Library Directories as well, using $(PlatformName) and #(Configuration) to pick out the right library paths, although it does mean some messing around with initial setup of the libraries. eg we have boost install its libs to boost/lib.Win32 or boost/lib.x64.


With regards to libraries, and people installing them in different places, there are a couple of options. If you have a very robust source control system, you can just put everything in source control, living in a libs folder next to your source. That probably won't work if you use more than a few libraries though, or if they are particularly large.

The other option that comes to mind is to set an environment variable on each user machine that points to the root of their libraries folder, eg LIB_ROOT=c:\libraries, and you can then access that in Visual Studio as $(LIB_ROOT).

若沐 2024-09-21 20:38:41

如果您想定义一些对整个解决方案有效的 UserMacros:

  1. 在解决方案根文件夹中创建一个 solution-global.props 文件

  2. 在其中定义您的 UserMacros:

    
    <项目工具版本=“4.0”xmlns=“http://schemas.microsoft.com/developer/msbuild/2003”>
      
        $(SolutionDir)Common\Utils\;
        $(SolutionDir)Common\DriverBase\
      
    
    
  3. 在您想要使用自定义宏的每个 *.vcxproj 文件中插入以下行:

    <导入项目="$(SolutionDir)solution-global.props"/>

  4. 使用您的自定义宏:

    $(CommonUtilsDir)\Source;%(AdditionalIncludeDirectories)

适用于 VS2015

If you want to define some UserMacros which should be valid for the entire solution:

  1. Create a solution-global.props file in your solution root folder

  2. Define there your UserMacros:

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup Label="UserMacros" >
        <CommonUtilsDir>$(SolutionDir)Common\Utils\</CommonUtilsDir>
        <DriverBaseDir>$(SolutionDir)Common\DriverBase\</DriverBaseDir>
      </PropertyGroup>
    </Project>
    
  3. insert in each *.vcxproj file in which you want to use your custom macros this line:

    <Import Project="$(SolutionDir)solution-global.props" />

  4. Use your custom macro:

    <AdditionalIncludeDirectories>$(CommonUtilsDir)\Source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

Works in VS2015

郁金香雨 2024-09-21 20:38:41

听起来似乎值得检查一个构建工具 - 在我的地方,我们使用一个定制的工具来监视文件和项目的更改并计算依赖关系和编译顺序。添加新文件没什么大不了的 - 编译是通过 msbuild 完成的。

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

It sounds like it could be worth checking out a build tool - at my place we use a custom made tool that watches files and projects for changes and figures the dependencies and compile order. Adding a new file is no big deal - compilation is done with msbuild.

If i had to compile more than a bunch of projects I would use something like nant:
http://nant.sourceforge.net/

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