Skip to content

Commit 12f31c1

Browse files
committed
Update walkthrough and make runAndDebug work
1 parent 622d67b commit 12f31c1

File tree

12 files changed

+84
-31
lines changed

12 files changed

+84
-31
lines changed

Extension/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3376,6 +3376,12 @@
33763376
"default": "default",
33773377
"markdownDescription": "%c_cpp.configuration.copilotHover.markdownDescription%",
33783378
"scope": "window"
3379+
},
3380+
"C_Cpp.persistDevEnvironment": {
3381+
"type": "boolean",
3382+
"default": true,
3383+
"markdownDescription": "%c_cpp.configuration.persistDevEnvironment.markdownDescription%",
3384+
"scope": "resource"
33793385
}
33803386
}
33813387
}

Extension/package.nls.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,7 @@
845845
]
846846
},
847847
"c_cpp.configuration.debugShortcut.description": "Show the \"Run and Debug\" play button and \"Add Debug Configuration\" gear in the editor title bar for C++ files.",
848+
"c_cpp.configuration.persistDevEnvironment.markdownDescription": "Remember the last used Visual Studio developer environment for the current workspace. This setting is only applicable for Windows.",
848849
"c_cpp.debuggers.pipeTransport.description": "When present, this tells the debugger to connect to a remote computer using another executable as a pipe that will relay standard input/output between VS Code and the MI-enabled debugger backend executable (such as gdb).",
849850
"c_cpp.debuggers.pipeTransport.default.pipeProgram": "enter the fully qualified path for the pipe program name, for example '/usr/bin/ssh'.",
850851
"c_cpp.debuggers.pipeTransport.default.debuggerPath": "The full path to the debugger on the target machine, for example /usr/bin/gdb.",
@@ -1027,15 +1028,15 @@
10271028
},
10281029
"c_cpp.walkthrough.create.cpp.file.altText": "Open a C++ file or a folder with a C++ project.",
10291030
"c_cpp.walkthrough.command.prompt.title": {
1030-
"message": "Launch from the Developer Command Prompt for VS",
1031+
"message": "Apply the Visual Studio Developer Environment",
10311032
"comment": [
1032-
"{Locked=\"Developer Command Prompt for VS\"}"
1033+
"{Locked=\"Visual Studio\"}"
10331034
]
10341035
},
10351036
"c_cpp.walkthrough.command.prompt.description": {
1036-
"message": "When using the Microsoft Visual Studio C++ compiler, the C++ extension requires you to launch VS Code from the Developer Command Prompt for VS. Follow the instructions on the right to relaunch.\n[Reload Window](command:workbench.action.reloadWindow)",
1037+
"message": "When using the Microsoft Visual Studio C++ compiler, the Visual Studio Developer Environment must be present.\n\nFollow the instructions on the right to relaunch or click the button below.\n[Set Developer Environment](command:C_Cpp.SetDevEnvironment?%22walkthrough%22)",
10371038
"comment": [
1038-
"{Locked=\"Visual Studio\"} {Locked=\"C++\"} {Locked=\"VS Code\"} {Locked=\"Developer Command Prompt for VS\"} {Locked=\"\\\n[\"} {Locked=\"](command:workbench.action.reloadWindow)\"}"
1039+
"{Locked=\"Visual Studio\"} {Locked=\"C++\"} {Locked=\"\\\n[\"} {Locked=\"](C_Cpp.SetDevEnvironment?%22walkthrough%22)\"}"
10391040
]
10401041
},
10411042
"c_cpp.walkthrough.run.debug.title": "Run and debug your C++ file",

Extension/src/Debugger/configurationProvider.ts

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
121121
}
122122

123123
if (this.isClConfiguration(selection.label)) {
124-
this.showErrorIfClNotAvailable(selection.label);
124+
await this.showErrorIfClNotAvailable(selection.label);
125125
}
126126

127127
return [selection.configuration];
@@ -582,12 +582,32 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
582582
return configurationLabel.startsWith("C/C++: cl.exe");
583583
}
584584

