async function expandConfigurePresetHelper()

in src/preset.ts [851:996]


async function expandConfigurePresetHelper(folder: string,
    preset: ConfigurePreset,
    workspaceFolder: string,
    sourceDir: string,
    allowUserPreset: boolean = false) {
    if (preset.__expanded) {
        return preset;
    }

    const refs = referencedConfigurePresets.get(folder)!;

    if (refs.has(preset.name) && !preset.__expanded) {
        // Referenced this preset before, but it still hasn't been expanded. So this is a circular inheritance.
        log.error(localize('circular.inherits.in.config.preset', 'Circular inherits in configure preset {0}', preset.name));
        return null;
    }

    refs.add(preset.name);

    // Init env and cacheVar to empty if not specified to avoid null checks later
    if (!preset.environment) {
        preset.environment = EnvironmentUtils.createPreserveNull();
    }
    if (!preset.cacheVariables) {
        preset.cacheVariables = {};
    }

    // Expand inherits
    let inheritedEnv = EnvironmentUtils.createPreserveNull();
    if (preset.inherits) {
        if (util.isString(preset.inherits)) {
            preset.inherits = [preset.inherits];
        }
        for (const parentName of preset.inherits) {
            const parent = await expandConfigurePresetImpl(folder, parentName, workspaceFolder, sourceDir, allowUserPreset);
            if (parent) {
                // Inherit environment
                inheritedEnv = EnvironmentUtils.mergePreserveNull([parent.environment, inheritedEnv]);
                // Inherit cache vars
                for (const name in parent.cacheVariables) {
                    if (preset.cacheVariables[name] === undefined) {
                        preset.cacheVariables[name] = parent.cacheVariables[name];
                    }
                }
                // Inherit other fields
                let key: keyof ConfigurePreset;
                for (key in parent) {
                    if (isInheritable(key) && preset[key] === undefined) {
                        // 'as never' to bypass type check
                        preset[key] = parent[key] as never;
                    }
                }
            }
        }
    }

    inheritedEnv = EnvironmentUtils.mergePreserveNull([process.env, inheritedEnv]);

    let compilerEnv = EnvironmentUtils.createPreserveNull();

    // [Windows Only] If CMAKE_CXX_COMPILER or CMAKE_C_COMPILER is set as cl, clang, clang-cl, clang-cpp and clang++,
    // but they are not on PATH, then set the env automatically.
    if (process.platform === 'win32') {
        const getStringValueFromCacheVar = (variable?: CacheVarType) => {
            if (util.isString(variable)) {
                return variable;
            } else if (variable && typeof variable === 'object') {
                return util.isString(variable.value) ? variable.value : null;
            }
            return null;
        };
        if (preset.cacheVariables) {
            const cxxCompiler = getStringValueFromCacheVar(preset.cacheVariables['CMAKE_CXX_COMPILER'])?.toLowerCase();
            const cCompiler = getStringValueFromCacheVar(preset.cacheVariables['CMAKE_C_COMPILER'])?.toLowerCase();
            // The env variables for the supported compilers are the same.
            const compilerName: string | undefined = util.isSupportedCompiler(cxxCompiler) || util.isSupportedCompiler(cCompiler);
            if (compilerName) {
                const compilerLocation = await execute('where.exe', [compilerName], null, {
                    environment: EnvironmentUtils.create(preset.environment),
                    silent: true,
                    encoding: 'utf8',
                    shell: true
                }).result;
                if (!compilerLocation.stdout) {
                    // Not on PATH, need to set env
                    const arch = getArchitecture(preset);
                    const toolset = getToolset(preset);

                    // Get version info for all VS instances. Create a map so we don't need to
                    // iterate through the array every time.
                    const vsVersions = new Map<string, string>();
                    for (const vs of await vsInstallations()) {
                        vsVersions.set(vs.instanceId, vs.installationVersion);
                    }
                    let latestVsVersion: string = '';
                    let latestVsIndex = -1;
                    for (let i = 0; i < kits.length; i++) {
                        const kit = kits[i];
                        if (kit.visualStudio && !kit.compilers) {
                            const version = vsVersions.get(kit.visualStudio);
                            if (kit.preferredGenerator && targetArchFromGeneratorPlatform(kit.preferredGenerator.platform) === arch &&
                                (kit.visualStudioArchitecture === toolset.host || kit.preferredGenerator.toolset === ('host=' + toolset.host))) {
                                if (toolset.version && version?.startsWith(toolset.version)) {
                                    latestVsVersion = version;
                                    latestVsIndex = i;
                                    break;
                                }
                                if (!toolset.version && version && compareVersions(latestVsVersion, version) < 0) {
                                    latestVsVersion = version;
                                    latestVsIndex = i;
                                }
                            }
                        }
                    }
                    if (latestVsIndex < 0) {
                        log.error(localize('specified.cl.not.found',
                            "Configure preset {0}: Compiler {1} with toolset {2} and architecture {3} was not found, you may need to run the 'CMake: Scan for Compilers' command if this toolset exists on your computer.",
                            preset.name, `"${compilerName}.exe"`, toolset.version ? `"${toolset.version},${toolset.host}"` : `"${toolset.host}"`, `"${arch}"`));
                    } else {
                        compilerEnv = await effectiveKitEnvironment(kits[latestVsIndex]);
                        // if ninja isn't on path, try to look for it in a VS install
                        const ninjaLoc = await execute('where.exe', ['ninja'], null, {
                            environment: EnvironmentUtils.create(preset.environment),
                            silent: true,
                            encoding: 'utf8',
                            shell: true
                        }).result;
                        if (!ninjaLoc.stdout) {
                            const vsCMakePaths = await paths.vsCMakePaths(kits[latestVsIndex].visualStudio);
                            if (vsCMakePaths.ninja) {
                                log.warning(localize('ninja.not.set', 'Ninja is not set on PATH, trying to use {0}', vsCMakePaths.ninja));
                                compilerEnv['PATH'] = `${path.dirname(vsCMakePaths.ninja)};${compilerEnv['PATH']}`;
                            }
                        }
                    }
                }
            }
        }
    }

    compilerEnv = EnvironmentUtils.mergePreserveNull([inheritedEnv, compilerEnv]);
    preset.environment = EnvironmentUtils.mergePreserveNull([compilerEnv, preset.environment]);

    preset.__expanded = true;
    return preset;
}