使用Visual C++和Open Folder自定义您的环境

[原文发表地址] Customizing your Environment with Visual C++ and Open Folder

[原文发表时间] 2017/11/02

自从我们支持了打开C ++代码文件夹的功能之后,社区的客户一直希望有更多地可以控制构建和编辑环境的功能。为实现这些想法,我们在Visual Studio 2017的最新版本中增加了一些新的方法可以通过使用CppProperties.json来自定义您的环境。

这个新的自定义界面使您能够使用更广泛的工具,编写更简洁的CppProperties文件,并且具有与MSBuild类似的强大的单个配置的自定义。下面的主题展示了原始C++ Open Folder文章中描述的几个概念。如果您不熟悉编辑CppProperties.json,Launch.vs.json和Tasks.vs.json,可能需要先阅读该文章。

C++ Open Folder这篇文章与我们之前发布的为CMake项目自定义您的环境相匹配,所以如果您已经阅读过了,可能会发现其中有一些内容是相似的,因为我们努力保持经验一致。而最重要的区别在于“关于Launch.vs.json和Tasks.vs.json”如何使用特定于配置的变量。

CppProperties.json的新功能

这种新的灵活性的核心在于您的项目的CppProperties.json文件,它源于两个新的概念:

  1. 使用“inheritEnvironments”属性来继承单个配置或一组默认全局环境变量的能力。
  2. 通过定义“environments”块来定义单个配置或是自定义环境变量及其值的能力。

通过使用“$ {env.VAR}”语法将这些新概念与CppProperties.json,launch.vs.json和tasks.vs.json中现有的使用环境变量的能力相结合,为创建丰富的开发环境提供了强大的机制。

我们先来看看如何使用此功能的快速示例:

 1{
2 // The "environments" property is an array of key value pairs of the form
3  // { "EnvVar1": "Value1", "EnvVar2": "Value2" }
4  "environments": [
5    {
6      "INCLUDE": "${workspaceRoot}\\src\\includes"
7    }
8  ],
9
10  "configurations": [
11    {
12      "inheritEnvironments": [
13        // Inherit the MSVC 32-bit environment and toolchain.
14        "msvc_x86"
15      ],
16      "name": "x86",
17      "includePath": [
18        // Use the include path defined above.
19        "${env.INCLUDE}"
20      ],
21      "defines": [ "WIN32", "_DEBUG", "UNICODE", "_UNICODE" ],
22      "intelliSenseMode": "msvc-x86"
23    },
24    {
25      "inheritEnvironments": [
26        // Inherit the MSVC 64-bit environment and toolchain.
27        "msvc_x64"
28      ],
29      "name": "x64",
30      "includePath": [
31        // Use the include path defined above.
32        "${env.INCLUDE}"
33      ],
34      "defines": [ "WIN32", "_DEBUG", "UNICODE", "_UNICODE" ],
35      "intelliSenseMode": "msvc-x64"
36    }
37  ]
38}

为了说明这个问题,这个例子定义了两个使用Microsoft Visual C++工具链构建的配置。第一个为x86构建(因为它继承了“msvc_x86”环境),另一个为x64构建。它还定义了被两个配置同时使用的环境变量“INCLUDE”(第6行)。

请记住,“environments”(第4行)和“inheritEnvironments”(第12和第25行)属性可以在所有配置,单个配置或是两者兼有中被作为全局定义,每个配置或两者。在上面的例子中,“INCLUDE”变量是全局的,“inheritEnvironment”属性将被应用于各自的配置中。

至今以下环境可用:

  • Target x86 Windows with MSVC (msvc_x86)
  • Target x64 Windows with MSVC (msvc_x64)
  • Target x86 Windows with the 64-bit MSVC (msvc_x64_x86)
  • Target x64 Windows with the 64-bit MSVC (msvc_x64_x64)

另外,如果您安装了Linux Workload,则可以使用以下环境来远程定位Linux和WSL:

  • Target x86 Linux remotely (linux_x86)
  • Target x64 Linux remotely (linux_x64)
  • Target ARM Linux remotely (linux_arm)

特定配置的环境变量可以覆盖全局的变量。下面的例子解释了注释中的覆盖行为:

 1{
2  // The "environments" property is an array of key value pairs of the form
3  // { "EnvVar1": "Value1", "EnvVar2": "Value2" }
4  "environments": [
5    {
6      "INCLUDE": "${workspaceRoot}\\src\\includes"
7    }
8  ],
9
10  "configurations": [
11    {
12      "inheritEnvironments": [
13        // Inherit the MSVC 32-bit environment and toolchain.
14        "msvc_x86"
15      ],
16      "name": "x86",
17      "includePath": [
18        // Use the include path defined above.
19        "${env.INCLUDE}"
20      ],
21      "defines": [ "WIN32", "_DEBUG", "UNICODE", "_UNICODE" ],
22      "intelliSenseMode": "msvc-x86"
23    },
24    {
25      // The "environments" property is an array of key value pairs of the form
26      // { "EnvVar1": "Value1", "EnvVar2": "Value2" }
27      "environments": [
28        {
29          // Append 64-bit specific include path to env.INCLUDE.
30          "INCLUDE": "${env.INCLUDE};${workspaceRoot}\\src\\includes64"
31        }
32      ],
33
34      "inheritEnvironments": [
35        // Inherit the MSVC 64-bit environment and toolchain.
36        "msvc_x64"
37      ],
38      "name": "x64",
39      "includePath": [
40        // Use the include path defined above.
41        "${env.INCLUDE}"
42      ],
43      "defines": [ "WIN32", "_DEBUG", "UNICODE", "_UNICODE" ],
44      "intelliSenseMode": "msvc-x64"
45    }
46  ]
47}