585-
private showErrorIfClNotAvailable(_configurationLabel: string): boolean {
586-
if (!process.env.DevEnvDir || process.env.DevEnvDir.length === 0) {
587-
void vscode.window.showErrorMessage(localize({
588-
key: "cl.exe.not.available",
589-
comment: ["{0} is a command option in a menu. {1} is the product name \"Developer Command Prompt for VS\"."]
590-
}, "{0} is only usable when VS Code is run from the {1}.", `cl.exe ${this.buildAndDebugActiveFileStr()}`, "Developer Command Prompt for VS"));
585+
/**
586+
* @returns `true` if the Developer Environment is not available and an error was shown to the user, `false` if the Developer Environment is available or the user chose to apply it.
587+
*/
588+
private async showErrorIfClNotAvailable(_configurationLabel: string): Promise<boolean> {
589+
if (!util.hasMsvcEnvironment()) {
590+
const applyDevEnv = localize("apply.dev.env", "Apply Developer Environment");
591+
const cancel = localize("cancel", "Cancel");
592+
const response = await vscode.window.showErrorMessage(
593+
localize({
594+
key: "cl.exe.not.available",
595+
comment: ["{0} is a command option in a menu."]
596+
}, "{0} requires the Visual Studio Developer Environment.", `cl.exe ${this.buildAndDebugActiveFileStr()}`),
597+
applyDevEnv,
598+
cancel);
599+
if (response === applyDevEnv) {
600+
try {
601+
await vscode.commands.executeCommand('C_Cpp.SetDevEnvironment');
602+
} catch {
603+
// Ignore the error, the user will be prompted to apply the environment manually.
604+
}
605+
}
606+
if (util.hasMsvcEnvironment()) {
607+
return false;
608+
}
609+
void vscode.window.showErrorMessage(
610+
localize('dev.env.not.applied', 'The Visual Studio Developer Environment was not applied. Please try again or run VS Code from the Developer Command Prompt for VS.'));
591611
return true;
592612
}
593613
return false;
@@ -967,7 +987,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
967987
placeHolder: items.length === 0 ? localize("no.compiler.found", "No compiler found") : localize("select.debug.configuration", "Select a debug configuration")
968988
});
969989
}
970-
if (selection && this.isClConfiguration(selection.configuration.name) && this.showErrorIfClNotAvailable(selection.configuration.name)) {
990+
if (selection && this.isClConfiguration(selection.configuration.name) && await this.showErrorIfClNotAvailable(selection.configuration.name)) {
971991
return;
972992
}
973993
return selection?.configuration;

Extension/src/LanguageServer/cppBuildTaskProvider.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
import * as cp from "child_process";
77
import * as os from 'os';
88
import * as path from 'path';
9-
import { CustomExecution, Disposable, Event, EventEmitter, ProcessExecution, Pseudoterminal, ShellExecution, Task, TaskDefinition, TaskEndEvent, TaskExecution, TaskGroup, TaskProvider, tasks, TaskScope, TerminalDimensions, TextEditor, window, workspace, WorkspaceFolder } from 'vscode';
9+
import { CustomExecution, Disposable, EnvironmentVariableMutator, Event, EventEmitter, ProcessExecution, Pseudoterminal, ShellExecution, Task, TaskDefinition, TaskEndEvent, TaskExecution, TaskGroup, TaskProvider, tasks, TaskScope, TerminalDimensions, TextEditor, window, workspace, WorkspaceFolder } from 'vscode';
1010
import * as nls from 'vscode-nls';
1111
import * as util from '../common';
1212
import * as telemetry from '../telemetry';
1313
import { Client } from './client';
1414
import * as configs from './configurations';
15+
import { isEnvironmentOverrideApplied } from "./devcmd";
1516
import * as ext from './extension';
1617
import { OtherSettings } from './settings';
1718

@@ -430,6 +431,22 @@ class CustomBuildTaskTerminal implements Pseudoterminal {
430431
}
431432
}
432433

