Add debugger information to kit file
The needed debugger dependes in some cases from the used compiler. This modification adds a section for the debugger into the kit file. This allows to switch gdb dependent on the used gcc or clang compiler.
This commit is contained in:
Родитель
9686ee0be4
Коммит
0e583a10bf
|
@ -68,6 +68,24 @@
|
|||
"required": [
|
||||
"name"
|
||||
]
|
||||
},
|
||||
"debugger": {
|
||||
"type": "object",
|
||||
"description": "Contains all options to configure the cmake debugger calls",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["Visual Studio", "LLDB", "GDB"],
|
||||
"description": "Type of debugger, it is used to define the MiMode and Cppdbg"
|
||||
},
|
||||
"debuggerPath": {
|
||||
"type": "string",
|
||||
"description": "Path to gdb or lldb executable"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
*/
|
||||
import {CMakeCache} from '@cmt/cache';
|
||||
import {CMakeExecutable, getCMakeExecutableInformation} from '@cmt/cmake/cmake-executable';
|
||||
import * as debugger_config from '@cmt/debugger';
|
||||
import {getDebugConfigurationFromKit} from '@cmt/debugger';
|
||||
import {versionToString} from '@cmt/util';
|
||||
import {DirectoryContext} from '@cmt/workspace';
|
||||
import * as http from 'http';
|
||||
|
@ -11,7 +13,6 @@ import * as vscode from 'vscode';
|
|||
import * as ws from 'ws';
|
||||
|
||||
import * as api from './api';
|
||||
import * as debugger_config from '@cmt/debugger';
|
||||
import {ExecutionOptions, ExecutionResult} from './api';
|
||||
import {CacheEditorContentProvider} from './cache-editor';
|
||||
import {CMakeServerClientDriver} from './cms-driver';
|
||||
|
@ -808,8 +809,31 @@ export class CMakeTools implements vscode.Disposable, api.CMakeToolsAPI {
|
|||
return null;
|
||||
}
|
||||
|
||||
let debug_config;
|
||||
|
||||
try {
|
||||
const kit = this._kitManager.activeKit;
|
||||
if (kit !== null && kit.debugger !== undefined) {
|
||||
debug_config = await getDebugConfigurationFromKit(kit.debugger, target);
|
||||
}
|
||||
|
||||
if (debug_config === undefined) {
|
||||
const cache = await CMakeCache.fromPath(drv.cachePath);
|
||||
const debug_config = debugger_config.getDebugConfigurationFromCache(cache, target, process.platform);
|
||||
debug_config = await debugger_config.getDebugConfigurationFromCache(cache, target, process.platform);
|
||||
}
|
||||
} catch (error) {
|
||||
vscode.window
|
||||
.showErrorMessage(error.message, {
|
||||
title: 'Learn more',
|
||||
isLearnMore: true,
|
||||
})
|
||||
.then(item => {
|
||||
if (item && item.isLearnMore) {
|
||||
open('https://vector-of-bool.github.io/docs/vscode-cmake-tools/debugging.html');
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
// add debug configuration from settings
|
||||
const user_config = this.workspaceContext.config.debugConfig;
|
||||
|
|
|
@ -1,5 +1,35 @@
|
|||
import {ExecutableTarget} from '@cmt/api';
|
||||
import {CMakeCache} from '@cmt/cache';
|
||||
import * as proc from '@cmt/proc';
|
||||
|
||||
|
||||
export enum DebuggerType {
|
||||
VISUALSTUDIO = 'Visual Studio',
|
||||
LLDB = 'LLDB',
|
||||
GDB = 'GDB',
|
||||
// LAUNCH // Future
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes configuration options for debugger in kit
|
||||
*/
|
||||
export interface DebuggerConfiguration {
|
||||
/**
|
||||
* Identifier of the type to launch
|
||||
*/
|
||||
type: DebuggerType;
|
||||
|
||||
/**
|
||||
* Path to gdb or lldb executable.
|
||||
*/
|
||||
debuggerPath?: string;
|
||||
|
||||
/**
|
||||
* Name of a existing launch configuration
|
||||
*/
|
||||
// launchConfiguration?: string; // Future
|
||||
}
|
||||
|
||||
|
||||
export interface Configuration {
|
||||
type: string;
|
||||
|
@ -8,7 +38,14 @@ export interface Configuration {
|
|||
[key: string]: any;
|
||||
}
|
||||
|
||||
function createGDBDebugConfiguration(debuggerPath: string, target: ExecutableTarget): Configuration {
|
||||
async function createGDBDebugConfiguration(debuggerPath: string, target: ExecutableTarget): Promise<Configuration> {
|
||||
if (!await checkDebugger(debuggerPath)) {
|
||||
debuggerPath = 'gdb';
|
||||
if (!await checkDebugger(debuggerPath)) {
|
||||
throw new Error(`Unable to find GDB in default search path and ${debuggerPath}.`);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'cppdbg',
|
||||
name: `Debug ${target.name}`,
|
||||
|
@ -28,7 +65,7 @@ function createGDBDebugConfiguration(debuggerPath: string, target: ExecutableTar
|
|||
};
|
||||
}
|
||||
|
||||
function createLLDBDebugConfiguration(debuggerPath: string, target: ExecutableTarget): Configuration {
|
||||
async function createLLDBDebugConfiguration(debuggerPath: string, target: ExecutableTarget): Promise<Configuration> {
|
||||
return {
|
||||
type: 'cppdbg',
|
||||
name: `Debug ${target.name}`,
|
||||
|
@ -54,14 +91,14 @@ function createMSVCDebugConfiguration(target: ExecutableTarget): Configuration {
|
|||
|
||||
const possible_debuggers: {
|
||||
[debugger_name: string]:
|
||||
{mi_mode: string, config_factory: (debugger_path: string, target: ExecutableTarget) => Configuration}
|
||||
{mi_mode: string, config_factory: (debugger_path: string, target: ExecutableTarget) => Promise<Configuration>}
|
||||
}
|
||||
= {
|
||||
gdb: {mi_mode: 'gdb', config_factory: createGDBDebugConfiguration},
|
||||
lldb: {mi_mode: 'lldb', config_factory: createLLDBDebugConfiguration}
|
||||
};
|
||||
|
||||
function searchForCompilerPath(cache: CMakeCache): string|null {
|
||||
function searchForCompilerPathInCache(cache: CMakeCache): string|null {
|
||||
const languages = ['CXX', 'C', 'CUDA'];
|
||||
for (const lang of languages) {
|
||||
const entry = cache.get(`CMAKE_${lang}_COMPILER`);
|
||||
|
@ -73,8 +110,9 @@ function searchForCompilerPath(cache: CMakeCache): string|null {
|
|||
return null;
|
||||
}
|
||||
|
||||
export function getDebugConfigurationFromCache(cache: CMakeCache, target: ExecutableTarget, platform: string):
|
||||
Configuration {
|
||||
|
||||
export async function getDebugConfigurationFromCache(cache: CMakeCache, target: ExecutableTarget, platform: string):
|
||||
Promise<Configuration> {
|
||||
const entry = cache.get('CMAKE_LINKER');
|
||||
if (entry !== null) {
|
||||
const linker = entry.value as string;
|
||||
|
@ -84,16 +122,21 @@ export function getDebugConfigurationFromCache(cache: CMakeCache, target: Execut
|
|||
}
|
||||
}
|
||||
|
||||
const compiler_path = searchForCompilerPath(cache);
|
||||
const compiler_path = searchForCompilerPathInCache(cache);
|
||||
if (compiler_path === null) {
|
||||
throw Error('No compiler found in cache file.'); // MSVC should be already found by CMAKE_LINKER
|
||||
}
|
||||
|
||||
const clang_compiler_regex = /(clang[\+]{0,2})+(?!-cl)/gi;
|
||||
const clang_debugger_path = compiler_path.replace(clang_compiler_regex, 'lldb');
|
||||
|
||||
if (clang_debugger_path.search(/lldb/) != -1) {
|
||||
let clang_debugger_path = compiler_path.replace(clang_compiler_regex, 'lldb');
|
||||
if ((clang_debugger_path.search(new RegExp('lldb')) != -1) && await checkDebugger(clang_debugger_path)) {
|
||||
return createLLDBDebugConfiguration(clang_debugger_path, target);
|
||||
} else {
|
||||
clang_debugger_path = compiler_path.replace(clang_compiler_regex, 'gdb');
|
||||
|
||||
if ((clang_debugger_path.search(new RegExp('gdb')) != -1) && await checkDebugger(clang_debugger_path)) {
|
||||
return createGDBDebugConfiguration(clang_debugger_path, target);
|
||||
}
|
||||
}
|
||||
|
||||
const debugger_name = platform == 'darwin' ? 'lldb' : 'gdb';
|
||||
|
@ -111,3 +154,35 @@ export function getDebugConfigurationFromCache(cache: CMakeCache, target: Execut
|
|||
|
||||
return {type: '', name: '', request: ''} as Configuration;
|
||||
}
|
||||
|
||||
export async function checkDebugger(debugger_path: string): Promise<boolean> {
|
||||
const res = await proc.execute(debugger_path, ['--version'], null, {shell: true}).result;
|
||||
return res.retc == 0;
|
||||
}
|
||||
|
||||
export async function getDebugConfigurationFromKit(debuggerConfig: DebuggerConfiguration,
|
||||
target: ExecutableTarget): Promise<Configuration> {
|
||||
const debugger_path = debuggerConfig.debuggerPath;
|
||||
|
||||
switch (debuggerConfig.type) {
|
||||
case DebuggerType.VISUALSTUDIO:
|
||||
return createMSVCDebugConfiguration(target);
|
||||
|
||||
case DebuggerType.GDB:
|
||||
if (debugger_path !== undefined && await checkDebugger(debugger_path)) {
|
||||
return createGDBDebugConfiguration(debugger_path, target);
|
||||
} else {
|
||||
throw new Error(`Unable to find GDB debugger (${debugger_path})`);
|
||||
}
|
||||
|
||||
case DebuggerType.LLDB:
|
||||
if (debugger_path !== undefined && await checkDebugger(debugger_path)) {
|
||||
return createLLDBDebugConfiguration(debugger_path, target);
|
||||
} else {
|
||||
throw new Error(`Unable to find LLDB debugger (${debugger_path})`);
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Invalid debugger type (${debuggerConfig.type}).`);
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
*/ /** */
|
||||
|
||||
import {ConfigurationReader} from '@cmt/config';
|
||||
import {DebuggerConfiguration} from '@cmt/debugger';
|
||||
import {StateManager} from '@cmt/state';
|
||||
import * as json5 from 'json5';
|
||||
import * as path from 'path';
|
||||
|
@ -75,6 +76,11 @@ export interface Kit {
|
|||
* Path to a CMake toolchain file.
|
||||
*/
|
||||
toolchainFile?: string;
|
||||
|
||||
/**
|
||||
* Configuration options for the debugger in cmaketools
|
||||
*/
|
||||
debugger?: DebuggerConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
GNU gdb (GDB) 7.6.1
|
||||
I am a fake GDB
|
|
@ -0,0 +1,2 @@
|
|||
GNU gdb (GDB) 7.6.1
|
||||
I am a fake GDB
|
|
@ -0,0 +1 @@
|
|||
lldb version 6.0.0
|
|
@ -1,6 +1,9 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
std::string generateConfigFilename(std::string inputFileName) {
|
||||
#ifdef _WIN32
|
||||
|
@ -12,8 +15,14 @@ std::string generateConfigFilename(std::string inputFileName) {
|
|||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
#ifdef _WIN32
|
||||
char buffer[MAX_PATH];
|
||||
DWORD length = GetModuleFileName( NULL, buffer, MAX_PATH);
|
||||
std::string filePath( buffer);
|
||||
#else
|
||||
|
||||
std::string filePath = argv[0];
|
||||
#endif
|
||||
std::string configFilePath = generateConfigFilename(filePath);
|
||||
|
||||
std::ifstream inputData(configFilePath.c_str());
|
||||
|
@ -24,6 +33,7 @@ int main(int argc, char** argv) {
|
|||
std::cerr << line << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Argv[0]" << argv[0] << std::endl;
|
||||
std::cerr << "ERROR: config file is missing '" << configFilePath << "'" << std::endl;
|
||||
return -99;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ CMAKE_AR:FILEPATH=/usr/bin/ar
|
|||
CMAKE_BUILD_TYPE:STRING=Debug
|
||||
|
||||
//CXX compiler
|
||||
CMAKE_CXX_COMPILER:FILEPATH=/usr/local/bin/g++
|
||||
CMAKE_CXX_COMPILER:FILEPATH=g++
|
||||
|
||||
//Flags used by the compiler during all build types.
|
||||
CMAKE_CXX_FLAGS:STRING=
|
||||
|
|
|
@ -27,7 +27,7 @@ CMAKE_AR:FILEPATH=/usr/bin/ar
|
|||
CMAKE_BUILD_TYPE:STRING=Debug
|
||||
|
||||
//CXX compiler
|
||||
CMAKE_CXX_COMPILER:FILEPATH=/usr/local/bin/g++
|
||||
CMAKE_CXX_COMPILER:FILEPATH=g++
|
||||
|
||||
//Flags used by the compiler during all build types.
|
||||
CMAKE_CXX_FLAGS:STRING=
|
||||
|
@ -46,7 +46,7 @@ CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
|
|||
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
|
||||
|
||||
//C compiler
|
||||
CMAKE_C_COMPILER:FILEPATH=/usr/local/bin/gcc
|
||||
CMAKE_C_COMPILER:FILEPATH=gcc
|
||||
|
||||
//Flags used by the compiler during all build types.
|
||||
CMAKE_C_FLAGS:STRING=
|
||||
|
|
|
@ -27,7 +27,7 @@ CMAKE_AR:FILEPATH=/usr/bin/ar
|
|||
CMAKE_BUILD_TYPE:STRING=Debug
|
||||
|
||||
//CXX compiler
|
||||
CMAKE_CXX_COMPILER:FILEPATH=/usr/local/bin/clang++
|
||||
CMAKE_CXX_COMPILER:FILEPATH=clang++
|
||||
|
||||
//Flags used by the compiler during all build types.
|
||||
CMAKE_CXX_FLAGS:STRING=
|
||||
|
@ -46,7 +46,7 @@ CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
|
|||
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
|
||||
|
||||
//C compiler
|
||||
CMAKE_C_COMPILER:FILEPATH=/usr/local/bin/clang
|
||||
CMAKE_C_COMPILER:FILEPATH=clang
|
||||
|
||||
//Flags used by the compiler during all build types.
|
||||
CMAKE_C_FLAGS:STRING=
|
||||
|
|
|
@ -15,60 +15,70 @@ function getTestResourceFilePath(filename: string): string {
|
|||
return path.normalize(path.join(here, '../../../test/unit-tests', filename));
|
||||
}
|
||||
|
||||
suite.only('Select debugger', async () => {
|
||||
function getFakeBin(): string { return path.normalize(path.join(here, '../../../test/fakebin')); }
|
||||
|
||||
suite('Select debugger', async () => {
|
||||
let path_backup: string|undefined = '';
|
||||
|
||||
setup(() => {
|
||||
path_backup = process.env.PATH;
|
||||
process.env['PATH'] = getFakeBin();
|
||||
});
|
||||
|
||||
teardown(() => { process.env['PATH'] = path_backup; });
|
||||
|
||||
test('Create debug config from cache - clang', async () => {
|
||||
const target = {name: 'Test', path: 'Target'};
|
||||
const cache = await CMakeCache.fromPath(getTestResourceFilePath('TestCMakeCache.txt'));
|
||||
const config = Debugger.getDebugConfigurationFromCache(cache, target, 'linux');
|
||||
const config = await Debugger.getDebugConfigurationFromCache(cache, target, 'linux');
|
||||
|
||||
expect(config.name).to.be.eq('Debug Test');
|
||||
expect(config['MIMode']).to.be.eq('lldb');
|
||||
expect(config.type).to.be.eq('cppdbg');
|
||||
expect(config['miDebuggerPath']).to.be.eq('/usr/local/bin/lldb');
|
||||
expect(config['miDebuggerPath']).to.be.eq('lldb');
|
||||
});
|
||||
|
||||
test('Create debug config from cache - GCC', async () => {
|
||||
const target = {name: 'Test', path: 'Target'};
|
||||
const cache = await CMakeCache.fromPath(getTestResourceFilePath('TestCMakeCache-gcc.txt'));
|
||||
|
||||
const config = Debugger.getDebugConfigurationFromCache(cache, target, 'linux');
|
||||
const config = await Debugger.getDebugConfigurationFromCache(cache, target, 'linux');
|
||||
|
||||
expect(config.name).to.be.eq('Debug Test');
|
||||
expect(config['MIMode']).to.be.eq('gdb');
|
||||
expect(config.type).to.be.eq('cppdbg');
|
||||
expect(config['miDebuggerPath']).to.be.eq('/usr/local/bin/gdb');
|
||||
expect(config['miDebuggerPath']).to.be.eq('gdb');
|
||||
});
|
||||
|
||||
test('Create debug config from cache - GCC Apple', async () => {
|
||||
const target = {name: 'Test', path: 'Target'};
|
||||
const cache = await CMakeCache.fromPath(getTestResourceFilePath('TestCMakeCache-gcc.txt'));
|
||||
|
||||
const config = Debugger.getDebugConfigurationFromCache(cache, target, 'darwin');
|
||||
const config = await Debugger.getDebugConfigurationFromCache(cache, target, 'darwin');
|
||||
|
||||
expect(config.name).to.be.eq('Debug Test');
|
||||
expect(config['MIMode']).to.be.eq('lldb');
|
||||
expect(config.type).to.be.eq('cppdbg');
|
||||
expect(config['miDebuggerPath']).to.be.eq('/usr/local/bin/lldb');
|
||||
expect(config['miDebuggerPath']).to.be.eq('lldb');
|
||||
});
|
||||
|
||||
test('Create debug config from cache - g++', async () => {
|
||||
const target = {name: 'Test', path: 'Target'};
|
||||
const cache = await CMakeCache.fromPath(getTestResourceFilePath('TestCMakeCache-g++.txt'));
|
||||
|
||||
const config = Debugger.getDebugConfigurationFromCache(cache, target, 'linux');
|
||||
const config = await Debugger.getDebugConfigurationFromCache(cache, target, 'linux');
|
||||
|
||||
expect(config.name).to.be.eq('Debug Test');
|
||||
expect(config['MIMode']).to.be.eq('gdb');
|
||||
expect(config.type).to.be.eq('cppdbg');
|
||||
expect(config['miDebuggerPath']).to.be.eq('/usr/local/bin/gdb');
|
||||
expect(config['miDebuggerPath']).to.be.eq('gdb');
|
||||
});
|
||||
|
||||
|
||||
test('Create debug config from cache - Visual Studio Community 2017', async () => {
|
||||
const target = {name: 'Test', path: 'Target'};
|
||||
const cache = await CMakeCache.fromPath(getTestResourceFilePath('TestCMakeCache-msvc-com-2017.txt'));
|
||||
|
||||
const config = Debugger.getDebugConfigurationFromCache(cache, target, 'win32');
|
||||
const config = await Debugger.getDebugConfigurationFromCache(cache, target, 'win32');
|
||||
|
||||
expect(config.name).to.be.eq('Debug Test');
|
||||
expect(config.type).to.be.eq('cppvsdbg');
|
||||
|
|
Загрузка…
Ссылка в новой задаче