Dev/andris/makefile tools/pr107 compile commands (#177)
* Add compile_commands.json generator * Move compile commands parsing into parseCustomConfigProvider * Support a non clean configuration * Save the compilation database in the cache * Remove redundant setting and change slightly where compile_commands is calculated. * Implement PR feedback. Co-authored-by: Giulio Girardi <giulio.girardi@protechgroup.it>
This commit is contained in:
Родитель
2df46a4a15
Коммит
d1697e0e4c
|
@ -455,6 +455,12 @@
|
|||
"default": true,
|
||||
"description": "Clear the output channel at the beginning of a build",
|
||||
"scope": "resource"
|
||||
},
|
||||
"makefile.compileCommandsPath": {
|
||||
"type": "string",
|
||||
"default": null,
|
||||
"description": "The path to the compilation database file",
|
||||
"scope": "resource"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -295,6 +295,20 @@ export function readConfigurationCachePath(): void {
|
|||
logger.message(`Configurations cached at ${configurationCachePath}`);
|
||||
}
|
||||
|
||||
let compileCommandsPath: string | undefined;
|
||||
export function getCompileCommandsPath(): string | undefined { return compileCommandsPath; }
|
||||
export function setCompileCommandsPath(path: string): void { compileCommandsPath = path; }
|
||||
export function readCompileCommandsPath(): void {
|
||||
let workspaceConfiguration: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("makefile");
|
||||
|
||||
compileCommandsPath = workspaceConfiguration.get<string>("compileCommandsPath");
|
||||
if (compileCommandsPath) {
|
||||
compileCommandsPath = util.resolvePathToRoot(compileCommandsPath);
|
||||
}
|
||||
|
||||
logger.message(`compile_commands.json path: ${compileCommandsPath}`);
|
||||
}
|
||||
|
||||
let additionalCompilerNames: string[] | undefined;
|
||||
export function getAdditionalCompilerNames(): string[] | undefined { return additionalCompilerNames; }
|
||||
export function setAdditionalCompilerNames(compilerNames: string[]): void { additionalCompilerNames = compilerNames; }
|
||||
|
@ -841,6 +855,7 @@ export async function initFromStateAndSettings(): Promise<void> {
|
|||
readBuildBeforeLaunch();
|
||||
readClearOutputBeforeBuild();
|
||||
readIgnoreDirectoryCommands();
|
||||
readCompileCommandsPath();
|
||||
|
||||
analyzeConfigureParams();
|
||||
|
||||
|
@ -1180,6 +1195,16 @@ export async function initFromStateAndSettings(): Promise<void> {
|
|||
updatedSettingsSubkeys.push(subKey);
|
||||
}
|
||||
|
||||
subKey = "compileCommandsPath";
|
||||
let updatedCompileCommandsPath: string | undefined = workspaceConfiguration.get<string>(subKey);
|
||||
if (updatedCompileCommandsPath) {
|
||||
updatedCompileCommandsPath = util.resolvePathToRoot(updatedCompileCommandsPath);
|
||||
}
|
||||
if (updatedCompileCommandsPath !== compileCommandsPath) {
|
||||
readCompileCommandsPath();
|
||||
updatedSettingsSubkeys.push(subKey);
|
||||
}
|
||||
|
||||
// Final updates in some constructs that depend on more than one of the above settings.
|
||||
if (extension.getState().configureDirty) {
|
||||
analyzeConfigureParams();
|
||||
|
|
|
@ -6,14 +6,19 @@
|
|||
import * as configuration from './configuration';
|
||||
import * as logger from './logger';
|
||||
import * as make from './make';
|
||||
import * as parser from './parser';
|
||||
import * as path from 'path';
|
||||
import * as util from './util';
|
||||
import * as vscode from 'vscode';
|
||||
import * as cpp from 'vscode-cpptools';
|
||||
|
||||
export interface SourceFileConfigurationItem extends cpp.SourceFileConfigurationItem {
|
||||
readonly compileCommand: parser.CompileCommand;
|
||||
}
|
||||
|
||||
export interface CustomConfigurationProvider {
|
||||
workspaceBrowse: cpp.WorkspaceBrowseConfiguration;
|
||||
fileIndex: Map<string, cpp.SourceFileConfigurationItem>;
|
||||
fileIndex: Map<string, SourceFileConfigurationItem>;
|
||||
}
|
||||
|
||||
export class CppConfigurationProvider implements cpp.CustomConfigurationProvider {
|
||||
|
@ -22,13 +27,13 @@ export class CppConfigurationProvider implements cpp.CustomConfigurationProvider
|
|||
|
||||
private workspaceBrowseConfiguration: cpp.WorkspaceBrowseConfiguration = { browsePath: [] };
|
||||
|
||||
private getConfiguration(uri: vscode.Uri): cpp.SourceFileConfigurationItem | undefined {
|
||||
private getConfiguration(uri: vscode.Uri): SourceFileConfigurationItem | undefined {
|
||||
const norm_path: string = path.normalize(uri.fsPath);
|
||||
|
||||
// First look in the file index computed during the last configure.
|
||||
// If nothing is found and there is a configure running right now,
|
||||
// try also the temporary index of the current configure.
|
||||
let sourceFileConfiguration: cpp.SourceFileConfigurationItem | undefined = this.fileIndex.get(norm_path);
|
||||
let sourceFileConfiguration: SourceFileConfigurationItem | undefined = this.fileIndex.get(norm_path);
|
||||
if (!sourceFileConfiguration && make.getIsConfiguring()) {
|
||||
sourceFileConfiguration = make.getDeltaCustomConfigurationProvider().fileIndex.get(norm_path);
|
||||
logger.message(`Configuration for file ${norm_path} was not found. Searching in the current configure temporary file index.`);
|
||||
|
@ -80,7 +85,7 @@ export class CppConfigurationProvider implements cpp.CustomConfigurationProvider
|
|||
};
|
||||
}
|
||||
|
||||
let map: Map<string, cpp.SourceFileConfigurationItem> = this.fileIndex;
|
||||
let map: Map<string, SourceFileConfigurationItem> = this.fileIndex;
|
||||
provider.fileIndex.forEach(function(value, key): void {
|
||||
map.set(key, value);
|
||||
});
|
||||
|
@ -115,7 +120,7 @@ export class CppConfigurationProvider implements cpp.CustomConfigurationProvider
|
|||
|
||||
public dispose(): void { }
|
||||
|
||||
private fileIndex = new Map<string, cpp.SourceFileConfigurationItem>();
|
||||
private fileIndex = new Map<string, SourceFileConfigurationItem>();
|
||||
|
||||
public logConfigurationProviderBrowse(): void {
|
||||
logger.message("Sending Workspace Browse Configuration: -----------------------------------", "Verbose");
|
||||
|
@ -129,7 +134,7 @@ export class CppConfigurationProvider implements cpp.CustomConfigurationProvider
|
|||
logger.message("----------------------------------------------------------------------------", "Verbose");
|
||||
}
|
||||
|
||||
public logConfigurationProviderItem(filePath: cpp.SourceFileConfigurationItem, fromCache: boolean = false): void {
|
||||
public logConfigurationProviderItem(filePath: SourceFileConfigurationItem, fromCache: boolean = false): void {
|
||||
let uriObj: vscode.Uri = <vscode.Uri>filePath.uri;
|
||||
logger.message("Sending configuration " + (fromCache ? "(from cache) " : "") + "for file " + uriObj.fsPath + " -----------------------------------", "Normal");
|
||||
logger.message(" Defines: " + filePath.configuration.defines.join(";"), "Verbose");
|
||||
|
|
|
@ -137,9 +137,14 @@ export class MakefileToolsExtension {
|
|||
// of all the compiler invocations of the current configuration
|
||||
customConfigProviderItem.files.forEach(filePath => {
|
||||
let uri: vscode.Uri = vscode.Uri.file(filePath);
|
||||
let sourceFileConfigurationItem: cpp.SourceFileConfigurationItem = {
|
||||
let sourceFileConfigurationItem: cpptools.SourceFileConfigurationItem = {
|
||||
uri,
|
||||
configuration,
|
||||
compileCommand: {
|
||||
command: customConfigProviderItem.line,
|
||||
directory: customConfigProviderItem.currentPath,
|
||||
file: filePath
|
||||
}
|
||||
};
|
||||
|
||||
// These are the configurations processed during the current configure.
|
||||
|
|
13
src/make.ts
13
src/make.ts
|
@ -79,7 +79,7 @@ export enum TriggeredBy {
|
|||
launch = "Launch (debug|run)",
|
||||
}
|
||||
|
||||
let fileIndex: Map<string, cpp.SourceFileConfigurationItem> = new Map<string, cpp.SourceFileConfigurationItem>();
|
||||
let fileIndex: Map<string, cpptools.SourceFileConfigurationItem> = new Map<string, cpptools.SourceFileConfigurationItem>();
|
||||
let workspaceBrowseConfiguration: cpp.WorkspaceBrowseConfiguration = { browsePath: [] };
|
||||
export function getDeltaCustomConfigurationProvider(): cpptools.CustomConfigurationProvider {
|
||||
let provider: cpptools.CustomConfigurationProvider = {
|
||||
|
@ -711,6 +711,7 @@ interface ConfigurationCache {
|
|||
fileIndex: [string, {
|
||||
uri: string | vscode.Uri;
|
||||
configuration: cpp.SourceFileConfiguration;
|
||||
compileCommand: parser.CompileCommand;
|
||||
}][];
|
||||
};
|
||||
}
|
||||
|
@ -857,6 +858,8 @@ export async function configure(triggeredBy: TriggeredBy, updateTargets: boolean
|
|||
readCache = true;
|
||||
}
|
||||
|
||||
let compileCommandsPath: string | undefined = configuration.getCompileCommandsPath();
|
||||
|
||||
// Identify for telemetry whether:
|
||||
// - this configure will need to double the workload, if it needs to analyze the build targets separately.
|
||||
// - this configure will need to reset the build target to the default, which will need a reconfigure.
|
||||
|
@ -955,6 +958,12 @@ export async function configure(triggeredBy: TriggeredBy, updateTargets: boolean
|
|||
util.writeFile(configurationCachePath, JSON.stringify(ConfigurationCache));
|
||||
}
|
||||
|
||||
// Export the compile_commands.json file if the option is enabled.
|
||||
if (compileCommandsPath && retc !== ConfigureBuildReturnCodeTypes.cancelled) {
|
||||
let compileCommands: parser.CompileCommand[] = ConfigurationCache.customConfigurationProvider.fileIndex.map(([, {compileCommand}]) => compileCommand);
|
||||
util.writeFile(compileCommandsPath, JSON.stringify(compileCommands, undefined, 4));
|
||||
}
|
||||
|
||||
let newBuildTarget: string | undefined = configuration.getCurrentTarget();
|
||||
let configureElapsedTime: number = util.elapsedTimeSince(configureStartTime);
|
||||
const telemetryMeasures: telemetry.Measures = {
|
||||
|
@ -1246,7 +1255,7 @@ export async function loadConfigurationFromCache(progress: vscode.Progress<{}>,
|
|||
extension.getCppConfigurationProvider().setCustomConfigurationProvider({
|
||||
workspaceBrowse: configurationCache.customConfigurationProvider.workspaceBrowse,
|
||||
// Trick to read a map from json
|
||||
fileIndex: new Map<string, cpp.SourceFileConfigurationItem>(configurationCache.customConfigurationProvider.fileIndex)
|
||||
fileIndex: new Map<string, cpptools.SourceFileConfigurationItem>(configurationCache.customConfigurationProvider.fileIndex)
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -834,6 +834,16 @@ async function currentPathAfterCommand(line: string, currentPathHistory: string[
|
|||
return currentPathHistory;
|
||||
}
|
||||
|
||||
// Structure used to describe a compilation command. Reference documentation is
|
||||
// hosted here https://clang.llvm.org/docs/JSONCompilationDatabase.html
|
||||
export interface CompileCommand {
|
||||
directory: string;
|
||||
file: string;
|
||||
command: string;
|
||||
arguments?: string[];
|
||||
output?: string;
|
||||
}
|
||||
|
||||
export interface CustomConfigProviderItem {
|
||||
defines: string[];
|
||||
includes: string[];
|
||||
|
@ -844,11 +854,15 @@ export interface CustomConfigProviderItem {
|
|||
compilerArgs: string[];
|
||||
files: string[];
|
||||
windowsSDKVersion?: string;
|
||||
currentPath: string;
|
||||
line: string;
|
||||
}
|
||||
|
||||
// Parse the output of the make dry-run command in order to provide CppTools
|
||||
// with information about includes, defines, compiler path....etc...
|
||||
// as needed by CustomConfigurationProvider
|
||||
// as needed by CustomConfigurationProvider. In addition generate a
|
||||
// CompileCommand entry for every file with a compiler invocation to build
|
||||
// a compile_commands.json file.
|
||||
export async function parseCustomConfigProvider(cancel: vscode.CancellationToken, dryRunOutputStr: string,
|
||||
statusCallback: (message: string) => void,
|
||||
onFoundCustomConfigProviderItem: (customConfigProviderItem: CustomConfigProviderItem) => void): Promise<number> {
|
||||
|
@ -955,8 +969,9 @@ export async function parseCustomConfigProvider(cancel: vscode.CancellationToken
|
|||
if (language) {
|
||||
// More standard validation and defaults, in the context of the whole command.
|
||||
let standard: util.StandardVersion = parseStandard(ext.extension.getCppToolsVersion(), standardStr, language);
|
||||
|
||||
if (ext.extension) {
|
||||
onFoundCustomConfigProviderItem({ defines, includes, forcedIncludes, standard, intelliSenseMode, compilerFullPath, compilerArgs, files, windowsSDKVersion });
|
||||
onFoundCustomConfigProviderItem({ defines, includes, forcedIncludes, standard, intelliSenseMode, compilerFullPath, compilerArgs, files, windowsSDKVersion, currentPath, line });
|
||||
}
|
||||
} else {
|
||||
// If the compiler command is mixing c and c++ source files, send a custom configuration for each of the source files separately,
|
||||
|
@ -970,8 +985,9 @@ export async function parseCustomConfigProvider(cancel: vscode.CancellationToken
|
|||
|
||||
// More standard validation and defaults, in the context of each source file.
|
||||
let standard: util.StandardVersion = parseStandard(ext.extension.getCppToolsVersion(), standardStr, language);
|
||||
|
||||
if (ext.extension) {
|
||||
onFoundCustomConfigProviderItem({ defines, includes, forcedIncludes, standard, intelliSenseMode, compilerFullPath, compilerArgs, files: [file], windowsSDKVersion });
|
||||
onFoundCustomConfigProviderItem({ defines, includes, forcedIncludes, standard, intelliSenseMode, compilerFullPath, compilerArgs, files: [file], windowsSDKVersion, currentPath, line });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче