From 28e01c27557244d39cf84477e5d50dc2894ad636 Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Sat, 17 Jun 2023 22:26:45 +0200
Subject: [PATCH] Setup msvc environment on Windows
---
packed/index.js | 297 +++++++++++++++++++++++++++++++++++++++++++++---
src/main.ts | 8 ++
src/msvc.ts | 294 +++++++++++++++++++++++++++++++++++++++++++++++
src/ninja.ts | 11 +-
src/platform.ts | 13 ---
5 files changed, 588 insertions(+), 35 deletions(-)
create mode 100644 src/msvc.ts
diff --git a/packed/index.js b/packed/index.js
index c6ffc3f91af6..9e6b4964858f 100644
--- a/packed/index.js
+++ b/packed/index.js
@@ -85,6 +85,7 @@ const child_process = __importStar(__nccwpck_require__(2081));
const fs = __importStar(__nccwpck_require__(7147));
const core = __importStar(__nccwpck_require__(2186));
const constants_1 = __nccwpck_require__(7077);
+const msvc_1 = __nccwpck_require__(1983);
const ninja_1 = __nccwpck_require__(6526);
const util_1 = __nccwpck_require__(9731);
const version_1 = __nccwpck_require__(6970);
@@ -184,6 +185,11 @@ async function run() {
await (0, ninja_1.configure_ninja_build_tool)(SDL_BUILD_PLATFORM);
});
}
+ if (SDL_BUILD_PLATFORM == platform_1.SdlBuildPlatform.Windows) {
+ await core.group(`Configuring VS environment`, async () => {
+ (0, msvc_1.setup_vc_environment)();
+ });
+ }
const source_dir = `${SETUP_SDL_ROOT}/src`;
const build_dir = `${SETUP_SDL_ROOT}/build`;
const install_dir = `${SETUP_SDL_ROOT}`;
@@ -198,6 +204,280 @@ async function run() {
run();
+/***/ }),
+
+/***/ 1983:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+// Copyright 2019 ilammy
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+// the Software, and to permit persons to whom the Software is furnished to do so,
+// subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.setup_vc_environment = void 0;
+const child_process = __importStar(__nccwpck_require__(2081));
+const fs = __importStar(__nccwpck_require__(7147));
+const path = __importStar(__nccwpck_require__(1017));
+const process = __importStar(__nccwpck_require__(7282));
+const core = __importStar(__nccwpck_require__(2186));
+const util_1 = __nccwpck_require__(9731);
+const PROGRAM_FILES_X86 = process.env["ProgramFiles(x86)"];
+const PROGRAM_FILES = [
+ process.env["ProgramFiles(x86)"],
+ process.env["ProgramFiles"],
+];
+const EDITIONS = ["Enterprise", "Professional", "Community"];
+const YEARS = ["2022", "2019", "2017"];
+const VsYearVersion = {
+ "2022": "17.0",
+ "2019": "16.0",
+ "2017": "15.0",
+ "2015": "14.0",
+ "2013": "12.0",
+};
+const VSWHERE_PATH = `${PROGRAM_FILES_X86}\\Microsoft Visual Studio\\Installer`;
+function vsversion_to_versionnumber(vsversion) {
+ if (Object.values(VsYearVersion).includes(vsversion)) {
+ return vsversion;
+ }
+ else {
+ if (vsversion in VsYearVersion) {
+ return VsYearVersion[vsversion];
+ }
+ }
+ return vsversion;
+}
+function vsversion_to_year(vsversion) {
+ if (Object.keys(VsYearVersion).includes(vsversion)) {
+ return vsversion;
+ }
+ else {
+ for (const [year, ver] of Object.entries(VsYearVersion)) {
+ if (ver === vsversion) {
+ return year;
+ }
+ }
+ }
+ return vsversion;
+}
+function findWithVswhere(pattern, version_pattern) {
+ try {
+ const installationPath = child_process
+ .execSync(`vswhere -products * ${version_pattern} -prerelease -property installationPath`)
+ .toString()
+ .trim();
+ return `${installationPath}\\\\${pattern}`;
+ }
+ catch (e) {
+ core.warning(`vswhere failed: ${e}`);
+ }
+ return null;
+}
+function findVcvarsall(vsversion) {
+ const vsversion_number = vsversion_to_versionnumber(vsversion);
+ let version_pattern;
+ if (vsversion_number) {
+ const upper_bound = vsversion_number.split(".")[0] + ".9";
+ version_pattern = `-version "${vsversion_number},${upper_bound}"`;
+ }
+ else {
+ version_pattern = "-latest";
+ }
+ // If vswhere is available, ask it about the location of the latest Visual Studio.
+ let path = findWithVswhere("VC\\Auxiliary\\Build\\vcvarsall.bat", version_pattern);
+ if (path && fs.existsSync(path)) {
+ core.info(`Found with vswhere: ${path}`);
+ return path;
+ }
+ core.info("Not found with vswhere");
+ // If that does not work, try the standard installation locations,
+ // starting with the latest and moving to the oldest.
+ const years = vsversion ? [vsversion_to_year(vsversion)] : YEARS;
+ for (const prog_files of PROGRAM_FILES) {
+ for (const ver of years) {
+ for (const ed of EDITIONS) {
+ path = `${prog_files}\\Microsoft Visual Studio\\${ver}\\${ed}\\VC\\Auxiliary\\Build\\vcvarsall.bat`;
+ core.info(`Trying standard location: ${path}`);
+ if (fs.existsSync(path)) {
+ core.info(`Found standard location: ${path}`);
+ return path;
+ }
+ }
+ }
+ }
+ core.info("Not found in standard locations");
+ // Special case for Visual Studio 2015 (and maybe earlier), try it out too.
+ path = `${PROGRAM_FILES_X86}\\Microsoft Visual C++ Build Tools\\vcbuildtools.bat`;
+ if (fs.existsSync(path)) {
+ core.info(`Found VS 2015: ${path}`);
+ return path;
+ }
+ core.info(`Not found in VS 2015 location: ${path}`);
+ throw new util_1.SetupSdlError("Microsoft Visual Studio not found");
+}
+function isPathVariable(name) {
+ const pathLikeVariables = ["PATH", "INCLUDE", "LIB", "LIBPATH"];
+ return pathLikeVariables.indexOf(name.toUpperCase()) != -1;
+}
+function filterPathValue(path) {
+ const paths = path.split(";");
+ // Remove duplicates by keeping the first occurrence and preserving order.
+ // This keeps path shadowing working as intended.
+ function unique(value, index, self) {
+ return self.indexOf(value) === index;
+ }
+ return paths.filter(unique).join(";");
+}
+/** See https://github.com/ilammy/msvc-dev-cmd#inputs */
+function setupMSVCDevCmd(arch, sdk, toolset, uwp, spectre, vsversion) {
+ if (process.platform != "win32") {
+ core.info("This is not a Windows virtual environment, bye!");
+ return;
+ }
+ // Add standard location of "vswhere" to PATH, in case it"s not there.
+ process.env.PATH += path.delimiter + VSWHERE_PATH;
+ // There are all sorts of way the architectures are called. In addition to
+ // values supported by Microsoft Visual C++, recognize some common aliases.
+ const arch_aliases = {
+ win32: "x86",
+ win64: "x64",
+ x86_64: "x64",
+ "x86-64": "x64",
+ };
+ // Ignore case when matching as that"s what humans expect.
+ if (arch.toLowerCase() in arch_aliases) {
+ arch = arch_aliases[arch.toLowerCase()];
+ }
+ // Due to the way Microsoft Visual C++ is configured, we have to resort to the following hack:
+ // Call the configuration batch file and then output *all* the environment variables.
+ const args = [arch];
+ if (uwp) {
+ args.push("uwp");
+ }
+ if (sdk) {
+ args.push(sdk);
+ }
+ if (toolset) {
+ args.push(`-vcvars_ver=${toolset}`);
+ }
+ if (spectre) {
+ args.push("-vcvars_spectre_libs=spectre");
+ }
+ const vcvars = `"${findVcvarsall(vsversion)}" ${args.join(" ")}`;
+ core.debug(`vcvars command-line: ${vcvars}`);
+ const cmd_output_string = child_process
+ .execSync(`set && cls && ${vcvars} && cls && set`, { shell: "cmd" })
+ .toString();
+ const cmd_output_parts = cmd_output_string.split("\f");
+ const old_environment = cmd_output_parts[0].split("\r\n");
+ const vcvars_output = cmd_output_parts[1].split("\r\n");
+ const new_environment = cmd_output_parts[2].split("\r\n");
+ // If vsvars.bat is given an incorrect command line, it will print out
+ // an error and *still* exit successfully. Parse out errors from output
+ // which don"t look like environment variables, and fail if appropriate.
+ const error_messages = vcvars_output.filter((line) => {
+ if (line.match(/^\[ERROR.*\]/)) {
+ // Don"t print this particular line which will be confusing in output.
+ if (!line.match(/Error in script usage. The correct usage is:$/)) {
+ return true;
+ }
+ }
+ return false;
+ });
+ if (error_messages.length > 0) {
+ throw new Error("invalid parameters" + "\r\n" + error_messages.join("\r\n"));
+ }
+ const result_vcvars = {};
+ // Convert old environment lines into a dictionary for easier lookup.
+ const old_env_vars = {};
+ for (const string of old_environment) {
+ const [name, value] = string.split("=");
+ old_env_vars[name] = value;
+ }
+ // Now look at the new environment and export everything that changed.
+ // These are the variables set by vsvars.bat. Also export everything
+ // that was not there during the first sweep: those are new variables.
+ core.startGroup("Environment variables");
+ for (const string of new_environment) {
+ const [key, vcvars_value] = string.split("=");
+ // vsvars.bat likes to print some fluff at the beginning.
+ // Skip lines that don"t look like environment variables.
+ if (!vcvars_value) {
+ continue;
+ }
+ const old_value = old_env_vars[key];
+ // For new variables "old_value === undefined".
+ if (vcvars_value !== old_value) {
+ let filtered_value = vcvars_value;
+ core.info(`Setting ${key}`);
+ // Special case for a bunch of PATH-like variables: vcvarsall.bat
+ // just prepends its stuff without checking if its already there.
+ // This makes repeated invocations of this action fail after some
+ // point, when the environment variable overflows. Avoid that.
+ if (isPathVariable(key)) {
+ filtered_value = filterPathValue(vcvars_value);
+ }
+ result_vcvars[key] = filtered_value;
+ }
+ }
+ core.endGroup();
+ core.info("Configured Developer Command Prompt");
+ return result_vcvars;
+}
+function setup_vc_environment() {
+ const arch = core.getInput("vc_arch");
+ const sdk = core.getInput("vc_sdk");
+ const toolset = core.getBooleanInput("vc_toolset");
+ const uwp = core.getBooleanInput("vc_uwp");
+ const spectre = core.getBooleanInput("vc_spectre");
+ const vsversion = core.getInput("vc_vsversion");
+ const msvc_env_vars = setupMSVCDevCmd(arch, sdk, toolset, uwp, spectre, vsversion);
+ for (const key in msvc_env_vars) {
+ process.env[key] = msvc_env_vars[key];
+ }
+}
+exports.setup_vc_environment = setup_vc_environment;
+
+
/***/ }),
/***/ 6526:
@@ -231,6 +511,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.configure_ninja_build_tool = exports.get_ninja_download_url = void 0;
const fs = __importStar(__nccwpck_require__(7147));
+const path = __importStar(__nccwpck_require__(1017));
const process = __importStar(__nccwpck_require__(7282));
const core = __importStar(__nccwpck_require__(2186));
const tc = __importStar(__nccwpck_require__(7784));
@@ -266,8 +547,7 @@ async function configure_ninja_build_tool(platform) {
const ninja_extract_folder = await tc.extractZip(ninja_zip_path, ninja_dir);
ninja_directory = await tc.cacheDir(ninja_extract_folder, cache_name, constants_1.NINJA_VERSION);
}
- const path_env_sep = (0, platform_1.get_platform_path_env_separator)(platform);
- process.env.PATH = ninja_directory + path_env_sep + process.env.PATH;
+ process.env.PATH = ninja_directory + path.delimiter + process.env.PATH;
}
exports.configure_ninja_build_tool = configure_ninja_build_tool;
@@ -303,7 +583,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.get_platform_root_directory = exports.get_platform_path_env_separator = exports.get_sdl_build_platform = exports.SdlBuildPlatform = void 0;
+exports.get_platform_root_directory = exports.get_sdl_build_platform = exports.SdlBuildPlatform = void 0;
const os = __importStar(__nccwpck_require__(2037));
const core = __importStar(__nccwpck_require__(2186));
const util_1 = __nccwpck_require__(9731);
@@ -325,17 +605,6 @@ function get_sdl_build_platform() {
throw new util_1.SetupSdlError("Unsupported build platform");
}
exports.get_sdl_build_platform = get_sdl_build_platform;
-function get_platform_path_env_separator(platform) {
- switch (platform) {
- case SdlBuildPlatform.Windows:
- return ";";
- case SdlBuildPlatform.Macos:
- case SdlBuildPlatform.Linux:
- default:
- return ":";
- }
-}
-exports.get_platform_path_env_separator = get_platform_path_env_separator;
function get_platform_root_directory(platform) {
const root = core.getInput("root");
if (root) {
diff --git a/src/main.ts b/src/main.ts
index 9b863567a17e..46bb4bfcb92d 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -4,6 +4,7 @@ import * as fs from "fs";
import * as core from "@actions/core";
import { SDL_GIT_URL } from "./constants";
+import { setup_vc_environment } from "./msvc";
import { configure_ninja_build_tool } from "./ninja";
import { SetupSdlError } from "./util";
@@ -16,6 +17,7 @@ import {
import {
get_sdl_build_platform,
get_platform_root_directory,
+ SdlBuildPlatform,
} from "./platform";
async function convert_git_branch_tag_to_hash(
@@ -158,6 +160,12 @@ async function run() {
});
}
+ if (SDL_BUILD_PLATFORM == SdlBuildPlatform.Windows) {
+ await core.group(`Configuring VS environment`, async () => {
+ setup_vc_environment();
+ });
+ }
+
const source_dir = `${SETUP_SDL_ROOT}/src`;
const build_dir = `${SETUP_SDL_ROOT}/build`;
const install_dir = `${SETUP_SDL_ROOT}`;
diff --git a/src/msvc.ts b/src/msvc.ts
new file mode 100644
index 000000000000..0e00fd5fed29
--- /dev/null
+++ b/src/msvc.ts
@@ -0,0 +1,294 @@
+// Copyright 2019 ilammy
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+// the Software, and to permit persons to whom the Software is furnished to do so,
+// subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import * as child_process from "child_process";
+import * as fs from "fs";
+import * as path from "path";
+import * as process from "process";
+
+import * as core from "@actions/core";
+
+import { SetupSdlError } from "./util";
+
+const PROGRAM_FILES_X86 = process.env["ProgramFiles(x86)"];
+const PROGRAM_FILES = [
+ process.env["ProgramFiles(x86)"],
+ process.env["ProgramFiles"],
+];
+
+const EDITIONS = ["Enterprise", "Professional", "Community"];
+const YEARS = ["2022", "2019", "2017"];
+
+const VsYearVersion: { [key: string]: string } = {
+ "2022": "17.0",
+ "2019": "16.0",
+ "2017": "15.0",
+ "2015": "14.0",
+ "2013": "12.0",
+};
+
+const VSWHERE_PATH = `${PROGRAM_FILES_X86}\\Microsoft Visual Studio\\Installer`;
+
+function vsversion_to_versionnumber(vsversion: string): string {
+ if (Object.values(VsYearVersion).includes(vsversion)) {
+ return vsversion;
+ } else {
+ if (vsversion in VsYearVersion) {
+ return VsYearVersion[vsversion];
+ }
+ }
+ return vsversion;
+}
+
+function vsversion_to_year(vsversion: string): string {
+ if (Object.keys(VsYearVersion).includes(vsversion)) {
+ return vsversion;
+ } else {
+ for (const [year, ver] of Object.entries(VsYearVersion)) {
+ if (ver === vsversion) {
+ return year;
+ }
+ }
+ }
+ return vsversion;
+}
+
+function findWithVswhere(
+ pattern: string,
+ version_pattern: string
+): string | null {
+ try {
+ const installationPath = child_process
+ .execSync(
+ `vswhere -products * ${version_pattern} -prerelease -property installationPath`
+ )
+ .toString()
+ .trim();
+ return `${installationPath}\\\\${pattern}`;
+ } catch (e) {
+ core.warning(`vswhere failed: ${e}`);
+ }
+ return null;
+}
+
+function findVcvarsall(vsversion: string): string {
+ const vsversion_number = vsversion_to_versionnumber(vsversion);
+ let version_pattern;
+ if (vsversion_number) {
+ const upper_bound = vsversion_number.split(".")[0] + ".9";
+ version_pattern = `-version "${vsversion_number},${upper_bound}"`;
+ } else {
+ version_pattern = "-latest";
+ }
+
+ // If vswhere is available, ask it about the location of the latest Visual Studio.
+ let path = findWithVswhere(
+ "VC\\Auxiliary\\Build\\vcvarsall.bat",
+ version_pattern
+ );
+ if (path && fs.existsSync(path)) {
+ core.info(`Found with vswhere: ${path}`);
+ return path;
+ }
+ core.info("Not found with vswhere");
+
+ // If that does not work, try the standard installation locations,
+ // starting with the latest and moving to the oldest.
+ const years = vsversion ? [vsversion_to_year(vsversion)] : YEARS;
+ for (const prog_files of PROGRAM_FILES) {
+ for (const ver of years) {
+ for (const ed of EDITIONS) {
+ path = `${prog_files}\\Microsoft Visual Studio\\${ver}\\${ed}\\VC\\Auxiliary\\Build\\vcvarsall.bat`;
+ core.info(`Trying standard location: ${path}`);
+ if (fs.existsSync(path)) {
+ core.info(`Found standard location: ${path}`);
+ return path;
+ }
+ }
+ }
+ }
+ core.info("Not found in standard locations");
+
+ // Special case for Visual Studio 2015 (and maybe earlier), try it out too.
+ path = `${PROGRAM_FILES_X86}\\Microsoft Visual C++ Build Tools\\vcbuildtools.bat`;
+ if (fs.existsSync(path)) {
+ core.info(`Found VS 2015: ${path}`);
+ return path;
+ }
+ core.info(`Not found in VS 2015 location: ${path}`);
+
+ throw new SetupSdlError("Microsoft Visual Studio not found");
+}
+
+function isPathVariable(name: string): boolean {
+ const pathLikeVariables = ["PATH", "INCLUDE", "LIB", "LIBPATH"];
+ return pathLikeVariables.indexOf(name.toUpperCase()) != -1;
+}
+
+function filterPathValue(path: string): string {
+ const paths = path.split(";");
+ // Remove duplicates by keeping the first occurrence and preserving order.
+ // This keeps path shadowing working as intended.
+ function unique(value: string, index: number, self: string[]): boolean {
+ return self.indexOf(value) === index;
+ }
+ return paths.filter(unique).join(";");
+}
+
+/** See https://github.com/ilammy/msvc-dev-cmd#inputs */
+function setupMSVCDevCmd(
+ arch: string,
+ sdk: string,
+ toolset: boolean,
+ uwp: boolean,
+ spectre: boolean,
+ vsversion: string
+) {
+ if (process.platform != "win32") {
+ core.info("This is not a Windows virtual environment, bye!");
+ return;
+ }
+
+ // Add standard location of "vswhere" to PATH, in case it"s not there.
+ process.env.PATH += path.delimiter + VSWHERE_PATH;
+
+ // There are all sorts of way the architectures are called. In addition to
+ // values supported by Microsoft Visual C++, recognize some common aliases.
+ const arch_aliases: { [key: string]: string } = {
+ win32: "x86",
+ win64: "x64",
+ x86_64: "x64",
+ "x86-64": "x64",
+ };
+ // Ignore case when matching as that"s what humans expect.
+ if (arch.toLowerCase() in arch_aliases) {
+ arch = arch_aliases[arch.toLowerCase()];
+ }
+
+ // Due to the way Microsoft Visual C++ is configured, we have to resort to the following hack:
+ // Call the configuration batch file and then output *all* the environment variables.
+
+ const args = [arch];
+ if (uwp) {
+ args.push("uwp");
+ }
+ if (sdk) {
+ args.push(sdk);
+ }
+ if (toolset) {
+ args.push(`-vcvars_ver=${toolset}`);
+ }
+ if (spectre) {
+ args.push("-vcvars_spectre_libs=spectre");
+ }
+
+ const vcvars = `"${findVcvarsall(vsversion)}" ${args.join(" ")}`;
+ core.debug(`vcvars command-line: ${vcvars}`);
+
+ const cmd_output_string = child_process
+ .execSync(`set && cls && ${vcvars} && cls && set`, { shell: "cmd" })
+ .toString();
+ const cmd_output_parts = cmd_output_string.split("\f");
+
+ const old_environment = cmd_output_parts[0].split("\r\n");
+ const vcvars_output = cmd_output_parts[1].split("\r\n");
+ const new_environment = cmd_output_parts[2].split("\r\n");
+
+ // If vsvars.bat is given an incorrect command line, it will print out
+ // an error and *still* exit successfully. Parse out errors from output
+ // which don"t look like environment variables, and fail if appropriate.
+ const error_messages = vcvars_output.filter((line) => {
+ if (line.match(/^\[ERROR.*\]/)) {
+ // Don"t print this particular line which will be confusing in output.
+ if (!line.match(/Error in script usage. The correct usage is:$/)) {
+ return true;
+ }
+ }
+ return false;
+ });
+ if (error_messages.length > 0) {
+ throw new Error(
+ "invalid parameters" + "\r\n" + error_messages.join("\r\n")
+ );
+ }
+
+ const result_vcvars: { [key: string]: string } = {};
+
+ // Convert old environment lines into a dictionary for easier lookup.
+ const old_env_vars: { [key: string]: string } = {};
+ for (const string of old_environment) {
+ const [name, value] = string.split("=");
+ old_env_vars[name] = value;
+ }
+
+ // Now look at the new environment and export everything that changed.
+ // These are the variables set by vsvars.bat. Also export everything
+ // that was not there during the first sweep: those are new variables.
+ core.startGroup("Environment variables");
+ for (const string of new_environment) {
+ const [key, vcvars_value] = string.split("=");
+ // vsvars.bat likes to print some fluff at the beginning.
+ // Skip lines that don"t look like environment variables.
+ if (!vcvars_value) {
+ continue;
+ }
+ const old_value = old_env_vars[key];
+ // For new variables "old_value === undefined".
+ if (vcvars_value !== old_value) {
+ let filtered_value = vcvars_value;
+ core.info(`Setting ${key}`);
+ // Special case for a bunch of PATH-like variables: vcvarsall.bat
+ // just prepends its stuff without checking if its already there.
+ // This makes repeated invocations of this action fail after some
+ // point, when the environment variable overflows. Avoid that.
+ if (isPathVariable(key)) {
+ filtered_value = filterPathValue(vcvars_value);
+ }
+
+ result_vcvars[key] = filtered_value;
+ }
+ }
+ core.endGroup();
+
+ core.info("Configured Developer Command Prompt");
+
+ return result_vcvars;
+}
+
+export function setup_vc_environment() {
+ const arch = core.getInput("vc_arch");
+ const sdk = core.getInput("vc_sdk");
+ const toolset = core.getBooleanInput("vc_toolset");
+ const uwp = core.getBooleanInput("vc_uwp");
+ const spectre = core.getBooleanInput("vc_spectre");
+ const vsversion = core.getInput("vc_vsversion");
+
+ const msvc_env_vars = setupMSVCDevCmd(
+ arch,
+ sdk,
+ toolset,
+ uwp,
+ spectre,
+ vsversion
+ );
+
+ for (const key in msvc_env_vars) {
+ process.env[key] = msvc_env_vars[key];
+ }
+}
diff --git a/src/ninja.ts b/src/ninja.ts
index 49f18672ffd7..3a89ae1cb404 100644
--- a/src/ninja.ts
+++ b/src/ninja.ts
@@ -1,15 +1,12 @@
import * as fs from "fs";
+import * as path from "path";
import * as process from "process";
import * as core from "@actions/core";
import * as tc from "@actions/tool-cache";
import { NINJA_VERSION } from "./constants";
-import {
- SdlBuildPlatform,
- get_platform_root_directory,
- get_platform_path_env_separator,
-} from "./platform";
+import { SdlBuildPlatform, get_platform_root_directory } from "./platform";
export function get_ninja_download_url(
platform: SdlBuildPlatform,
@@ -53,7 +50,5 @@ export async function configure_ninja_build_tool(platform: SdlBuildPlatform) {
);
}
- const path_env_sep = get_platform_path_env_separator(platform);
-
- process.env.PATH = ninja_directory + path_env_sep + process.env.PATH;
+ process.env.PATH = ninja_directory + path.delimiter + process.env.PATH;
}
diff --git a/src/platform.ts b/src/platform.ts
index 88813d89ceb7..9a2dc2720901 100644
--- a/src/platform.ts
+++ b/src/platform.ts
@@ -21,19 +21,6 @@ export function get_sdl_build_platform(): SdlBuildPlatform {
throw new SetupSdlError("Unsupported build platform");
}
-export function get_platform_path_env_separator(
- platform: SdlBuildPlatform
-): string {
- switch (platform) {
- case SdlBuildPlatform.Windows:
- return ";";
- case SdlBuildPlatform.Macos:
- case SdlBuildPlatform.Linux:
- default:
- return ":";
- }
-}
-
export function get_platform_root_directory(
platform: SdlBuildPlatform
): string {