Detection of Clang for MSVC (GNU CLI) kits (#940)

* Clang: Use environment variable LLVM_ROOT when scanning for kits

* Clang: Create kits for bundled LLVM in MSVC

* Add creation of Clang for MSVC (GNU CLI) kits

* Fixes and cleanup

* Better Clang kit name string

* Fixed the build after the merge

* Fix explosion of VS bundled Clang kits when more VS are installed

* More merge aftermath

* Fix typo

* Removed unused import

* Ensure unique name for windows clang installations, 32/64bit but independent of Visual Studio

Co-authored-by: Bob Brown <bobbrow@users.noreply.github.com>
Co-authored-by: Andreea Isac <andris@microsoft.com>
Co-authored-by: Andreea Isac <48239328+andreeis@users.noreply.github.com>
This commit is contained in:
Zingam 2020-10-12 15:00:15 +03:00 коммит произвёл GitHub
Родитель aa254ef872
Коммит 285bd4d07b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
34 изменённых файлов: 224 добавлений и 115 удалений

Просмотреть файл

@ -29,7 +29,7 @@
"detected.kit.for.version": "已检测到适用于版本的 VsKit",
"generator.present": "存在生成器: {0}",
"selected.preferred.generator.name": "已选择首选生成器名称: {0} {1}",
"clang.for.msvc": "用于 MSVC 的 Clang {0},具有 {1} ({2})",
"clang.for.msvc": "用于 MSVC 的 Clang {0}{1},具有 {2} ({3})",
"scanning.for.kits.on.system": "正在系统上扫描工具包",
"scanning.for.kits": "正在扫描工具包",
"scanning.for.cmake.kits": "正在扫描 CMake 工具包...",

Просмотреть файл

@ -29,7 +29,7 @@
"detected.kit.for.version": "已偵測到 VsKit 的版本",
"generator.present": "產生器已存在: {0}",
"selected.preferred.generator.name": "已選取慣用產生器名稱: {0} {1}",
"clang.for.msvc": "適用於 {1} ({2}) 中 MSVC 的 Clang {0}",
"clang.for.msvc": "適用於 {2} ({3}) 中 MSVC 的 Clang {0}{1}",
"scanning.for.kits.on.system": "正在掃描系統上的套件",
"scanning.for.kits": "正在掃描套件",
"scanning.for.cmake.kits": "正在掃描 CMake 套件...",

Просмотреть файл

@ -29,7 +29,7 @@
"detected.kit.for.version": "Zjištěna sada VsKit pro verzi",
"generator.present": "Generátor je přítomen: {0}",
"selected.preferred.generator.name": "Název vybraného upřednostňovaného generátoru: {0} {1}",
"clang.for.msvc": "Clang {0} pro MSVC s {1} ({2})",
"clang.for.msvc": "Clang {0}{1} pro MSVC s {2} ({3})",
"scanning.for.kits.on.system": "Hledají se sady v systému.",
"scanning.for.kits": "Hledají se sady.",
"scanning.for.cmake.kits": "Hledají se sady CMake...",

Просмотреть файл

@ -29,7 +29,7 @@
"detected.kit.for.version": "Erkanntes VsKit für Version",
"generator.present": "Generator vorhanden: {0}",
"selected.preferred.generator.name": "Ausgewählter bevorzugter Generatorname: {0} {1}",
"clang.for.msvc": "Clang {0} für MSVC mit {1} ({2})",
"clang.for.msvc": "Clang {0}{1} für MSVC mit {2} ({3})",
"scanning.for.kits.on.system": "Es wird nach Kits auf dem System gesucht.",
"scanning.for.kits": "Es wird nach Kits gesucht.",
"scanning.for.cmake.kits": "Es wird nach CMake-Kits gesucht...",

Просмотреть файл

@ -29,7 +29,7 @@
"detected.kit.for.version": "VsKit detectado para la versión",
"generator.present": "Generador presente: {0}",
"selected.preferred.generator.name": "Nombre de generador preferido seleccionado: {0} {1}",
"clang.for.msvc": "Clang {0} para MSVC con {1} ({2})",
"clang.for.msvc": "Clang {0}{1} para MSVC con {2} ({3})",
"scanning.for.kits.on.system": "Buscando kits en el sistema",
"scanning.for.kits": "Buscando kits",
"scanning.for.cmake.kits": "Examinando los kits de CMake...",

Просмотреть файл

@ -29,7 +29,7 @@
"detected.kit.for.version": "VsKit détecté pour la version",
"generator.present": "Générateur présent : {0}",
"selected.preferred.generator.name": "Nom du générateur par défaut sélectionné : {0} {1}",
"clang.for.msvc": "Clang {0} pour MSVC avec {1} ({2})",
"clang.for.msvc": "Clang {0}{1} pour MSVC avec {2} ({3})",
"scanning.for.kits.on.system": "Recherche de kits sur le système",
"scanning.for.kits": "Recherche de kits",
"scanning.for.cmake.kits": "Recherche de kits CMake...",

Просмотреть файл

@ -29,7 +29,7 @@
"detected.kit.for.version": "Rilevato kit di Visual Studio per la versione",
"generator.present": "Generatore presente: {0}",
"selected.preferred.generator.name": "Nome del generatore preferito selezionato: {0} {1}",
"clang.for.msvc": "Clang {0} per MSVC con {1} ({2})",
"clang.for.msvc": "Clang {0}{1} per MSVC con {2} ({3})",
"scanning.for.kits.on.system": "Ricerca dei kit nel sistema",
"scanning.for.kits": "Ricerca dei kit",
"scanning.for.cmake.kits": "Ricerca dei kit CMake...",

Просмотреть файл

@ -29,7 +29,7 @@
"detected.kit.for.version": "バージョンの VsKit が検出されました",
"generator.present": "ジェネレーターが存在します: {0}",
"selected.preferred.generator.name": "選択された優先ジェネレーター名: {0} {1}",
"clang.for.msvc": "{1} ({2}) での MSVC 用 Clang {0}",
"clang.for.msvc": "{2} ({3}) での MSVC 用 Clang {0}{1}",
"scanning.for.kits.on.system": "システムでキットをスキャンしています",
"scanning.for.kits": "キットをスキャンしています",
"scanning.for.cmake.kits": "CMake キットをスキャンしています...",

Просмотреть файл

@ -29,7 +29,7 @@
"detected.kit.for.version": "버전에 대한 검색된 VsKit",
"generator.present": "생성기가 있음: {0}",
"selected.preferred.generator.name": "선택된 기본 설정 생성기 이름: {0} {1}",
"clang.for.msvc": "{1}({2})이(가) 포함된 MSVC에 대한 Clang {0}",
"clang.for.msvc": "{2}({3})이(가) 포함된 MSVC에 대한 Clang {0}{1}",
"scanning.for.kits.on.system": "시스템에서 키트를 검색하는 중",
"scanning.for.kits": "키트를 검색하는 중",
"scanning.for.cmake.kits": "CMake 키트를 검색하는 중...",

Просмотреть файл

@ -29,7 +29,7 @@
"detected.kit.for.version": "Wykryto zestaw VsKit dla wersji",
"generator.present": "Generator jest dostępny: {0}",
"selected.preferred.generator.name": "Nazwa wybranego preferowanego generatora: {0} {1}",
"clang.for.msvc": "Kompilator Clang {0} dla programu MSVC {1} ({2})",
"clang.for.msvc": "Kompilator Clang {0}{1} dla programu MSVC {2} ({3})",
"scanning.for.kits.on.system": "Trwa skanowanie w poszukiwaniu zestawów w systemie",
"scanning.for.kits": "Skanowanie w poszukiwaniu zestawów",
"scanning.for.cmake.kits": "Trwa skanowanie w poszukiwaniu zestawów narzędzia CMake...",

Просмотреть файл

@ -29,7 +29,7 @@
"detected.kit.for.version": "Detectado VsKit para a versão",
"generator.present": "Gerador Presente: {0}",
"selected.preferred.generator.name": "Nome do Gerador Preferencial Selecionado: {0} {1}",
"clang.for.msvc": "Clang {0} para MSVC com {1} ({2})",
"clang.for.msvc": "Clang {0}{1} para MSVC com {2} ({3})",
"scanning.for.kits.on.system": "Examinando o sistema em busca de Kits",
"scanning.for.kits": "Examinando em busca de kits",
"scanning.for.cmake.kits": "Examinando em busca de kits do CMake...",

Просмотреть файл

@ -29,7 +29,7 @@
"detected.kit.for.version": "Обнаружен VsKit для версии.",
"generator.present": "Генератор существует: {0}",
"selected.preferred.generator.name": "Выбранное предпочтительное имя генератора: {0} {1}",
"clang.for.msvc": "Clang {0} для MSVC с {1} ({2})",
"clang.for.msvc": "Clang {0}{1} для MSVC с {2} ({3})",
"scanning.for.kits.on.system": "Поиск наборов в системе.",
"scanning.for.kits": "Поиск наборов.",
"scanning.for.cmake.kits": "Поиск наборов CMake…",

Просмотреть файл

@ -29,7 +29,7 @@
"detected.kit.for.version": "Sürüm için VsKit algılandı",
"generator.present": "Mevcut Oluşturucu: {0}",
"selected.preferred.generator.name": "Seçili Tercih Edilen Oluşturucu Adı: {0} {1}",
"clang.for.msvc": "{1} ({2}) ile MSVC için {0} Clang",
"clang.for.msvc": "{2} ({3}) ile MSVC için {0}{1} Clang",
"scanning.for.kits.on.system": "Sistemdeki Setler için taranıyor",
"scanning.for.kits": "Setler için taranıyor",
"scanning.for.cmake.kits": "CMake setleri için taranıyor...",

Просмотреть файл

@ -140,7 +140,7 @@ export async function getDebugConfigurationFromCache(cache: CMakeCache, target:
const entry = cache.get('CMAKE_LINKER');
if (entry !== null) {
const linker = entry.value as string;
const is_msvc_linker = linker.endsWith('link.exe');
const is_msvc_linker = linker.endsWith('link.exe') || linker.endsWith('ld.lld.exe');
if (is_msvc_linker) {
return createMSVCDebugConfiguration(target);
}

Просмотреть файл

@ -22,7 +22,7 @@ import {
effectiveKitEnvironment,
scanForKitsIfNeeded,
} from '@cmt/kit';
import {KitsController, KitsReadMode} from '@cmt/kitsController';
import {KitsController} from '@cmt/kitsController';
import * as logging from '@cmt/logging';
import {fs} from '@cmt/pr';
import {FireNow, FireLate} from '@cmt/prop';
@ -347,7 +347,7 @@ class ExtensionManager implements vscode.Disposable {
// Do this only for the first folder, to avoid multiple rescans taking place in a multi-root workspace.
const silentScanForKitsNeeded: boolean = vscode.workspace.workspaceFolders !== undefined &&
vscode.workspace.workspaceFolders[0] === cmt.folder &&
await scanForKitsIfNeeded(cmt.extensionContext);
await scanForKitsIfNeeded(cmt);
let should_configure = cmt.workspaceContext.config.configureOnOpen;
if (should_configure === null && process.env['CMT_TESTING'] !== '1') {
@ -588,8 +588,10 @@ class ExtensionManager implements vscode.Disposable {
* Watches for changes to the kits file
*/
private readonly _kitsWatcher =
util.chokidarOnAnyChange(chokidar.watch(USER_KITS_FILEPATH, {ignoreInitial: true}),
_ => rollbar.takePromise(localize('rereading.kits', 'Re-reading kits'), {}, KitsController.readUserKits()));
util.chokidarOnAnyChange(chokidar.watch(USER_KITS_FILEPATH,
{ignoreInitial: true}),
_ => rollbar.takePromise(localize('rereading.kits', 'Re-reading kits'), {}, KitsController.readUserKits(this._folders.activeFolder?.cmakeTools)));
/**
* Set the current kit for the specified workspace folder
@ -638,10 +640,12 @@ class ExtensionManager implements vscode.Disposable {
async scanForKits() {
KitsController.minGWSearchDirs = this._getMinGWDirs();
const duplicateRemoved = await KitsController.scanForKits();
await this._folders.activeFolder?.kitsController.readKits(KitsReadMode.folderKits);
const cmakeTools = this._folders.activeFolder?.cmakeTools;
if (undefined === cmakeTools) {
return;
}
const duplicateRemoved = await KitsController.scanForKits(cmakeTools);
if (duplicateRemoved) {
// Check each folder. If there is an active kit set and if it is of the old definition,
// unset the kit

Просмотреть файл

@ -9,14 +9,15 @@ import * as path from 'path';
import * as vscode from 'vscode';
import * as kitsController from '@cmt/kitsController';
import {VSInstallation, vsInstallations} from './installs/visual-studio';
import CMakeTools from './cmake-tools';
import * as expand from './expand';
import {VSInstallation, vsInstallations} from './installs/visual-studio';
import * as logging from './logging';
import paths from './paths';
import {fs} from './pr';
import * as proc from './proc';
import {loadSchema} from './schema';
import {compare, dropNulls, objectPairs, Ordering} from './util';
import {compare, dropNulls, objectPairs, Ordering, versionLess} from './util';
import * as nls from 'vscode-nls';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
@ -274,14 +275,27 @@ export async function kitIfCompiler(bin: string, pr?: ProgressReporter): Promise
if (version === null) {
return null;
}
if (version.target && version.target.includes('msvc')) {
// DO NOT include Clang's that target MSVC but don't present the MSVC
// command-line interface. CMake does not support them properly.
if (version.target && version.target.includes('msvc') &&
version.installedDir && version.installedDir.includes("Microsoft Visual Studio")) {
// Skip MSVC ABI compatible Clang installations (bundled within VS), which will be handled in 'scanForClangForMSVCKits()' later.
// But still process any Clang installations outside VS (right in Program Files for example), even if their version
// mentions msvc.
return null;
}
const clangxx_fname = fname.replace(/^clang/, 'clang++');
const clangxx_bin = path.join(path.dirname(bin), clangxx_fname);
const name = `Clang ${version.version}`;
let name = `Clang ${version.version}`;
// On windows (except MinGW, Cygwin, etc... represented by a non undefined process.env.MSYSTEM),
// make the distinction between [Program Files]/LLVM and [Program Files(x86)]/LLVM in the kit name,
// to be able to represent both in the kits file.
// clang --version returns the same version.version for these 2 different installs,
// but version.target differs and can be used to ensure name uniqueness.
if (process.platform === "win32" && process.env.MSYSTEM === undefined) {
name += ` (${version.target})`;
}
log.debug(localize('detected.clang.compiler', 'Detected Clang compiler: {0}', bin));
if (await fs.exists(clangxx_bin)) {
return {
@ -800,35 +814,69 @@ export async function scanForVSKits(pr?: ProgressReporter): Promise<Kit[]> {
return ([] as Kit[]).concat(...vs_kits);
}
async function scanDirForClangCLKits(dir: string, vsInstalls: VSInstallation[]): Promise<Kit[]> {
async function scanDirForClangForMSVCKits(dir: string, vsInstalls: VSInstallation[], cmakeTools: CMakeTools | undefined): Promise<Kit[]> {
const kits = await scanDirectory(dir, async(binPath): Promise<Kit[]|null> => {
if (!path.basename(binPath).startsWith('clang-cl')) {
const isClangGNUCLI = (path.basename(binPath, '.exe') === 'clang');
const isClangCL = (path.basename(binPath, '.exe') === 'clang-cl');
if (!isClangGNUCLI && !isClangCL) {
return null;
}
const version = await getClangVersion(binPath);
if (version === null) {
return null;
}
return vsInstalls.map((vs): Kit => {
const installName = vsDisplayName(vs);
let clang_cli = '(MSVC CLI)';
// Clang for MSVC ABI with GNU CLI (command line interface) is supported in CMake 3.15.0+
if (isClangGNUCLI) {
if (undefined === cmakeTools) {
log.error("failed.to.scan.for.kits", "Failed to scan for kits:", "cmakeTools is undefined");
return null;
} else {
const cmake_executable = await cmakeTools?.getCMakeExecutable();
if (undefined === cmake_executable.version) {
return null;
} else {
if (versionLess(cmake_executable.version, '3.15.0')) {
// Could not find a supported CMake version
return null;
}
}
}
// Found a supported CMake version
clang_cli = '(GNU CLI)';
}
const clangKits: Kit[] = [];
vsInstalls.forEach(vs => {
const install_name = vsDisplayName(vs);
const vs_arch = (version.target && version.target.includes('i686-pc')) ? 'x86' : 'amd64';
return {
name: localize('clang.for.msvc', 'Clang {0} for MSVC with {1} ({2})', version.version, installName, vs_arch),
visualStudio: kitVSName(vs),
visualStudioArchitecture: vs_arch,
compilers: {
C: binPath,
CXX: binPath,
},
};
const clangArch = (vs_arch === "amd64") ? "x64\\" : "";
if (binPath.startsWith(`${vs.installationPath}\\VC\\Tools\\Llvm\\${clangArch}bin`) &&
util.checkFileExists(util.lightNormalizePath(binPath))) {
clangKits.push({
name: localize('clang.for.msvc', 'Clang {0} {1} with {2} ({3})', version.version, clang_cli, install_name, vs_arch),
visualStudio: kitVSName(vs),
visualStudioArchitecture: vs_arch,
compilers: {
C: binPath,
CXX: binPath,
}
});
}
});
return clangKits;
});
return ([] as Kit[]).concat(...kits);
}
export async function scanForClangCLKits(searchPaths: string[]): Promise<Promise<Kit[]>[]> {
export async function scanForClangForMSVCKits(searchPaths: string[], cmakeTools: CMakeTools | undefined): Promise<Promise<Kit[]>[]> {
const vs_installs = await vsInstallations();
const results = searchPaths.map(p => scanDirForClangCLKits(p, vs_installs));
const results = searchPaths.map(p => scanDirForClangForMSVCKits(p, vs_installs, cmakeTools));
return results;
}
@ -930,7 +978,7 @@ export interface KitScanOptions {
* Search for Kits available on the platform.
* @returns A list of Kits.
*/
export async function scanForKits(opt?: KitScanOptions) {
export async function scanForKits(cmakeTools: CMakeTools | undefined, opt?: KitScanOptions) {
const kit_options = opt || {};
log.debug(localize('scanning.for.kits.on.system', 'Scanning for Kits on system'));
@ -943,6 +991,7 @@ export async function scanForKits(opt?: KitScanOptions) {
const isWin32 = process.platform === 'win32';
pr.report({message: localize('scanning.for.cmake.kits', 'Scanning for CMake kits...')});
const scan_paths = new Set<string>();
// Search directories on `PATH` for compiler binaries
@ -960,35 +1009,39 @@ export async function scanForKits(opt?: KitScanOptions) {
scan_paths.add(dir);
}
}
// Default installation locations
scan_paths.add('C:\\Program Files (x86)\\LLVM\\bin');
scan_paths.add('C:\\Program Files\\LLVM\\bin');
const compiler_kits = Array.from(scan_paths).map(path_el => scanDirForCompilerKits(path_el, pr));
kit_promises = kit_promises.concat(compiler_kits);
if (isWin32) {
// Prepare clang-cl search paths
const clang_cl_paths = new Set<string>();
const clang_paths = new Set<string>();
// LLVM_ROOT environment variable location
if (process.env.hasOwnProperty('LLVM_ROOT')) {
const llvm_root = path.normalize(process.env.LLVM_ROOT as string + "\\bin");
clang_cl_paths.add(llvm_root);
clang_paths.add(llvm_root);
}
// Default installation locations
clang_cl_paths.add('C:\\Program Files (x86)\\LLVM\\bin');
clang_cl_paths.add('C:\\Program Files\\LLVM\\bin');
// PATH environment variable locations
scan_paths.forEach(path_el => clang_cl_paths.add(path_el));
scan_paths.forEach(path_el => clang_paths.add(path_el));
// LLVM bundled in VS locations
const vs_installs = await vsInstallations();
const bundled_clang_cl_paths = vs_installs.map(vs_install => {
return vs_install.installationPath + "\\VC\\Tools\\Llvm\\bin";
const bundled_clang_paths: string[] = [];
vs_installs.forEach(vs_install => {
bundled_clang_paths.push(vs_install.installationPath + "\\VC\\Tools\\Llvm\\bin");
bundled_clang_paths.push(vs_install.installationPath + "\\VC\\Tools\\Llvm\\x64\\bin");
});
bundled_clang_cl_paths.forEach(path_ => {clang_cl_paths.add(path_);});
bundled_clang_paths.forEach(path_el => {clang_paths.add(path_el);});
// Scan for kits
const vs_kits = scanForVSKits(pr);
kit_promises.push(vs_kits);
const cl_paths = Array.from(clang_cl_paths);
const clang_cl_kits = await scanForClangCLKits(cl_paths);
kit_promises = kit_promises.concat(clang_cl_kits);
const clang_kits = await scanForClangForMSVCKits(Array.from(clang_paths), cmakeTools);
kit_promises = kit_promises.concat(clang_kits);
}
const arrays = await Promise.all(kit_promises);
@ -1000,16 +1053,16 @@ export async function scanForKits(opt?: KitScanOptions) {
}
// Rescan if the kits versions (extension context state var versus value defined for this release) don't match.
export async function scanForKitsIfNeeded(context: vscode.ExtensionContext) : Promise<boolean> {
const kitsVersionSaved = context.globalState.get<number>('kitsVersionSaved');
export async function scanForKitsIfNeeded(cmt: CMakeTools) : Promise<boolean> {
const kitsVersionSaved = cmt.extensionContext.globalState.get<number>('kitsVersionSaved');
const kitsVersionCurrent = 2;
// Scan also when there is no kits version saved in the state.
if ((!kitsVersionSaved || kitsVersionSaved !== kitsVersionCurrent) &&
process.env['CMT_TESTING'] !== '1' && !kitsController.KitsController.isScanningForKits()) {
log.info(localize('silent.kits.rescan', 'Detected kits definition version change from {0} to {1}. Silently scanning for kits.', kitsVersionSaved, kitsVersionCurrent));
await kitsController.KitsController.scanForKits();
context.globalState.update('kitsVersionSaved', kitsVersionCurrent);
await kitsController.KitsController.scanForKits(cmt);
cmt.extensionContext.globalState.update('kitsVersionSaved', kitsVersionCurrent);
return true;
}
@ -1025,10 +1078,17 @@ export async function descriptionForKit(kit: Kit): Promise<string> {
return localize('kit.for.toolchain.file', 'Kit for toolchain file {0}', kit.toolchainFile);
}
if (kit.visualStudio) {
const inst = await getVSInstallForKit(kit);
if (inst) {
const hostTargetArch = kitHostTargetArch(kit.visualStudioArchitecture!, kit.preferredGenerator?.platform);
return localize('using.compilers.for', 'Using compilers for {0} ({1} architecture)', vsVersionName(inst), hostTargetArch);
const vs_install = await getVSInstallForKit(kit);
if (vs_install) {
if (kit.compilers) {
// Clang for MSVC
const compilers = Object.keys(kit.compilers).map(k => `${k} = ${kit.compilers![k]}`);
return localize('using.compilers', 'Using compilers: {0}', compilers.join(', '));
} else {
// MSVC
const hostTargetArch = kitHostTargetArch(kit.visualStudioArchitecture!, kit.preferredGenerator?.platform);
return localize('using.compilers.for', 'Using compilers for {0} ({1} architecture)', vsVersionName(vs_install), hostTargetArch);
}
}
return '';
}

Просмотреть файл

@ -52,7 +52,7 @@ export class KitsController {
static async init(cmakeTools: CMakeTools) {
if (KitsController.userKits.length === 0) {
// never initialized before
await KitsController.readUserKits();
await KitsController.readUserKits(cmakeTools);
}
const kitsWatcher = chokidar.watch(KitsController._workspaceKitsPath(cmakeTools.folder), {ignoreInitial: true});
const kitsController = new KitsController(cmakeTools, kitsWatcher);
@ -76,7 +76,10 @@ export class KitsController {
get folder() { return this.cmakeTools.folder; }
static async readUserKits(progress?: ProgressHandle) {
static async readUserKits(cmakeTools: CMakeTools | undefined, progress?: ProgressHandle) {
if (undefined === cmakeTools) {
return;
}
// Read user kits if we are under userKits/allAvailable read mode, or if userKits is empty (which means userKits are never loaded)
// Migrate kits from old pre-1.1.3 location
try {
@ -106,7 +109,7 @@ export class KitsController {
KitsController.userKits = [...special_kits, ...user_kits];
// Pruning requires user interaction, so it happens fully async
KitsController._startPruneOutdatedKitsAsync();
KitsController._startPruneOutdatedKitsAsync(cmakeTools);
}
/**
@ -114,7 +117,7 @@ export class KitsController {
*/
async readKits(kitsReadMode = KitsReadMode.allAvailable, progress?: ProgressHandle) {
if (kitsReadMode === KitsReadMode.userKits || kitsReadMode === KitsReadMode.allAvailable) {
await KitsController.readUserKits(progress);
await KitsController.readUserKits(this.cmakeTools, progress);
}
if (kitsReadMode === KitsReadMode.folderKits || kitsReadMode === KitsReadMode.allAvailable) {
// Read folder kits
@ -182,7 +185,7 @@ export class KitsController {
if (!KitsController.checkingHaveKits) {
KitsController.checkingHaveKits = true;
if (!KitsController.minGWSearchDirs) {
await KitsController.scanForKits();
await KitsController.scanForKits(this.cmakeTools);
} else {
await vscode.commands.executeCommand('cmake.scanForKits');
}
@ -243,7 +246,7 @@ export class KitsController {
return false;
} else {
if (chosen_kit.kit.name == SpecialKits.ScanForKits) {
await KitsController.scanForKits();
await KitsController.scanForKits(this.cmakeTools);
return false;
} else {
log.debug(localize('user.selected.kit', 'User selected kit {0}', JSON.stringify(chosen_kit)));
@ -284,7 +287,7 @@ export class KitsController {
*
* Always returns immediately.
*/
private static _startPruneOutdatedKitsAsync() {
private static _startPruneOutdatedKitsAsync(cmakeTools: CMakeTools) {
// Iterate over _user_ kits. We don't care about workspace-local kits
for (const kit of KitsController.userKits) {
if (kit.keep === true) {
@ -340,9 +343,9 @@ export class KitsController {
}
switch (chosen.action) {
case 'keep':
return KitsController._keepKit(kit);
return KitsController._keepKit(cmakeTools, kit);
case 'remove':
return KitsController._removeKit(kit);
return KitsController._removeKit(cmakeTools, kit);
}
});
rollbar.takePromise(localize('pruning.kit', "Pruning kit"), {kit}, pr);
@ -354,7 +357,7 @@ export class KitsController {
* re-writes the user kits file.
* @param kit The kit to mark
*/
private static async _keepKit(kit: Kit) {
private static async _keepKit(cmakeTools: CMakeTools, kit: Kit) {
const new_kits = KitsController.userKits.map(k => {
if (k.name === kit.name) {
return {...k, keep: true};
@ -363,24 +366,24 @@ export class KitsController {
}
});
KitsController.userKits = new_kits;
return KitsController._writeUserKitsFile(new_kits);
return KitsController._writeUserKitsFile(cmakeTools, new_kits);
}
/**
* Remove a kit from the user-local kits.
* @param kit The kit to remove
*/
private static async _removeKit(kit: Kit) {
private static async _removeKit(cmakeTools: CMakeTools, kit: Kit) {
const new_kits = KitsController.userKits.filter(k => k.name !== kit.name);
KitsController.userKits = new_kits;
return KitsController._writeUserKitsFile(new_kits);
return KitsController._writeUserKitsFile(cmakeTools, new_kits);
}
/**
* Write the given kits the the user-local cmake-kits.json file.
* @param kits The kits to write to the file.
*/
private static async _writeUserKitsFile(kits: Kit[]) {
private static async _writeUserKitsFile(cmakeTools: CMakeTools, kits: Kit[]) {
log.debug(localize('saving.kits.to', 'Saving kits to {0}', USER_KITS_FILEPATH));
// Remove the special kits
@ -429,7 +432,7 @@ export class KitsController {
}
switch (choice.do) {
case 'retry':
return KitsController.scanForKits();
return KitsController.scanForKits(cmakeTools);
case 'cancel':
return false;
}
@ -455,11 +458,11 @@ export class KitsController {
*
* @returns if any duplicate vs kits are removed.
*/
static async scanForKits() {
static async scanForKits(cmakeTools: CMakeTools) {
log.debug(localize('rescanning.for.kits', 'Rescanning for kits'));
// Do the scan:
const discovered_kits = await scanForKits({minGWSearchDirs: KitsController.minGWSearchDirs});
const discovered_kits = await scanForKits(cmakeTools, {minGWSearchDirs: KitsController.minGWSearchDirs});
// The list with the new definition user kits starts with the non VS ones,
// which do not have any variations in the way they can be defined.
@ -517,9 +520,9 @@ export class KitsController {
const new_kits = Object.keys(new_kits_by_name).map(k => new_kits_by_name[k]);
KitsController.userKits = new_kits;
await KitsController._writeUserKitsFile(new_kits);
await KitsController._writeUserKitsFile(cmakeTools, new_kits);
KitsController._startPruneOutdatedKitsAsync();
KitsController._startPruneOutdatedKitsAsync(cmakeTools);
return duplicateRemoved;
}

Просмотреть файл

@ -454,6 +454,11 @@ export function versionGreater(lhs: Version|string, rhs: Version|string): boolea
return compareVersions(lhs, rhs) === Ordering.Greater;
}
export function versionGreaterOrEquals(lhs: Version|string, rhs: Version|string): boolean {
const ordering = compareVersions(lhs, rhs);
return (Ordering.Greater === ordering) || (Ordering.Equivalent === ordering);
}
export function versionEquals(lhs: Version|string, rhs: Version|string): boolean {
return compareVersions(lhs, rhs) === Ordering.Equivalent;
}
@ -462,6 +467,11 @@ export function versionLess(lhs: Version|string, rhs: Version|string): boolean {
return compareVersions(lhs, rhs) === Ordering.Less;
}
export function versionLessOrEquals(lhs: Version|string, rhs: Version|string): boolean {
const ordering = compareVersions(lhs, rhs);
return (Ordering.Less === ordering) || (Ordering.Equivalent === ordering);
}
export function compare(a: any, b: any): Ordering {
const a_json = JSON.stringify(a);
const b_json = JSON.stringify(b);

Просмотреть файл

@ -12,6 +12,7 @@ import {ITestCallbackContext} from 'mocha';
import * as fs_ from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
import CMakeTools from '@cmt/cmake-tools';
// tslint:disable:no-unused-expression
@ -28,6 +29,7 @@ if (process.env.TRAVIS_OS_NAME) {
suite('Build', async () => {
let testEnv: DefaultEnvironment;
let compdb_cp_path: string;
let cmakeTools : CMakeTools;
suiteSetup(async function(this: Mocha.IHookCallbackContext) {
this.timeout(100000);
@ -37,6 +39,7 @@ suite('Build', async () => {
testEnv = new DefaultEnvironment('test/extension-tests/multi-root-UI/project-folder2', build_loc, exe_res);
compdb_cp_path = path.join(testEnv.projectFolder.location, 'compdb_cp.json');
cmakeTools = await CMakeTools.create(testEnv.vsContext, testEnv.wsContext);
// This test will use all on the same kit.
// No rescan of the tools is needed
@ -48,7 +51,7 @@ suite('Build', async () => {
setup(async function(this: Mocha.IBeforeAndAfterContext) {
this.timeout(100000);
const kit = await getFirstSystemKit();
const kit = await getFirstSystemKit(cmakeTools);
console.log("Using following kit in next test: ", kit);
await vscode.commands.executeCommand('cmake.setKitByName', kit.name);
testEnv.projectFolder.buildDirectory.clear();
@ -135,12 +138,12 @@ suite('Build', async () => {
// Run test
testEnv.kitSelection.defaultKitLabel = compiler[0].kitLabel;
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(compiler[0].kitLabel)).name);
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(cmakeTools, compiler[0].kitLabel)).name);
await vscode.commands.executeCommand('cmake.buildAll');
testEnv.kitSelection.defaultKitLabel = compiler[1].kitLabel;
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(compiler[1].kitLabel)).name);
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(cmakeTools, compiler[1].kitLabel)).name);
await vscode.commands.executeCommand('cmake.buildAll');
const result = await testEnv.result.getResultAsJson();
@ -159,11 +162,11 @@ suite('Build', async () => {
const compiler = os_compilers[workername];
testEnv.kitSelection.defaultKitLabel = compiler[0].kitLabel;
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(compiler[0].kitLabel)).name);
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(cmakeTools, compiler[0].kitLabel)).name);
await vscode.commands.executeCommand('cmake.buildAll');
testEnv.kitSelection.defaultKitLabel = compiler[1].kitLabel;
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(compiler[1].kitLabel)).name);
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(cmakeTools, compiler[1].kitLabel)).name);
await vscode.commands.executeCommand('cmake.buildAll');
const result = await testEnv.result.getResultAsJson();

Просмотреть файл

@ -1,11 +1,13 @@
import {DefaultEnvironment, expect, getFirstSystemKit} from '@test/util';
// import sinon = require('sinon');
import * as vscode from 'vscode';
import CMakeTools from '@cmt/cmake-tools';
// tslint:disable:no-unused-expression
suite('[Debug/Launch interface]', async () => {
let testEnv: DefaultEnvironment;
let cmakeTools: CMakeTools;
setup(async function(this: Mocha.IBeforeAndAfterContext) {
this.timeout(100000);
@ -14,8 +16,9 @@ suite('[Debug/Launch interface]', async () => {
const exe_res = 'output.txt';
testEnv = new DefaultEnvironment('test/extension-tests/multi-root-UI/project-folder2', build_loc, exe_res);
cmakeTools = await CMakeTools.create(testEnv.vsContext, testEnv.wsContext);
const kit = await getFirstSystemKit();
const kit = await getFirstSystemKit(cmakeTools);
console.log("Using following kit in next test: ", kit);
await vscode.commands.executeCommand('cmake.setKitByName', kit.name);
testEnv.projectFolder.buildDirectory.clear();

Просмотреть файл

@ -5,11 +5,13 @@ import {clearExistingKitConfigurationFile, DefaultEnvironment, expect, getFirstS
import {fs} from '@cmt/pr';
import * as path from 'path';
import * as vscode from 'vscode';
import CMakeTools from '@cmt/cmake-tools';
// tslint:disable:no-unused-expression
suite('[Environment Variables in Variants]', async () => {
let testEnv: DefaultEnvironment;
let cmakeTools : CMakeTools;
setup(async function(this: Mocha.IBeforeAndAfterContext) {
this.timeout(100000);
@ -18,13 +20,14 @@ suite('[Environment Variables in Variants]', async () => {
const exe_res = 'output.txt';
testEnv = new DefaultEnvironment('test/extension-tests/multi-root-UI/project-folder2', build_loc, exe_res);
cmakeTools = await CMakeTools.create(testEnv.vsContext, testEnv.wsContext);
// This test will use all on the same kit.
// No rescan of the tools is needed
// No new kit selection is needed
await clearExistingKitConfigurationFile();
const kit = await getFirstSystemKit();
const kit = await getFirstSystemKit(cmakeTools);
console.log("Using following kit in next test: ", kit);
await vscode.commands.executeCommand('cmake.setKitByName', kit.name);

Просмотреть файл

@ -11,6 +11,7 @@ import {
import {ITestCallbackContext} from 'mocha';
import * as path from 'path';
import * as vscode from 'vscode';
import CMakeTools from '@cmt/cmake-tools';
// tslint:disable:no-unused-expression
@ -27,6 +28,7 @@ if (process.env.TRAVIS_OS_NAME) {
suite('Build', async () => {
let testEnv: DefaultEnvironment;
let compdb_cp_path: string;
let cmakeTools : CMakeTools;
suiteSetup(async function(this: Mocha.IHookCallbackContext) {
this.timeout(100000);
@ -36,6 +38,7 @@ suite('Build', async () => {
testEnv = new DefaultEnvironment('test/extension-tests/single-root-UI/project-folder', build_loc, exe_res);
compdb_cp_path = path.join(testEnv.projectFolder.location, 'compdb_cp.json');
cmakeTools = await CMakeTools.create(testEnv.vsContext, testEnv.wsContext);
// This test will use all on the same kit.
// No rescan of the tools is needed
@ -47,7 +50,7 @@ suite('Build', async () => {
setup(async function(this: Mocha.IBeforeAndAfterContext) {
this.timeout(100000);
const kit = await getFirstSystemKit();
const kit = await getFirstSystemKit(cmakeTools);
console.log("Using following kit in next test: ", kit);
await vscode.commands.executeCommand('cmake.setKitByName', kit.name);
testEnv.projectFolder.buildDirectory.clear();
@ -121,12 +124,12 @@ suite('Build', async () => {
// Run test
testEnv.kitSelection.defaultKitLabel = compiler[0].kitLabel;
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(compiler[0].kitLabel)).name);
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(cmakeTools, compiler[0].kitLabel)).name);
await vscode.commands.executeCommand('cmake.build');
testEnv.kitSelection.defaultKitLabel = compiler[1].kitLabel;
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(compiler[1].kitLabel)).name);
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(cmakeTools, compiler[1].kitLabel)).name);
await vscode.commands.executeCommand('cmake.build');
const result1 = await testEnv.result.getResultAsJson();
@ -145,11 +148,11 @@ suite('Build', async () => {
const compiler = os_compilers[workername];
testEnv.kitSelection.defaultKitLabel = compiler[0].kitLabel;
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(compiler[0].kitLabel)).name);
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(cmakeTools, compiler[0].kitLabel)).name);
await vscode.commands.executeCommand('cmake.build');
testEnv.kitSelection.defaultKitLabel = compiler[1].kitLabel;
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(compiler[1].kitLabel)).name);
await vscode.commands.executeCommand('cmake.setKitByName', (await getMatchingSystemKit(cmakeTools, compiler[1].kitLabel)).name);
await vscode.commands.executeCommand('cmake.build');
const result1 = await testEnv.result.getResultAsJson();

Просмотреть файл

@ -1,11 +1,13 @@
import {DefaultEnvironment, expect, getFirstSystemKit} from '@test/util';
// import sinon = require('sinon');
import * as vscode from 'vscode';
import CMakeTools from '@cmt/cmake-tools';
// tslint:disable:no-unused-expression
suite('[Debug/Launch interface]', async () => {
let testEnv: DefaultEnvironment;
let cmakeTools: CMakeTools;
setup(async function(this: Mocha.IBeforeAndAfterContext) {
this.timeout(100000);
@ -14,8 +16,9 @@ suite('[Debug/Launch interface]', async () => {
const exe_res = 'output.txt';
testEnv = new DefaultEnvironment('test/extension-tests/single-root-UI/project-folder', build_loc, exe_res);
cmakeTools = await CMakeTools.create(testEnv.vsContext, testEnv.wsContext);
const kit = await getFirstSystemKit();
const kit = await getFirstSystemKit(cmakeTools);
console.log("Using following kit in next test: ", kit);
await vscode.commands.executeCommand('cmake.setKitByName', kit.name);
testEnv.projectFolder.buildDirectory.clear();

Просмотреть файл

@ -5,11 +5,13 @@ import {clearExistingKitConfigurationFile, DefaultEnvironment, expect, getFirstS
import {fs} from '@cmt/pr';
import * as path from 'path';
import * as vscode from 'vscode';
import CMakeTools from '@cmt/cmake-tools';
// tslint:disable:no-unused-expression
suite('[Environment Variables in Variants]', async () => {
let testEnv: DefaultEnvironment;
let cmakeTools: CMakeTools;
setup(async function(this: Mocha.IBeforeAndAfterContext) {
this.timeout(100000);
@ -18,13 +20,14 @@ suite('[Environment Variables in Variants]', async () => {
const exe_res = 'output.txt';
testEnv = new DefaultEnvironment('test/extension-tests/single-root-UI/project-folder', build_loc, exe_res);
cmakeTools = await CMakeTools.create(testEnv.vsContext, testEnv.wsContext);
// This test will use all on the same kit.
// No rescan of the tools is needed
// No new kit selection is needed
await clearExistingKitConfigurationFile();
const kit = await getFirstSystemKit();
const kit = await getFirstSystemKit(cmakeTools);
console.log("Using following kit in next test: ", kit);
await vscode.commands.executeCommand('cmake.setKitByName', kit.name);

Просмотреть файл

@ -18,7 +18,7 @@ suite('cmake', async () => {
// No rescan of the tools is needed
// No new kit selection is needed
await clearExistingKitConfigurationFile();
await cmt.setKit(await getFirstSystemKit());
await cmt.setKit(await getFirstSystemKit(cmt));
testEnv.projectFolder.buildDirectory.clear();
});

Просмотреть файл

@ -51,7 +51,7 @@ suite('Build', async () => {
this.timeout(100000);
cmt = await CMakeTools.create(testEnv.vsContext, testEnv.wsContext);
const kit = await getFirstSystemKit();
const kit = await getFirstSystemKit(cmt);
console.log("Using following kit in next test: ", kit);
await cmt.setKit(kit);
testEnv.projectFolder.buildDirectory.clear();
@ -141,12 +141,12 @@ suite('Build', async () => {
// Run test
testEnv.kitSelection.defaultKitLabel = compiler[0].kitLabel;
await cmt.setKit(await getMatchingSystemKit(compiler[0].kitLabel));
await cmt.setKit(await getMatchingSystemKit(cmt, compiler[0].kitLabel));
await cmt.build();
testEnv.kitSelection.defaultKitLabel = compiler[1].kitLabel;
await cmt.setKit(await getMatchingSystemKit(compiler[1].kitLabel));
await cmt.setKit(await getMatchingSystemKit(cmt, compiler[1].kitLabel));
await cmt.build();
const result1 = await testEnv.result.getResultAsJson();
@ -216,11 +216,11 @@ suite('Build', async () => {
const compiler = os_compilers[workername];
testEnv.kitSelection.defaultKitLabel = compiler[0].kitLabel;
await cmt.setKit(await getMatchingSystemKit(compiler[0].kitLabel));
await cmt.setKit(await getMatchingSystemKit(cmt, compiler[0].kitLabel));
await cmt.build();
testEnv.kitSelection.defaultKitLabel = compiler[1].kitLabel;
await cmt.setKit(await getMatchingSystemKit(compiler[1].kitLabel));
await cmt.setKit(await getMatchingSystemKit(cmt, compiler[1].kitLabel));
await cmt.build();
const result1 = await testEnv.result.getResultAsJson();

Просмотреть файл

@ -15,7 +15,7 @@ suite('[Debug/Launch interface]', async () => {
testEnv = new DefaultEnvironment('test/extension-tests/successful-build/project-folder', 'build', 'output.txt');
cmt = await CMakeTools.create(testEnv.vsContext, testEnv.wsContext);
await cmt.setKit(await getFirstSystemKit());
await cmt.setKit(await getFirstSystemKit(cmt));
testEnv.projectFolder.buildDirectory.clear();
expect(await cmt.build()).to.be.eq(0);
});

Просмотреть файл

@ -18,7 +18,7 @@ suite('[Environment]', async () => {
// No rescan of the tools is needed
// No new kit selection is needed
await clearExistingKitConfigurationFile();
await cmt.setKit(await getFirstSystemKit());
await cmt.setKit(await getFirstSystemKit(cmt));
testEnv.projectFolder.buildDirectory.clear();
});

Просмотреть файл

@ -223,7 +223,7 @@ function makeExtensionTestSuite(name: string,
// No rescan of the tools is needed
// No new kit selection is needed
await clearExistingKitConfigurationFile();
context.kits = await scanForKits();
context.kits = await scanForKits(context.cmt);
skipTestIf({kitIsNotAvailable: true}, this, context);
});

Просмотреть файл

@ -12,7 +12,7 @@ suite('[MinGW Tests]', async () => {
});
test('Test scan of mingw', async () => {
const kits = await scanForKits({
const kits = await scanForKits(undefined, {
scanDirs: [],
minGWSearchDirs: mingw_dirs,
});

Просмотреть файл

@ -20,7 +20,7 @@ suite('[Variable Substitution]', async () => {
// No rescan of the tools is needed
// No new kit selection is needed
await clearExistingKitConfigurationFile();
await cmt.setKit(await getFirstSystemKit());
await cmt.setKit(await getFirstSystemKit(cmt));
testEnv.projectFolder.buildDirectory.clear();
});

Просмотреть файл

@ -22,7 +22,7 @@ suite('[Environment Variables in Variants]', async () => {
// No rescan of the tools is needed
// No new kit selection is needed
await clearExistingKitConfigurationFile();
await cmt.setKit(await getFirstSystemKit());
await cmt.setKit(await getFirstSystemKit(cmt));
testEnv.projectFolder.buildDirectory.clear();
});

Просмотреть файл

@ -8,6 +8,9 @@ import {expect} from 'chai';
import * as kit from '../../src/kit';
import {fs} from '../../src/pr';
import {CMakeTools} from '@cmt/cmake-tools';
import {clearExistingKitConfigurationFile, DefaultEnvironment,} from '@test/util';
// tslint:disable:no-unused-expression
const here = __dirname;
@ -24,6 +27,9 @@ function getPathWithoutCompilers() {
}
suite('Kits scan test', async () => {
let cmt: CMakeTools;
let testEnv: DefaultEnvironment;
const fakebin = getTestRootFilePath('fakebin');
const mingwMakePath = path.join(fakebin, 'mingw32-make');
const mingwMakePathBackup = path.join(fakebin, 'mingw32-make.bak');
@ -38,8 +44,16 @@ suite('Kits scan test', async () => {
test('Detect system kits never throws',
async () => {
const build_loc = 'build';
const exe_res = 'output.txt';
testEnv = new DefaultEnvironment('test/extension-tests/successful-build/project-folder', build_loc, exe_res);
cmt = await CMakeTools.create(testEnv.vsContext, testEnv.wsContext);
await clearExistingKitConfigurationFile();
// Don't care about the result, just check that we don't throw during the test
await kit.scanForKits();
await kit.scanForKits(cmt);
})
// Compiler detection can run a little slow
.timeout(60000);

Просмотреть файл

@ -29,21 +29,21 @@ export async function getExtension() {
let AVAIL_KITS: Promise<Kit[]> | null = null;
export async function getSystemKits(): Promise<Kit[]> {
export async function getSystemKits(cmakeTools: CMakeTools): Promise<Kit[]> {
if (AVAIL_KITS === null) {
AVAIL_KITS = scanForKits();
AVAIL_KITS = scanForKits(cmakeTools);
}
return AVAIL_KITS;
}
export async function getFirstSystemKit(): Promise<Kit> {
const kits = await getSystemKits();
export async function getFirstSystemKit(cmakeTools: CMakeTools): Promise<Kit> {
const kits = await getSystemKits(cmakeTools);
console.assert(kits.length >= 1, 'No kits found for testing');
return kits[0];
}
export async function getMatchingSystemKit(re: RegExp): Promise<Kit> {
const kits = await getSystemKits();
export async function getMatchingSystemKit(cmakeTools: CMakeTools, re: RegExp): Promise<Kit> {
const kits = await getSystemKits(cmakeTools);
return getMatchingKit(kits, re);
}