434+
if (isEnvironmentOverrideApplied(util.extensionContext)) {
435+
// If the user has applied the Developer Environment to this workspace, it should apply to all newly opened terminals.
436+
// However, this does not apply to processes that we spawn ourselves in the Pseudoterminal, so we need to specify the
437+
// correct environment in order to emulate the terminal behavior properly.
438+
const env = { ...process.env };
439+
util.extensionContext?.environmentVariableCollection.forEach((variable: string, mutator: EnvironmentVariableMutator) => {
440+
if (variable.toLowerCase() === "path") {
441+
// Path is special because it has a placeholder to insert the current Path into.
442+
env[variable] = util.resolveVariables(mutator.value);
443+
} else {
444+
env[variable] = mutator.value;
445+
}
446+
});
447+
this.options.env = env;
448+
}
449+
433450
const splitWriteEmitter = (lines: string | Buffer) => {
434451
const splitLines: string[] = lines.toString().split(/\r?\n/g);
435452
for (let i: number = 0; i < splitLines.length; i++) {

Extension/src/LanguageServer/devcmd.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ import { vcvars } from 'node-vcvarsall';
88
import { vswhere } from 'node-vswhere';
99
import * as path from 'path';
1010
import * as vscode from 'vscode';
11+
import { CppSettings } from './settings';
12+
13+
export function isEnvironmentOverrideApplied(context?: vscode.ExtensionContext) {
14+
return context?.environmentVariableCollection.get('VCToolsInstallDir') !== undefined;
15+
}
1116

1217
export async function setEnvironment(context?: vscode.ExtensionContext) {
1318
if (!context) {
@@ -42,14 +47,15 @@ export async function setEnvironment(context?: vscode.ExtensionContext) {
4247
host: match(host, { 'x86': 'x86', 'x64': 'x64' }) ?? 'x64',
4348
target: match(target, { 'x86': 'x86', 'x64': 'x64', 'arm64': 'ARM64', 'arm': 'ARM' }) ?? 'x64'
4449
});
45-
const persist = vscode.workspace.getConfiguration('devcmd').get<boolean>('persistEnvironment') === true;
50+
const settings = new CppSettings(vscode.workspace.workspaceFolders?.at(0)?.uri);
4651

4752
context.environmentVariableCollection.clear();
4853
for (const key of Object.keys(vars)) {
4954
context.environmentVariableCollection.replace(key, vars[key].replace(`%${key}%`, '${env:' + key + '}'));
5055
}
5156
context.environmentVariableCollection.description = (arch ? `${arch} ` : '') + 'Developer Command Prompt for ' + vs.displayName;
52-
context.environmentVariableCollection.persistent = persist;
57+
context.environmentVariableCollection.persistent = settings.persistDevEnvironment;
58+
5359
return true;
5460
}
5561

Extension/src/LanguageServer/extension.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,6 +1565,7 @@ async function showCopilotContent(copilotHoverProvider: CopilotHoverProvider, ho
15651565
async function onSetDevEnvironment(): Promise<void> {
15661566
try {
15671567
await setEnvironment(util.extensionContext);
1568+
await vscode.commands.executeCommand('setContext', 'cpptools.msvcEnvironmentFound', util.hasMsvcEnvironment());
15681569
void vscode.window.showInformationMessage(`${util.extensionContext?.environmentVariableCollection.description} successfully set.`);
15691570
} catch (error: any) {
15701571
void vscode.window.showErrorMessage(`Developer environment not set: ${error.message}`);
@@ -1573,4 +1574,5 @@ async function onSetDevEnvironment(): Promise<void> {
15731574

15741575
async function onClearDevEnvironment(): Promise<void> {
15751576
util.extensionContext?.environmentVariableCollection.clear();
1577+
await vscode.commands.executeCommand('setContext', 'cpptools.msvcEnvironmentFound', util.hasMsvcEnvironment());
15761578
}

Extension/src/LanguageServer/settings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ export class CppSettings extends Settings {
549549
&& this.intelliSenseEngine.toLowerCase() === "default" && vscode.workspace.getConfiguration("workbench").get<any>("colorTheme") !== "Default High Contrast";
550550
}
551551
public get sshTargetsView(): string { return this.getAsString("sshTargetsView"); }
552+
public get persistDevEnvironment(): boolean { return this.getAsBoolean("persistDevEnvironment"); }
552553

553554
// Returns the value of a setting as a string with proper type validation and checks for valid enum values while returning an undefined value if necessary.
554555
private getAsStringOrUndefined(settingName: string): string | undefined {

Extension/src/common.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1564,7 +1564,10 @@ export function hasMsvcEnvironment(): boolean {
15641564
'WindowsSDKLibVersion',
15651565
'WindowsSDKVersion'
15661566
];
1567-
return msvcEnvVars.every((envVarName) => process.env[envVarName] !== undefined && process.env[envVarName] !== '');
1567+
return msvcEnvVars.every(envVarName =>
1568+
(process.env[envVarName] !== undefined && process.env[envVarName] !== '') ||
1569+
extensionContext?.environmentVariableCollection?.get(envVarName) !== undefined
1570+
);
15681571
}
15691572

15701573
function isIntegral(str: string): boolean {
Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
<h1 data-loc-id="walkthrough.windows.title.open.dev.command.prompt">Relaunch using the <span>Developer Command Prompt for VS</span></h1>
2-
<p data-loc-id="walkthrough.windows.background.dev.command.prompt"> You are using a Windows machine with the MSVC compiler, so you need to start VS Code from the <span>Developer Command Prompt for VS</span> for all environment variables to be set correctly. To relaunch using the <span>Developer Command Prompt for VS</span>:</p>
2+
<p data-loc-id="walkthrough.windows.background.dev.command.prompt"> You are using a Windows machine with the MSVC compiler, so for all environment variables to be set correctly, you either need to:</p>
33
<ol>
4-
<li><p data-loc-id="walkthrough.open.command.prompt">Open the <span>Developer Command Prompt for VS</span> by typing "<span>developer</span>" in the Windows Start menu. Select the <span>Developer Command Prompt for VS</span>, which will automatically navigate to your current open folder.</p>
4+
<li><p data-loc-id="walkthrough.windows.start.from.dev.command">Start VS Code from the <span>Developer Command Prompt for VS.</span></p></li>
5+
<p data-loc-id="walkthrough.windows.or">- or -</p>
6+
<li><p data-loc-id="walkthrough.windows.run.dev.command">Run the <code>C/C++: Set Developer Environment</code> command.</p></span>
7+
</ol>
8+
<h4 data-loc-id="walkthrough.windows.relaunch.command.prompt">To relaunch using the <span>Developer Command Prompt for VS</span></h4>
9+
<ol>
10+
<li><p data-loc-id="walkthrough.open.command.prompt">Open the <span>Developer Command Prompt for VS</span> by typing <code>developer</code> in the Windows Start menu. Select the <span>Developer Command Prompt for VS</span>, which will automatically navigate to your current open folder.</p>
511
</li>
6-
<li><p data-loc-id="walkthrough.windows.press.f5">Type "<span>code</span>" into the command prompt and hit enter. This should relaunch VS Code and take you back to this walkthrough. </p>
12+
<li><p data-loc-id="walkthrough.windows.press.f5">Type <code>code</code> into the command prompt and hit enter. This should relaunch VS Code and take you back to this walkthrough. </p>
713
</li>

Extension/walkthrough/installcompiler/install-compiler-windows.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,8 @@
88
<p><strong data-loc-id="walkthrough.windows.note1">Note</strong>: <span data-loc-id="walkthrough.windows.note1.text">You can use the C++ toolset from Visual Studio Build Tools along with Visual Studio Code to compile, build, and verify any C++ codebase as long as you also have a valid Visual Studio license (either Community, Pro, or Enterprise) that you are actively using to develop that C++ codebase.</span></p>
99
</blockquote>
1010
</li>
11-
<li><p data-loc-id="walkthrough.windows.open.command.prompt">Open the <strong>Developer Command Prompt for VS</strong> by typing &#39;<code>developer</code>&#39; in the Windows Start menu.</p>
11+
<li><p data-loc-id="walkthrough.windows.open.command.prompt">Open the <strong>Developer Command Prompt for VS</strong> by typing <code>developer</code> in the Windows Start menu.</p>
1212
</li>
1313
<li><p data-loc-id="walkthrough.windows.check.install">Check your MSVC installation by typing <code>cl</code> into the <span>Developer Command Prompt for VS</span>. You should see a copyright message with the version and basic usage description.</p>
14-
<blockquote>
15-
<p><strong data-loc-id="walkthrough.windows.note2">Note</strong>: <span data-loc-id="walkthrough.windows.note2.text">To use MSVC from the command line or VS Code, you must run from a <strong>Developer Command Prompt for VS</strong>. An ordinary shell such as <span>PowerShell</span>, <span>Bash</span>, or the Windows command prompt does not have the necessary path environment variables set.</span></p>
16-
</blockquote>
1714
</li>
1815
</ol>

0 commit comments

Comments
 (0)