如果您需要为您的构建环境声明很多变量,然后对每个配置进行少量修改,则此重写功能可以大大缩小您项目的CppProperties.json文件。

关于Launch.vs.json和Tasks.vs.json

如果您想知道是否可以在CppProperties.json文件之外使用这些变量,答案是肯定的!您在CppProperties.json中声明的所有环境变量都可以在launch.vs.jsontasks.vs.json中使用。只需将相同的“$ {env.VarName}”语法嵌入任务或启动配置中的任何属性值即可。宏语法将被扩展为它的实际值,因为它在第16行。

 1{
2  "version": "0.2.1",
3  "tasks": [
4    {
5      "taskName": "build-helloworld",
6      "appliesTo": "*.cpp",
7      "contextType": "build",
8      "type": "launch",
9      "command": "${env.comspec}",
10      "workingDirectory": "${workspaceRoot}",
11      // Use environment from selected configuration, you can omit this
12      // to only use globally defined variables instead.
13      "inheritEnvironments": [ "${cpp.activeConfiguration}" ],
14      "output": "${workspaceRoot}\\bin\\helloworld.exe",
15      "args": [
16        "build.bat ${env.BUILD_ARGS}"
17      ]
18    }
19  ]
20}

如果环境变量的值是配置里面特定的,则当您尝试运行任务或调试程序时,将使用当前选定配置的值(如果将其包含在您的任务或启动配置中):

 "inheritEnvironments":  [ "${cpp.activeConfiguration}" ]

如果您不包括这个,只有全局定义的变量将可用。

您声明的环境变量也将由任务启动的进程继承。另一方面,正在调试的程序将不会自动继承构建环境。下面的例子展示了如何显式地将环境变量传递给启动的进程。

 1{
2  "version": "0.2.1",
3  "defaults": {},
4  "configurations": [
5    {
6      "type": "native",
7      "name": "helloworld.exe",
8      // Use environment from selected configuration, you can omit this
9      // to only use globally defined variables instead.
10      "inheritEnvironments":  [ "${cpp.activeConfiguration}" ],
11      "project": "bin\\helloworld.exe",
12      "args": [
13        // Use arguments defined in CppProperties.json.
14        "${env.PROG_ARGS}"
15      ] ,
16      "env": "var1=${env.var1}\u0000var2=hardcodedvalue"
17    }
18  ]
19}

您可以在第14行看到在CppProperties.json文件中引用被定义变量是可以的。第17行中的“\ u0000”是一个空字符,用于分隔变量。

高级功能

您那敏锐的眼睛可能已经注意到,“environments”和“inheritEnvironments”是CppProperties.json语法中的数组,可以声明和继承多个环境。对于典型的构建方案,您不太可能希望从多个环境中继承,但有些情况下您可能需要声明多个环境块。主要的用例是声明几个变量,您可以在任何CppProperties,Launch或者Tasks JSON中引用这些变量同时不用添加这些变量到构建环境中—例如,不在派生的构建过程继承。

以下示例显示了如何完成创建一个自定义命名空间:

 1{
2  // The "environments" property is an array of key value pairs of the form
3  // { "EnvVar1": "Value1", "EnvVar2": "Value2" }
4  "environments": [
5    {
6      "INCLUDE": "${workspaceRoot}\\src\\includes"
7    },
8    {
9      // "namespace" is a reserved key that lets you put variables
10      // in namespaces other than $env.
11      "namespace": "special",
12      // SpecialVar will not be added to the environment.
13      "SpecialVar": "special"
14    }
15
16  ],
17
18  "configurations": [
19    {
20      "inheritEnvironments": [
21        // Inherit the MSVC 32-bit environment and toolchain.
22        "msvc_x86"
23      ],
24      "name": "x86",
25      "includePath": [
26        // Use the include path defined above.
27        "${env.INCLUDE}"
28      ],
29      "defines": [
30        // You can use alternative namespaces (such as special defined above)
31        // just like "${env.VAR}"
32        "${special.specialVar}",
33        "WIN32", "_DEBUG", "UNICODE", "_UNICODE"
34      ],
35      "intelliSenseMode": "msvc-x86"
36    }
37  ]
38}

您可以通过语法“$ {special.SpecialVar}”来访问任何CppProperties,Launch或Tasks JSON文件中的“SpecialVar”,如第32行所示。

发送反馈

要尝试最新的和最好的C ++功能,并给我们一些早期的反馈,请下载并安装最新的Visual Studio 2017 Preview。一如既往,我们欢迎您的反馈。欢迎通过电子邮件 visualcpp@microsoft.com,通过Twitter @visualcMicrosoft Visual Cpp的Facebook发送任何评论。

如果您遇到Visual Studio 2017的其他问题,请通过报告问题告诉我们,这个问题在安装程序和IDE本身都可用。对于建议,让我们通过UserVoice知道。