aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRabsRincon <ruben@rinconblanco.es>2022-09-12 09:13:35 +0200
committerRabsRincon <ruben@rinconblanco.es>2022-09-12 09:13:35 +0200
commit2a310b31867069dc4915d1a45124f0d4c8eb0bc2 (patch)
tree9bbd94d9de590f313c7d71918a974731f3acb932
parent8000ee89124a0c1c94a686cd8f7898b054679193 (diff)
downloadcompiler-explorer-gh-4189.tar.gz
compiler-explorer-gh-4189.zip
Properly tsfy base-toolsgh-4189
-rw-r--r--lib/base-compiler.ts3
-rwxr-xr-xlib/options-handler.js31
-rwxr-xr-xlib/tooling/base-tool.interface.ts49
-rwxr-xr-xlib/tooling/base-tool.ts80
-rw-r--r--lib/tooling/compiler-dropin-tool.js4
-rw-r--r--lib/tooling/llvm-cov-tool.ts36
-rw-r--r--lib/utils.ts9
-rw-r--r--test/options-handler.js2
-rw-r--r--types/compilation/compilation.interfaces.ts5
9 files changed, 137 insertions, 82 deletions
diff --git a/lib/base-compiler.ts b/lib/base-compiler.ts
index 3f78031e2..ac9efd3a8 100644
--- a/lib/base-compiler.ts
+++ b/lib/base-compiler.ts
@@ -72,6 +72,7 @@ import {IAsmParser} from './parsers/asm-parser.interfaces';
import {LlvmPassDumpParser} from './parsers/llvm-pass-dump-parser';
import {getToolchainPath} from './toolchain-utils';
import * as utils from './utils';
+import {ToolTypeKey} from './tooling/base-tool.interface';
export class BaseCompiler {
public compiler: any;
@@ -1300,7 +1301,7 @@ export class BaseCompiler {
return this.postProcess(asmResult, outputFilename, filters);
}
- runToolsOfType(tools, type, compilationInfo): Promise<ToolResult>[] {
+ runToolsOfType(tools, type: ToolTypeKey, compilationInfo): Promise<ToolResult>[] {
const tooling: Promise<ToolResult>[] = [];
if (tools) {
for (const tool of tools) {
diff --git a/lib/options-handler.js b/lib/options-handler.js
index 953817c4f..21e754bec 100755
--- a/lib/options-handler.js
+++ b/lib/options-handler.js
@@ -31,7 +31,7 @@ import _ from 'underscore';
import {logger} from './logger';
import {getToolTypeByKey} from './tooling';
-import {asSafeVer, getHash, splitArguments} from './utils';
+import {asSafeVer, getHash, splitArguments, splitIntoArray} from './utils';
/***
* Handles the setup of the options object passed on each page request
@@ -143,7 +143,7 @@ export class ClientOptionsHandler {
name: this.compilerProps(lang, toolBaseName + '.name'),
type: this.compilerProps(lang, toolBaseName + '.type'),
exe: toolPath,
- exclude: this.compilerProps(lang, toolBaseName + '.exclude'),
+ exclude: splitIntoArray(this.compilerProps(lang, toolBaseName + '.exclude')),
includeKey: this.compilerProps(lang, toolBaseName + '.includeKey'),
options: splitArguments(this.compilerProps(lang, toolBaseName + '.options')),
args: this.compilerProps(lang, toolBaseName + '.args'),
@@ -168,14 +168,6 @@ export class ClientOptionsHandler {
return tools;
}
- splitIntoArray(value, defaultArr) {
- if (value) {
- return value.split(':');
- } else {
- return defaultArr;
- }
- }
-
parseLibraries(baseLibs) {
const libraries = {};
for (const [lang, forLang] of Object.entries(baseLibs)) {
@@ -187,14 +179,11 @@ export class ClientOptionsHandler {
name: this.compilerProps(lang, libBaseName + '.name'),
url: this.compilerProps(lang, libBaseName + '.url'),
description: this.compilerProps(lang, libBaseName + '.description'),
- staticliblink: this.splitIntoArray(
- this.compilerProps(lang, libBaseName + '.staticliblink'),
- [],
- ),
- liblink: this.splitIntoArray(this.compilerProps(lang, libBaseName + '.liblink'), []),
- dependencies: this.splitIntoArray(this.compilerProps(lang, libBaseName + '.dependencies'), []),
+ staticliblink: splitIntoArray(this.compilerProps(lang, libBaseName + '.staticliblink')),
+ liblink: splitIntoArray(this.compilerProps(lang, libBaseName + '.liblink')),
+ dependencies: splitIntoArray(this.compilerProps(lang, libBaseName + '.dependencies')),
versions: {},
- examples: this.splitIntoArray(this.compilerProps(lang, libBaseName + '.examples'), []),
+ examples: splitIntoArray(this.compilerProps(lang, libBaseName + '.examples')),
options: splitArguments(this.compilerProps(lang, libBaseName + '.options', '')),
};
const listedVersions = `${this.compilerProps(lang, libBaseName + '.versions')}`;
@@ -203,18 +192,18 @@ export class ClientOptionsHandler {
const libVersionName = libBaseName + `.versions.${version}`;
const versionObject = {
version: this.compilerProps(lang, libVersionName + '.version'),
- staticliblink: this.splitIntoArray(
+ staticliblink: splitIntoArray(
this.compilerProps(lang, libVersionName + '.staticliblink'),
libraries[lang][lib].staticliblink,
),
- alias: this.splitIntoArray(this.compilerProps(lang, libVersionName + '.alias'), []),
- dependencies: this.splitIntoArray(
+ alias: splitIntoArray(this.compilerProps(lang, libVersionName + '.alias')),
+ dependencies: splitIntoArray(
this.compilerProps(lang, libVersionName + '.dependencies'),
libraries[lang][lib].dependencies,
),
path: [],
libpath: [],
- liblink: this.splitIntoArray(
+ liblink: splitIntoArray(
this.compilerProps(lang, libVersionName + '.liblink'),
libraries[lang][lib].liblink,
),
diff --git a/lib/tooling/base-tool.interface.ts b/lib/tooling/base-tool.interface.ts
new file mode 100755
index 000000000..afc092d21
--- /dev/null
+++ b/lib/tooling/base-tool.interface.ts
@@ -0,0 +1,49 @@
+// Copyright (c) 2022, Compiler Explorer Authors
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+import {LanguageKey} from '../../types/languages.interfaces';
+
+export type ToolTypeKey = 'independent' | 'postcompilation';
+
+export type ToolInfo = {
+ id: string;
+ name?: string;
+ type?: ToolTypeKey;
+ exe: string;
+ exclude: string[];
+ includeKey?: string;
+ options: string[];
+ args?: string;
+ languageId?: LanguageKey;
+ stdinHint?: string;
+ monacoStdin?: string;
+ icon?: string;
+ darkIcon?: string;
+ compilerLanguage: LanguageKey;
+};
+
+export type ToolEnv = {
+ ceProps: (key: string, defaultValue?: any) => string | boolean | number | undefined;
+ compilerProps: (key: string, defaultValue?: any) => string | boolean | number | undefined;
+};
diff --git a/lib/tooling/base-tool.ts b/lib/tooling/base-tool.ts
index dac1a6f5f..aae1449f6 100755
--- a/lib/tooling/base-tool.ts
+++ b/lib/tooling/base-tool.ts
@@ -27,11 +27,15 @@ import path from 'path';
import PromClient from 'prom-client';
import _ from 'underscore';
+import {ExecutionOptions, ToolResult} from '../../types/compilation/compilation.interfaces';
+import {ResultLine} from '../../types/resultline/resultline.interfaces';
import * as exec from '../exec';
import {logger} from '../logger';
-import * as utils from '../utils';
-import {ToolEnv, ToolInfo} from './base-tool.interface';
-import {ExecutionOptions} from '../../types/compilation/compilation.interfaces';
+import {parseOutput} from '../utils';
+
+import {ToolEnv, ToolInfo, ToolTypeKey} from './base-tool.interface';
+import {UnprocessedExecResult} from '../../types/execution/execution.interfaces';
+import {Library, SelectedLibraryVersion} from '../../types/libraries/libraries.interfaces';
const toolCounter = new PromClient.Counter({
name: 'tool_invocations_total',
@@ -39,29 +43,22 @@ const toolCounter = new PromClient.Counter({
labelNames: ['language', 'name'],
});
-type BaseToolInfo = Omit<ToolInfo, 'exclude'> & {exclude?: string};
-
export class BaseTool {
protected tool: ToolInfo;
private env: ToolEnv;
private addOptionsToToolArgs = true;
- protected parseOutput: (...args: any[]) => any;
- constructor(toolInfo: BaseToolInfo, env: ToolEnv) {
- this.tool = {
- ...toolInfo,
- exclude: toolInfo.exclude ? toolInfo.exclude.split(':') : [],
- };
+ constructor(toolInfo: ToolInfo, env: ToolEnv) {
+ this.tool = toolInfo;
this.env = env;
this.addOptionsToToolArgs = true;
- this.parseOutput = utils.parseOutput;
}
getId() {
return this.tool.id;
}
- getType() {
+ getType(): ToolTypeKey {
return this.tool.type || 'independent';
}
@@ -71,7 +68,7 @@ export class BaseTool {
return this.tool.id.replace(/[^\da-z]/gi, '_') + timestamp_str + '_';
}
- isCompilerExcluded(compilerId: string, compilerProps: ToolEnv['compilerProps']) {
+ isCompilerExcluded(compilerId: string, compilerProps: ToolEnv['compilerProps']): boolean {
if (this.tool.includeKey) {
// If the includeKey is set, we only support compilers that have a truthy 'includeKey'.
if (!compilerProps(this.tool.includeKey)) {
@@ -79,7 +76,7 @@ export class BaseTool {
}
// Even if the include key is truthy, we fall back to the exclusion list.
}
- return this.tool.exclude.find(excl => compilerId.includes(excl));
+ return this.tool.exclude.find(excl => compilerId.includes(excl)) !== undefined;
}
exec(toolExe: string, args: string[], options: ExecutionOptions) {
@@ -94,19 +91,24 @@ export class BaseTool {
};
}
- createErrorResponse(message: string) {
+ // By default calls utils.parseOutput, but lets subclasses override their output processing
+ protected parseOutput(lines: string, inputFilename?: string, pathPrefix?: string): ResultLine[] {
+ return parseOutput(lines, inputFilename, pathPrefix);
+ }
+
+ createErrorResponse(message: string): ToolResult {
return {
id: this.tool.id,
name: this.tool.name,
code: -1,
languageId: 'stderr',
stdout: [],
- stderr: utils.parseOutput(message),
+ stderr: this.parseOutput(message),
};
}
// mostly copy&paste from base-compiler.js
- findLibVersion(selectedLib, supportedLibraries) {
+ findLibVersion(selectedLib: SelectedLibraryVersion, supportedLibraries: Record<string, Library>) {
const foundLib = _.find(supportedLibraries, (o, libId) => libId === selectedLib.id);
if (!foundLib) return false;
@@ -114,38 +116,40 @@ export class BaseTool {
}
// mostly copy&paste from base-compiler.js
- getIncludeArguments(libraries, supportedLibraries) {
+ getIncludeArguments(libraries: SelectedLibraryVersion[], supportedLibraries: Record<string, Library>): string[] {
const includeFlag = '-I';
- return _.flatten(
- _.map(libraries, selectedLib => {
- const foundVersion = this.findLibVersion(selectedLib, supportedLibraries);
- if (!foundVersion) return false;
+ return libraries.flatMap(selectedLib => {
+ const foundVersion = this.findLibVersion(selectedLib, supportedLibraries);
+ if (!foundVersion) return [];
- return _.map(foundVersion.path, path => includeFlag + path);
- }),
- );
+ return foundVersion.path.map(path => includeFlag + path);
+ });
}
- getLibraryOptions(libraries, supportedLibraries) {
- return _.flatten(
- _.map(libraries, selectedLib => {
- const foundVersion = this.findLibVersion(selectedLib, supportedLibraries);
- if (!foundVersion) return false;
+ getLibraryOptions(libraries: SelectedLibraryVersion[], supportedLibraries: Record<string, Library>): string[] {
+ return libraries.flatMap(selectedLib => {
+ const foundVersion = this.findLibVersion(selectedLib, supportedLibraries);
+ if (!foundVersion) return [];
- return foundVersion.options;
- }),
- );
+ return foundVersion.options;
+ });
}
- async runTool(compilationInfo, inputFilepath, args, stdin /*, supportedLibraries*/) {
+ async runTool(
+ compilationInfo: Record<any, any>,
+ inputFilepath?: string,
+ args?: string[],
+ stdin?: string,
+ supportedLibraries?: Record<string, Library>,
+ ) {
if (this.tool.name) {
toolCounter.inc({
language: compilationInfo.compiler.lang,
name: this.tool.name,
});
}
- const execOptions = this.getDefaultExecOptions() as ExecutionOptions;
+ const execOptions = this.getDefaultExecOptions();
if (inputFilepath) execOptions.customCwd = path.dirname(inputFilepath);
execOptions.input = stdin;
@@ -164,8 +168,8 @@ export class BaseTool {
}
}
- convertResult(result, inputFilepath, exeDir) {
- const transformedFilepath = result.filenameTransform(inputFilepath);
+ convertResult(result: UnprocessedExecResult, inputFilepath?: string, exeDir?: string): ToolResult {
+ const transformedFilepath = inputFilepath ? result.filenameTransform(inputFilepath) : undefined;
return {
id: this.tool.id,
name: this.tool.name,
diff --git a/lib/tooling/compiler-dropin-tool.js b/lib/tooling/compiler-dropin-tool.js
index ab7be7c33..31a52b1a1 100644
--- a/lib/tooling/compiler-dropin-tool.js
+++ b/lib/tooling/compiler-dropin-tool.js
@@ -101,8 +101,8 @@ export class CompilerDropinTool extends BaseTool {
async runTool(compilationInfo, inputFilepath, args, stdin, supportedLibraries) {
const sourcefile = inputFilepath;
- const includeflags = super.getIncludeArguments(compilationInfo.libraries, supportedLibraries);
- const libOptions = super.getLibraryOptions(compilationInfo.libraries, supportedLibraries);
+ const includeflags = this.getIncludeArguments(compilationInfo.libraries, supportedLibraries);
+ const libOptions = this.getLibraryOptions(compilationInfo.libraries, supportedLibraries);
const compileFlags = this.getOrderedArguments(compilationInfo, includeflags, libOptions, args, sourcefile);
if (!compileFlags) {
diff --git a/lib/tooling/llvm-cov-tool.ts b/lib/tooling/llvm-cov-tool.ts
index 0fd24e356..adf12ffe5 100644
--- a/lib/tooling/llvm-cov-tool.ts
+++ b/lib/tooling/llvm-cov-tool.ts
@@ -22,26 +22,34 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
-import fs from 'fs-extra';
import path from 'path';
-import {logger} from '../logger';
-import {BaseTool} from './base-tool';
import {ExecutionOptions} from '../../types/compilation/compilation.interfaces';
+import {BaseTool} from './base-tool';
+
export class LLVMCovTool extends BaseTool {
static get key() {
return 'llvm-cov-tool';
}
- override async runTool(compilationInfo, inputFilepath, args, stdin /*, supportedLibraries*/) {
- const compilationExecOptions = this.getDefaultExecOptions() as ExecutionOptions;
+ override async runTool(compilationInfo, inputFilepath, args, stdin) {
+ const compilationExecOptions = this.getDefaultExecOptions();
compilationExecOptions.customCwd = path.dirname(inputFilepath);
compilationExecOptions.input = stdin;
try {
+ const generatedExecutableName = this.getUniqueFilePrefix() + '-coverage.a';
const compilationResult = await this.exec(
compilationInfo.compiler.exe,
- ['-fprofile-instr-generate', '-fcoverage-mapping', '-g', '-O0', inputFilepath, '-o', 'coverage.a'],
+ [
+ '-fprofile-instr-generate',
+ '-fcoverage-mapping',
+ '-g',
+ '-O0',
+ inputFilepath,
+ '-o',
+ generatedExecutableName,
+ ],
compilationExecOptions,
);
@@ -54,7 +62,7 @@ export class LLVMCovTool extends BaseTool {
const runExecOptions = this.getDefaultExecOptions() as ExecutionOptions;
runExecOptions.customCwd = path.dirname(inputFilepath);
- await this.exec('./coverage.a', [], {
+ await this.exec('./' + generatedExecutableName, [], {
...runExecOptions,
input: stdin,
});
@@ -62,9 +70,10 @@ export class LLVMCovTool extends BaseTool {
const folder = path.dirname(this.tool.exe);
const profdataPath = path.join(folder, 'llvm-profdata');
+ const generatedProfdataName = this.getUniqueFilePrefix() + '.profdata';
const profdataResult = await this.exec(
profdataPath,
- ['merge', '-sparse', './default.profraw', '-o', './coverage.profdata'],
+ ['merge', '-sparse', './default.profraw', '-o', './' + generatedProfdataName],
runExecOptions,
);
if (profdataResult.code !== 0) {
@@ -73,20 +82,15 @@ export class LLVMCovTool extends BaseTool {
);
}
- const cppFiltPath = path.join(folder, 'llvm-cxxfilt');
const covResult = await this.exec(
this.tool.exe,
[
'show',
- './coverage.a',
- '-instr-profile=./coverage.profdata',
+ './' + generatedExecutableName,
+ '-instr-profile=./' + generatedProfdataName,
'-format',
'text',
'-use-color',
- '-Xdemangler',
- cppFiltPath,
- '-Xdemangler',
- '-n',
'-compilation-dir=./',
...args,
],
@@ -98,7 +102,7 @@ export class LLVMCovTool extends BaseTool {
return this.createErrorResponse(`<llvm-cov error>\n${covResult.stdout}\n${covResult.stderr}`);
}
} catch (e) {
- return this.createErrorResponse(`<Tool error: ${e}`);
+ return this.createErrorResponse(`<Tool error: ${e}>`);
}
}
}
diff --git a/lib/utils.ts b/lib/utils.ts
index 840c9cb79..dc3087528 100644
--- a/lib/utils.ts
+++ b/lib/utils.ts
@@ -367,6 +367,15 @@ export function base32Encode(buffer: Buffer): string {
return output;
}
+// Splits a : separated list into its own array, or to default if input is undefined
+export function splitIntoArray(input?: string, defaultArray: string[] = []): string[] {
+ if (input !== undefined) {
+ return input.split(':');
+ } else {
+ return defaultArray;
+ }
+}
+
export function splitArguments(options = ''): string[] {
// escape hashes first, otherwise they're interpreted as comments
const escapedOptions = options.replaceAll(/#/g, '\\#');
diff --git a/test/options-handler.js b/test/options-handler.js
index 80ab8c80a..fd8253ced 100644
--- a/test/options-handler.js
+++ b/test/options-handler.js
@@ -511,7 +511,6 @@ describe('Options handler', () => {
fake: {
faketool: {
addOptionsToToolArgs: true,
- parseOutput: parseOutput,
tool: {
args: undefined,
compilerLanguage: 'fake',
@@ -531,7 +530,6 @@ describe('Options handler', () => {
},
someothertool: {
addOptionsToToolArgs: true,
- parseOutput: parseOutput,
tool: {
args: undefined,
compilerLanguage: 'fake',
diff --git a/types/compilation/compilation.interfaces.ts b/types/compilation/compilation.interfaces.ts
index 3f1703b0f..6d686ace5 100644
--- a/types/compilation/compilation.interfaces.ts
+++ b/types/compilation/compilation.interfaces.ts
@@ -23,6 +23,7 @@
// POSSIBILITY OF SUCH DAMAGE.
import {BuildEnvDownloadInfo} from '../../lib/buildenvsetup/buildenv.interfaces';
+import {LanguageKey} from '../languages.interfaces';
import {ResultLine} from '../resultline/resultline.interfaces';
export type CompilationResult = {
@@ -114,9 +115,9 @@ export type Artifact = {
export type ToolResult = {
id: string;
- name: string;
+ name?: string;
code: number;
- languageId: string;
+ languageId?: LanguageKey | 'stderr';
stderr: ResultLine[];
stdout: ResultLine[];
artifact?: Artifact;