mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2026-05-16 19:31:45 -04:00
Compiler overrides (#5001)
This commit is contained in:
@@ -61,6 +61,10 @@ const compilerParsers = {
|
||||
ts: Parsers.TypeScriptNativeParser,
|
||||
turboc: Parsers.TurboCParser,
|
||||
toit: Parsers.ToitParser,
|
||||
circle: Parsers.CircleParser,
|
||||
ghc: Parsers.GHCParser,
|
||||
tendra: Parsers.TendraParser,
|
||||
golang: Parsers.GolangParser,
|
||||
};
|
||||
|
||||
class CompilerArgsApp {
|
||||
@@ -88,28 +92,64 @@ class CompilerArgsApp {
|
||||
}
|
||||
}
|
||||
|
||||
async doTheParsing() {
|
||||
async getPossibleStdvers() {
|
||||
const parser = this.getParser();
|
||||
return await parser.getPossibleStdvers(this.compiler);
|
||||
}
|
||||
|
||||
async getPossibleTargets() {
|
||||
const parser = this.getParser();
|
||||
return await parser.getPossibleTargets(this.compiler);
|
||||
}
|
||||
|
||||
async getPossibleEditions() {
|
||||
const parser = this.getParser();
|
||||
return await parser.getPossibleEditions(this.compiler);
|
||||
}
|
||||
|
||||
getParser() {
|
||||
if (compilerParsers[this.parserName]) {
|
||||
const parser = compilerParsers[this.parserName];
|
||||
await parser.parse(this.compiler);
|
||||
return compilerParsers[this.parserName];
|
||||
} else {
|
||||
console.error('Unknown parser type');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
print() {
|
||||
async doTheParsing() {
|
||||
const parser = this.getParser();
|
||||
await parser.parse(this.compiler);
|
||||
const options = this.compiler.possibleArguments.possibleArguments;
|
||||
if (parser.hasSupportStartsWith(options, '--target=')) {
|
||||
console.log('supportsTargetIs');
|
||||
} else if (parser.hasSupportStartsWith(options, '--target ')) {
|
||||
console.log('supportsTarget');
|
||||
} else if (parser.hasSupportStartsWith(options, '--march=')) {
|
||||
console.log('supportsMarch');
|
||||
} else {
|
||||
console.log('none of the things?');
|
||||
}
|
||||
}
|
||||
|
||||
async print() {
|
||||
const args = _.keys(this.compiler.possibleArguments.possibleArguments);
|
||||
for (const arg of args) {
|
||||
console.log(padRight(arg, this.pad) + this.compiler.possibleArguments.possibleArguments[arg].description);
|
||||
}
|
||||
|
||||
console.log('Stdvers:');
|
||||
console.log(await this.getPossibleStdvers());
|
||||
console.log('Targets:');
|
||||
console.log(await this.getPossibleTargets());
|
||||
console.log('Editions:');
|
||||
console.log(await this.getPossibleEditions());
|
||||
}
|
||||
}
|
||||
|
||||
if (!opts.parser || !opts.exe) {
|
||||
console.error(
|
||||
'Usage: ' +
|
||||
'node -r esm -r ts-node/register compiler-args-app.ts ' +
|
||||
'ts-node-esm compiler-args-app.ts ' +
|
||||
'--parser=<compilertype> --exe=<path> [--padding=<number>]\n' +
|
||||
'for example: --parser=clang --exe=/opt/compiler-explorer/clang-15.0.0/bin/clang++ --padding=50',
|
||||
);
|
||||
@@ -117,8 +157,6 @@ if (!opts.parser || !opts.exe) {
|
||||
} else {
|
||||
const app = new CompilerArgsApp();
|
||||
app.doTheParsing()
|
||||
.then(() => {
|
||||
app.print();
|
||||
})
|
||||
.then(() => app.print())
|
||||
.catch(e => console.error(e));
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ import type {BuildEnvDownloadInfo} from './buildenvsetup/buildenv.interfaces.js'
|
||||
import * as cfg from './cfg/cfg.js';
|
||||
import {CompilationEnvironment} from './compilation-env.js';
|
||||
import {CompilerArguments} from './compiler-arguments.js';
|
||||
import {ClangParser, GCCParser} from './compilers/argument-parsers.js';
|
||||
import {ClangParser, GCCParser, ICCParser} from './compilers/argument-parsers.js';
|
||||
import {BaseDemangler, getDemanglerTypeByKey} from './demangler/index.js';
|
||||
import {LLVMIRDemangler} from './demangler/llvm.js';
|
||||
import * as exec from './exec.js';
|
||||
@@ -78,10 +78,27 @@ import {AsmParser} from './parsers/asm-parser.js';
|
||||
import type {IAsmParser} from './parsers/asm-parser.interfaces.js';
|
||||
import {LlvmPassDumpParser} from './parsers/llvm-pass-dump-parser.js';
|
||||
import type {PropertyGetter} from './properties.interfaces.js';
|
||||
import {getToolchainPath, removeToolchainArg} from './toolchain-utils.js';
|
||||
import {
|
||||
clang_style_sysroot_flag,
|
||||
getSpecificTargetBasedOnToolchainPath,
|
||||
getSysrootByToolchainPath,
|
||||
getToolchainFlagFromOptions,
|
||||
getToolchainPath,
|
||||
hasSysrootArg,
|
||||
hasToolchainArg,
|
||||
removeToolchainArg,
|
||||
replaceSysrootArg,
|
||||
replaceToolchainArg,
|
||||
} from './toolchain-utils.js';
|
||||
import type {ITool} from './tooling/base-tool.interface.js';
|
||||
import * as utils from './utils.js';
|
||||
import {unwrap} from './assert.js';
|
||||
import {
|
||||
CompilerOverrideOption,
|
||||
CompilerOverrideOptions,
|
||||
CompilerOverrideType,
|
||||
ConfiguredOverrides,
|
||||
} from '../types/compilation/compiler-overrides.interfaces.js';
|
||||
|
||||
const compilationTimeHistogram = new PromClient.Histogram({
|
||||
name: 'ce_base_compiler_compilation_duration_seconds',
|
||||
@@ -95,6 +112,18 @@ const executionTimeHistogram = new PromClient.Histogram({
|
||||
buckets: [0.1, 0.5, 1, 5, 10, 20, 30],
|
||||
});
|
||||
|
||||
export const c_default_target_description =
|
||||
'Change the target architecture of the compiler. ' +
|
||||
'Be aware that the architecture might not be fully supported by the compiler' +
|
||||
' eventhough the option is available. ' +
|
||||
'The compiler might also require additional arguments to be fully functional.';
|
||||
|
||||
export const c_default_toolchain_description =
|
||||
'Change the default GCC toolchain for this compiler. ' +
|
||||
'This may or may not affect header usage (e.g. libstdc++ version) and linking to GCCs pre-built binaries.';
|
||||
|
||||
export const c_value_placeholder = '<value>';
|
||||
|
||||
export class BaseCompiler implements ICompiler {
|
||||
protected compiler: CompilerInfo; // TODO: Some missing types still present in Compiler type
|
||||
public lang: Language;
|
||||
@@ -288,6 +317,7 @@ export class BaseCompiler implements ICompiler {
|
||||
env.CC = this.compiler.exe;
|
||||
}
|
||||
|
||||
// TODO(#5051): support changing of toolchainPath per compile
|
||||
if (this.toolchainPath) {
|
||||
if (process.platform === 'win32') {
|
||||
const ldPath = `${this.toolchainPath}/bin/ld.exe`;
|
||||
@@ -348,6 +378,11 @@ export class BaseCompiler implements ICompiler {
|
||||
options.ldPath = this.getSharedLibraryPathsAsLdLibraryPaths([]);
|
||||
}
|
||||
|
||||
if (options.createAndUseTempDir) {
|
||||
const tmpDir = await this.newTempDir();
|
||||
options.customCwd = tmpDir;
|
||||
}
|
||||
|
||||
const key = this.getCompilerCacheKey(compiler, args, options);
|
||||
let result = await this.env.compilerCacheGet(key as any);
|
||||
if (!result) {
|
||||
@@ -364,6 +399,8 @@ export class BaseCompiler implements ICompiler {
|
||||
}
|
||||
}
|
||||
|
||||
if (options.createAndUseTempDir) fs.remove(options.customCwd);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -813,13 +850,13 @@ export class BaseCompiler implements ICompiler {
|
||||
) as string[];
|
||||
}
|
||||
|
||||
protected getSharedLibraryPathsAsArguments(libraries, libDownloadPath?) {
|
||||
protected getSharedLibraryPathsAsArguments(libraries, libDownloadPath?: string, toolchainPath?: string) {
|
||||
const pathFlag = this.compiler.rpathFlag || '-Wl,-rpath,';
|
||||
const libPathFlag = this.compiler.libpathFlag || '-L';
|
||||
|
||||
let toolchainLibraryPaths: string[] = [];
|
||||
if (this.toolchainPath) {
|
||||
toolchainLibraryPaths = [path.join(this.toolchainPath, '/lib64'), path.join(this.toolchainPath, '/lib32')];
|
||||
if (toolchainPath) {
|
||||
toolchainLibraryPaths = [path.join(toolchainPath, '/lib64'), path.join(toolchainPath, '/lib32')];
|
||||
}
|
||||
|
||||
if (!libDownloadPath) {
|
||||
@@ -900,6 +937,88 @@ export class BaseCompiler implements ICompiler {
|
||||
);
|
||||
}
|
||||
|
||||
getDefaultOrOverridenToolchainPath(overrides: ConfiguredOverrides): string {
|
||||
for (const override of overrides) {
|
||||
if (override.value) {
|
||||
const possible = this.compiler.possibleOverrides?.find(ov => ov.name === override.name);
|
||||
if (possible && possible.name === CompilerOverrideType.toolchain) {
|
||||
return override.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.toolchainPath;
|
||||
}
|
||||
|
||||
getOverridenToolchainPath(overrides: ConfiguredOverrides): string | false {
|
||||
for (const override of overrides) {
|
||||
if (override.value) {
|
||||
const possible = this.compiler.possibleOverrides?.find(ov => ov.name === override.name);
|
||||
if (possible && possible.name === CompilerOverrideType.toolchain) {
|
||||
return override.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
changeOptionsBasedOnOverrides(options: string[], overrides: ConfiguredOverrides): string[] {
|
||||
const overriddenToolchainPath = this.getOverridenToolchainPath(overrides);
|
||||
const sysrootPath: string | false =
|
||||
overriddenToolchainPath ?? getSysrootByToolchainPath(overriddenToolchainPath);
|
||||
|
||||
for (const override of overrides) {
|
||||
if (override.value) {
|
||||
const possible = this.compiler.possibleOverrides?.find(ov => ov.name === override.name);
|
||||
if (!possible) continue;
|
||||
|
||||
switch (possible.name) {
|
||||
case CompilerOverrideType.toolchain: {
|
||||
if (hasToolchainArg(options)) {
|
||||
options = replaceToolchainArg(options, override.value);
|
||||
} else {
|
||||
for (const flag of possible.flags) {
|
||||
options.push(flag.replace(c_value_placeholder, override.value));
|
||||
}
|
||||
}
|
||||
|
||||
if (sysrootPath) {
|
||||
if (hasSysrootArg(options)) {
|
||||
options = replaceSysrootArg(options, sysrootPath);
|
||||
} else {
|
||||
options.push(clang_style_sysroot_flag + sysrootPath);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CompilerOverrideType.arch: {
|
||||
let betterTarget = override.value;
|
||||
if (overriddenToolchainPath) {
|
||||
betterTarget = getSpecificTargetBasedOnToolchainPath(
|
||||
override.value,
|
||||
overriddenToolchainPath,
|
||||
);
|
||||
}
|
||||
|
||||
for (const flag of possible.flags) {
|
||||
options.push(flag.replace(c_value_placeholder, betterTarget));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
for (const flag of possible.flags) {
|
||||
options.push(flag.replace(c_value_placeholder, override.value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
prepareArguments(
|
||||
userOptions: string[],
|
||||
filters: ParseFiltersAndOutputOptions,
|
||||
@@ -907,6 +1026,7 @@ export class BaseCompiler implements ICompiler {
|
||||
inputFilename: string,
|
||||
outputFilename: string,
|
||||
libraries,
|
||||
overrides: ConfiguredOverrides,
|
||||
) {
|
||||
let options = this.optionsForFilter(filters, outputFilename, userOptions);
|
||||
backendOptions = backendOptions || {};
|
||||
@@ -921,6 +1041,8 @@ export class BaseCompiler implements ICompiler {
|
||||
options = options.concat(unwrap(this.compiler.optArg));
|
||||
}
|
||||
|
||||
const toolchainPath = this.getDefaultOrOverridenToolchainPath(backendOptions.overrides || []);
|
||||
|
||||
const libIncludes = this.getIncludeArguments(libraries);
|
||||
const libOptions = this.getLibraryOptions(libraries);
|
||||
let libLinks: string[] = [];
|
||||
@@ -929,12 +1051,14 @@ export class BaseCompiler implements ICompiler {
|
||||
|
||||
if (filters.binary) {
|
||||
libLinks = this.getSharedLibraryLinks(libraries) || [];
|
||||
libPaths = this.getSharedLibraryPathsAsArguments(libraries);
|
||||
libPaths = this.getSharedLibraryPathsAsArguments(libraries, undefined, toolchainPath);
|
||||
staticLibLinks = this.getStaticLibraryLinks(libraries) || [];
|
||||
}
|
||||
|
||||
userOptions = this.filterUserOptions(userOptions) || [];
|
||||
options = this.fixIncompatibleOptions(options, userOptions);
|
||||
options = this.changeOptionsBasedOnOverrides(options, overrides);
|
||||
|
||||
return this.orderArguments(
|
||||
options,
|
||||
inputFilename,
|
||||
@@ -1536,6 +1660,8 @@ export class BaseCompiler implements ICompiler {
|
||||
buildFilters.binary = true;
|
||||
buildFilters.execute = true;
|
||||
|
||||
const overrides = this.sanitizeCompilerOverrides(key.backendOptions.overrides || []);
|
||||
|
||||
const compilerArguments = _.compact(
|
||||
this.prepareArguments(
|
||||
key.options,
|
||||
@@ -1544,12 +1670,15 @@ export class BaseCompiler implements ICompiler {
|
||||
inputFilename,
|
||||
outputFilename,
|
||||
key.libraries,
|
||||
overrides,
|
||||
),
|
||||
);
|
||||
|
||||
const execOptions = this.getDefaultExecOptions();
|
||||
execOptions.ldPath = this.getSharedLibraryPathsAsLdLibraryPaths(key.libraries);
|
||||
|
||||
this.applyOverridesToExecOptions(execOptions, overrides);
|
||||
|
||||
const result = await this.buildExecutable(key.compiler.exe, compilerArguments, inputFilename, execOptions);
|
||||
|
||||
return {
|
||||
@@ -1794,18 +1923,56 @@ export class BaseCompiler implements ICompiler {
|
||||
}
|
||||
}
|
||||
|
||||
sanitizeCompilerOverrides(overrides: ConfiguredOverrides): ConfiguredOverrides {
|
||||
const allowedRegex = /^[A-Z_]{1,}[A-Z0-9_]*$/;
|
||||
for (const override of overrides) {
|
||||
if (override.name === CompilerOverrideType.env && override.values) {
|
||||
// lowercase names are allowed, but let's assume everyone means to use uppercase
|
||||
override.values.forEach(env => (env.name = env.name.trim().toUpperCase()));
|
||||
override.values = override.values.filter(
|
||||
env => env.name !== 'LD_PRELOAD' && env.name.match(allowedRegex),
|
||||
);
|
||||
}
|
||||
}
|
||||
return overrides;
|
||||
}
|
||||
|
||||
applyOverridesToExecOptions(execOptions: ExecutionOptions, overrides: ConfiguredOverrides): void {
|
||||
if (!execOptions.env) execOptions.env = {};
|
||||
|
||||
for (const override of overrides) {
|
||||
if (override.name === CompilerOverrideType.env && override.values) {
|
||||
for (const env of override.values) {
|
||||
execOptions.env[env.name] = env.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async doCompilation(inputFilename, dirPath, key, options, filters, backendOptions, libraries, tools) {
|
||||
const inputFilenameSafe = this.filename(inputFilename);
|
||||
|
||||
const outputFilename = this.getOutputFilename(dirPath, this.outputFilebase, key);
|
||||
|
||||
const overrides = this.sanitizeCompilerOverrides(backendOptions.overrides || []);
|
||||
|
||||
options = _.compact(
|
||||
this.prepareArguments(options, filters, backendOptions, inputFilename, outputFilename, libraries),
|
||||
this.prepareArguments(
|
||||
options,
|
||||
filters,
|
||||
backendOptions,
|
||||
inputFilename,
|
||||
outputFilename,
|
||||
libraries,
|
||||
overrides,
|
||||
),
|
||||
);
|
||||
|
||||
const execOptions = this.getDefaultExecOptions();
|
||||
execOptions.ldPath = this.getSharedLibraryPathsAsLdLibraryPaths([]);
|
||||
|
||||
this.applyOverridesToExecOptions(execOptions, overrides);
|
||||
|
||||
const makeAst = backendOptions.produceAst && this.compiler.supportsAstView;
|
||||
const makePp = backendOptions.producePp && this.compiler.supportsPpView;
|
||||
const makeGnatDebug = backendOptions.produceGnatDebug && this.compiler.supportsGnatDebugViews;
|
||||
@@ -2008,7 +2175,7 @@ export class BaseCompiler implements ICompiler {
|
||||
return stepResult;
|
||||
}
|
||||
|
||||
createCmakeExecParams(execParams, dirPath, libsAndOptions) {
|
||||
createCmakeExecParams(execParams: ExecutionOptions, dirPath: string, libsAndOptions, toolchainPath: string) {
|
||||
const cmakeExecParams = Object.assign({}, execParams);
|
||||
|
||||
const libIncludes = this.getIncludeArguments(libsAndOptions.libraries);
|
||||
@@ -2026,7 +2193,7 @@ export class BaseCompiler implements ICompiler {
|
||||
cmakeExecParams.ldPath = [dirPath];
|
||||
|
||||
// todo: if we don't use nsjail, the path should not be /app but dirPath
|
||||
const libPaths = this.getSharedLibraryPathsAsArguments(libsAndOptions.libraries, '/app');
|
||||
const libPaths = this.getSharedLibraryPathsAsArguments(libsAndOptions.libraries, '/app', toolchainPath);
|
||||
cmakeExecParams.env.LDFLAGS = libPaths.join(' ');
|
||||
|
||||
return cmakeExecParams;
|
||||
@@ -2045,9 +2212,10 @@ export class BaseCompiler implements ICompiler {
|
||||
return [];
|
||||
}
|
||||
|
||||
getCMakeExtToolchainParam(): string {
|
||||
if (this.toolchainPath) {
|
||||
return `-DCMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN=${this.toolchainPath}`;
|
||||
getCMakeExtToolchainParam(overrides: ConfiguredOverrides): string {
|
||||
const toolchainPath = this.getDefaultOrOverridenToolchainPath(overrides);
|
||||
if (toolchainPath) {
|
||||
return `-DCMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN=${toolchainPath}`;
|
||||
}
|
||||
|
||||
return '';
|
||||
@@ -2087,6 +2255,8 @@ export class BaseCompiler implements ICompiler {
|
||||
|
||||
const libsAndOptions = this.createLibsAndOptions(key);
|
||||
|
||||
const toolchainPath = this.getDefaultOrOverridenToolchainPath(key.backendOptions.overrides || []);
|
||||
|
||||
const doExecute = key.filters.execute;
|
||||
const executeParameters: ExecutableExecutionOptions = {
|
||||
ldPath: this.getSharedLibraryPathsAsLdLibraryPaths(key.libraries),
|
||||
@@ -2122,7 +2292,7 @@ export class BaseCompiler implements ICompiler {
|
||||
|
||||
await fs.mkdir(execParams.customCwd);
|
||||
|
||||
const makeExecParams = this.createCmakeExecParams(execParams, dirPath, libsAndOptions);
|
||||
const makeExecParams = this.createCmakeExecParams(execParams, dirPath, libsAndOptions, toolchainPath);
|
||||
|
||||
fullResult = {
|
||||
buildsteps: [],
|
||||
@@ -2131,7 +2301,7 @@ export class BaseCompiler implements ICompiler {
|
||||
|
||||
fullResult.downloads = await this.setupBuildEnvironment(cacheKey, dirPath, true);
|
||||
|
||||
const toolchainparam = this.getCMakeExtToolchainParam();
|
||||
const toolchainparam = this.getCMakeExtToolchainParam(key.backendOptions.overrides || []);
|
||||
|
||||
const cmakeArgs = utils.splitArguments(key.backendOptions.cmakeArgs);
|
||||
const partArgs: string[] = [toolchainparam, ...this.getExtraCMakeArgs(key), ...cmakeArgs, '..'];
|
||||
@@ -2722,7 +2892,9 @@ but nothing was dumped. Possible causes are:
|
||||
|
||||
protected getArgumentParser(): any {
|
||||
const exe = this.compiler.exe.toLowerCase();
|
||||
if (exe.includes('clang') || exe.includes('icpx') || exe.includes('icx')) {
|
||||
if (exe.includes('icc')) {
|
||||
return ICCParser;
|
||||
} else if (exe.includes('clang') || exe.includes('icpx') || exe.includes('icx')) {
|
||||
// check this first as "clang++" matches "g++"
|
||||
return ClangParser;
|
||||
} else if (exe.includes('g++') || exe.includes('gcc')) {
|
||||
@@ -2756,6 +2928,87 @@ but nothing was dumped. Possible causes are:
|
||||
this.supportedLibraries = this.getSupportedLibraries(this.compiler.libsArr, clientOptions.libs[this.lang.id]);
|
||||
}
|
||||
|
||||
async getTargetsAsOverrideValues(): Promise<CompilerOverrideOption[]> {
|
||||
if (!this.buildenvsetup || !this.buildenvsetup.getCompilerArch()) {
|
||||
const parser = this.getArgumentParser();
|
||||
const targets = await parser.getPossibleTargets(this);
|
||||
|
||||
return targets.map(target => {
|
||||
return {
|
||||
name: target,
|
||||
value: target,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async getPossibleStdversAsOverrideValues(): Promise<CompilerOverrideOption[]> {
|
||||
const parser = this.getArgumentParser();
|
||||
return await parser.getPossibleStdvers(this);
|
||||
}
|
||||
|
||||
async populatePossibleOverrides() {
|
||||
const targets = await this.getTargetsAsOverrideValues();
|
||||
if (targets.length > 0) {
|
||||
this.compiler.possibleOverrides?.push({
|
||||
name: CompilerOverrideType.arch,
|
||||
display_title: 'Target architecture',
|
||||
description: c_default_target_description,
|
||||
flags: this.getTargetFlags(),
|
||||
values: targets,
|
||||
});
|
||||
}
|
||||
|
||||
const compilerOptions = utils.splitArguments(this.compiler.options);
|
||||
if (hasToolchainArg(compilerOptions)) {
|
||||
const possibleToolchains: CompilerOverrideOptions = await this.getPossibleToolchains();
|
||||
|
||||
if (possibleToolchains.length > 0) {
|
||||
const flag = getToolchainFlagFromOptions(compilerOptions);
|
||||
this.compiler.possibleOverrides?.push({
|
||||
name: CompilerOverrideType.toolchain,
|
||||
display_title: 'Toolchain',
|
||||
description: c_default_toolchain_description,
|
||||
flags: [flag + '<value>'],
|
||||
values: possibleToolchains,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const stdVersions = await this.getPossibleStdversAsOverrideValues();
|
||||
if (stdVersions.length > 0) {
|
||||
this.compiler.possibleOverrides?.push({
|
||||
name: CompilerOverrideType.stdver,
|
||||
display_title: 'Std version',
|
||||
description: this.getStdVerOverrideDescription(),
|
||||
flags: this.getStdverFlags(),
|
||||
values: stdVersions,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getStdVerOverrideDescription(): string {
|
||||
return 'Change the C/C++ standard version of the compiler.';
|
||||
}
|
||||
|
||||
getStdverFlags(): string[] {
|
||||
return ['-std=<value>'];
|
||||
}
|
||||
|
||||
getTargetFlags(): string[] {
|
||||
if (this.compiler.supportsMarch) return [`-march=${c_value_placeholder}`];
|
||||
if (this.compiler.supportsTargetIs) return [`--target=${c_value_placeholder}`];
|
||||
if (this.compiler.supportsTarget) return ['--target', c_value_placeholder];
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
async getPossibleToolchains(): Promise<CompilerOverrideOptions> {
|
||||
return this.env.getPossibleToolchains();
|
||||
}
|
||||
|
||||
async initialise(mtime: Date, clientOptions, isPrediscovered = false) {
|
||||
this.mtime = mtime;
|
||||
|
||||
@@ -2812,6 +3065,9 @@ but nothing was dumped. Possible causes are:
|
||||
return this;
|
||||
} else {
|
||||
const initResult = await this.getArgumentParser().parse(this);
|
||||
|
||||
await this.populatePossibleOverrides();
|
||||
|
||||
logger.info(`${compiler} ${version} is ready`);
|
||||
return initResult;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import {logger} from './logger.js';
|
||||
import {CompilerProps} from './properties.js';
|
||||
import type {PropertyGetter} from './properties.interfaces.js';
|
||||
import {unwrap} from './assert.js';
|
||||
import {CompilerOverrideOptions} from '../types/compilation/compiler-overrides.interfaces.js';
|
||||
|
||||
export class CompilationEnvironment {
|
||||
ceProps: PropertyGetter;
|
||||
@@ -52,6 +53,7 @@ export class CompilationEnvironment {
|
||||
multiarch: string | null;
|
||||
baseEnv: Record<string, string | undefined>;
|
||||
formatHandler: FormattingHandler;
|
||||
possibleToolchains?: CompilerOverrideOptions;
|
||||
|
||||
constructor(compilerProps, compilationQueue, doCache) {
|
||||
this.ceProps = compilerProps.ceProps;
|
||||
@@ -109,6 +111,14 @@ export class CompilationEnvironment {
|
||||
return env;
|
||||
}
|
||||
|
||||
setPossibleToolchains(toolchains: CompilerOverrideOptions) {
|
||||
this.possibleToolchains = toolchains;
|
||||
}
|
||||
|
||||
getPossibleToolchains(): CompilerOverrideOptions {
|
||||
return this.possibleToolchains || [];
|
||||
}
|
||||
|
||||
async cacheGet(object: CacheableValue) {
|
||||
const result = await this.cache.get(BaseCache.hash(object));
|
||||
if (this.cache.gets % this.reportCacheEvery === 0) {
|
||||
|
||||
@@ -42,6 +42,7 @@ import {ClientOptionsHandler, OptionHandlerArguments} from './options-handler.js
|
||||
import {CompilerProps} from './properties.js';
|
||||
import type {PropertyGetter} from './properties.interfaces.js';
|
||||
import {basic_comparator, remove} from './common-utils.js';
|
||||
import {getPossibleGccToolchainsFromCompilerInfo} from './toolchain-utils.js';
|
||||
|
||||
const sleep = promisify(setTimeout);
|
||||
|
||||
@@ -332,6 +333,7 @@ export class CompilerFinder {
|
||||
name: props<string>('licenseName'),
|
||||
preamble: props<string>('licensePreamble'),
|
||||
},
|
||||
possibleOverrides: [],
|
||||
};
|
||||
|
||||
if (props('demanglerClassFile') !== undefined) {
|
||||
@@ -463,6 +465,10 @@ export class CompilerFinder {
|
||||
|
||||
async find() {
|
||||
const compilerList = await this.getCompilers();
|
||||
|
||||
const toolchains = await getPossibleGccToolchainsFromCompilerInfo(compilerList);
|
||||
this.compileHandler.setPossibleToolchains(toolchains);
|
||||
|
||||
const compilers = await this.compileHandler.setCompilers(compilerList, this.optionsHandler.get());
|
||||
if (!compilers) {
|
||||
logger.error('#### No compilers found: no compilation will be done!');
|
||||
|
||||
@@ -29,6 +29,7 @@ import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
|
||||
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
|
||||
import {BaseCompiler} from '../base-compiler.js';
|
||||
import * as utils from '../utils.js';
|
||||
import type {ConfiguredOverrides} from '../../types/compilation/compiler-overrides.interfaces.js';
|
||||
|
||||
export class AdaCompiler extends BaseCompiler {
|
||||
static get key() {
|
||||
@@ -76,6 +77,7 @@ export class AdaCompiler extends BaseCompiler {
|
||||
inputFilename: string,
|
||||
outputFilename: string,
|
||||
libraries,
|
||||
overrides: ConfiguredOverrides,
|
||||
) {
|
||||
backendOptions = backendOptions || {};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -143,6 +143,8 @@ export class AssemblyCompiler extends BaseCompiler {
|
||||
buildFilters.binary = true;
|
||||
buildFilters.execute = false;
|
||||
|
||||
const overrides = this.sanitizeCompilerOverrides(key.backendOptions.overrides);
|
||||
|
||||
const compilerArguments = _.compact(
|
||||
this.prepareArguments(
|
||||
key.options,
|
||||
@@ -151,6 +153,7 @@ export class AssemblyCompiler extends BaseCompiler {
|
||||
inputFilename,
|
||||
outputFilename,
|
||||
key.libraries,
|
||||
overrides,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@@ -25,13 +25,17 @@
|
||||
import path from 'path';
|
||||
|
||||
import {BaseCompiler} from '../base-compiler.js';
|
||||
import {ConanBuildProperties} from '../buildenvsetup/ceconan.js';
|
||||
import {CircleParser} from './argument-parsers.js';
|
||||
|
||||
export class CircleCompiler extends BaseCompiler {
|
||||
static get key() {
|
||||
return 'circle';
|
||||
}
|
||||
|
||||
protected override getArgumentParser() {
|
||||
return CircleParser;
|
||||
}
|
||||
|
||||
override optionsForFilter(filters, outputFilename) {
|
||||
let options = [`-o=${this.filename(outputFilename)}`];
|
||||
if (this.compiler.intelAsm && filters.intel && !filters.binary) {
|
||||
|
||||
@@ -36,6 +36,7 @@ import {AmdgpuAsmParser} from '../parsers/asm-parser-amdgpu.js';
|
||||
import {SassAsmParser} from '../parsers/asm-parser-sass.js';
|
||||
import * as utils from '../utils.js';
|
||||
import {ArtifactType} from '../../types/tool.interfaces.js';
|
||||
import {ClangParser} from './argument-parsers.js';
|
||||
|
||||
const offloadRegexp = /^#\s+__CLANG_OFFLOAD_BUNDLE__(__START__|__END__)\s+(.*)$/gm;
|
||||
|
||||
@@ -70,6 +71,10 @@ export class ClangCompiler extends BaseCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
protected override getArgumentParser(): any {
|
||||
return ClangParser;
|
||||
}
|
||||
|
||||
async addTimeTraceToResult(result: CompilationResult, dirPath: string, outputFilename: string) {
|
||||
let timeTraceJson = '';
|
||||
const outputExt = path.extname(outputFilename);
|
||||
|
||||
@@ -31,6 +31,7 @@ import {DartAsmParser} from '../parsers/asm-parser-dart.js';
|
||||
import * as utils from '../utils.js';
|
||||
|
||||
import {BaseParser} from './argument-parsers.js';
|
||||
import type {ConfiguredOverrides} from '../../types/compilation/compiler-overrides.interfaces.js';
|
||||
|
||||
export class DartCompiler extends BaseCompiler {
|
||||
constructor(info: PreliminaryCompilerInfo, env) {
|
||||
@@ -49,6 +50,7 @@ export class DartCompiler extends BaseCompiler {
|
||||
inputFilename: string,
|
||||
outputFilename: string,
|
||||
libraries,
|
||||
overrides: ConfiguredOverrides,
|
||||
) {
|
||||
let options = this.optionsForFilter(filters, outputFilename, userOptions);
|
||||
|
||||
|
||||
@@ -27,12 +27,17 @@ import path from 'path';
|
||||
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
|
||||
|
||||
import {FortranCompiler} from './fortran.js';
|
||||
import {FlangParser} from './argument-parsers.js';
|
||||
|
||||
export class FlangCompiler extends FortranCompiler {
|
||||
static override get key() {
|
||||
return 'flang';
|
||||
}
|
||||
|
||||
protected override getArgumentParser(): any {
|
||||
return FlangParser;
|
||||
}
|
||||
|
||||
override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: string) {
|
||||
let options = ['-o', this.filename(outputFilename)];
|
||||
if (this.compiler.intelAsm && filters.intel && !filters.binary) {
|
||||
|
||||
@@ -27,12 +27,21 @@ import path from 'path';
|
||||
import type {CompilationResult, ExecutionOptions} from '../../types/compilation/compilation.interfaces.js';
|
||||
import {BaseCompiler} from '../base-compiler.js';
|
||||
import * as utils from '../utils.js';
|
||||
import {GccFortranParser} from './argument-parsers.js';
|
||||
|
||||
export class FortranCompiler extends BaseCompiler {
|
||||
static get key() {
|
||||
return 'fortran';
|
||||
}
|
||||
|
||||
protected override getArgumentParser(): any {
|
||||
return GccFortranParser;
|
||||
}
|
||||
|
||||
override getStdVerOverrideDescription(): string {
|
||||
return 'Change the Fortran standard version of the compiler.';
|
||||
}
|
||||
|
||||
override async runCompiler(
|
||||
compiler: string,
|
||||
options: string[],
|
||||
|
||||
@@ -31,7 +31,7 @@ import {unwrap} from '../assert.js';
|
||||
import {BaseCompiler} from '../base-compiler.js';
|
||||
import * as utils from '../utils.js';
|
||||
|
||||
import {ClangParser} from './argument-parsers.js';
|
||||
import {GolangParser} from './argument-parsers.js';
|
||||
|
||||
// Each arch has a list of jump instructions in
|
||||
// Go source src/cmd/asm/internal/arch.
|
||||
@@ -268,7 +268,7 @@ export class GolangCompiler extends BaseCompiler {
|
||||
return options;
|
||||
}
|
||||
|
||||
override getArgumentParser() {
|
||||
return ClangParser;
|
||||
override getArgumentParser(): any {
|
||||
return GolangParser;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
|
||||
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
|
||||
import {BaseCompiler} from '../base-compiler.js';
|
||||
|
||||
import {ClangParser} from './argument-parsers.js';
|
||||
import {GHCParser} from './argument-parsers.js';
|
||||
|
||||
export class HaskellCompiler extends BaseCompiler {
|
||||
static get key() {
|
||||
@@ -76,7 +76,7 @@ export class HaskellCompiler extends BaseCompiler {
|
||||
return [libPathFlag + '.', ...this.getSharedLibraryPaths(libraries).map(path => libPathFlag + path)];
|
||||
}
|
||||
|
||||
override getArgumentParser() {
|
||||
return ClangParser;
|
||||
override getArgumentParser(): any {
|
||||
return GHCParser;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import type {ConfiguredOverrides} from '../../types/compilation/compiler-overrides.interfaces.js';
|
||||
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
|
||||
|
||||
import {AssemblyCompiler} from './assembly.js';
|
||||
@@ -38,6 +39,7 @@ export class NasmCompiler extends AssemblyCompiler {
|
||||
inputFilename: string,
|
||||
outputFilename: string,
|
||||
libraries,
|
||||
overrides: ConfiguredOverrides,
|
||||
) {
|
||||
let options = super.prepareArguments(
|
||||
userOptions,
|
||||
@@ -46,6 +48,7 @@ export class NasmCompiler extends AssemblyCompiler {
|
||||
inputFilename,
|
||||
outputFilename,
|
||||
libraries,
|
||||
overrides,
|
||||
);
|
||||
|
||||
let fmode;
|
||||
|
||||
@@ -35,6 +35,8 @@ import type {BuildEnvDownloadInfo} from '../buildenvsetup/buildenv.interfaces.js
|
||||
import {parseRustOutput} from '../utils.js';
|
||||
|
||||
import {RustParser} from './argument-parsers.js';
|
||||
import {CompilerOverrideType} from '../../types/compilation/compiler-overrides.interfaces.js';
|
||||
import {SemVer} from 'semver';
|
||||
|
||||
export class RustCompiler extends BaseCompiler {
|
||||
linker: string;
|
||||
@@ -50,7 +52,7 @@ export class RustCompiler extends BaseCompiler {
|
||||
this.compiler.supportsLLVMOptPipelineView = true;
|
||||
this.compiler.supportsRustMirView = true;
|
||||
|
||||
const isNightly = info.name === 'nightly' || info.semver === 'nightly';
|
||||
const isNightly = this.isNightly();
|
||||
// Macro expansion (-Zunpretty=expanded) and HIR (-Zunpretty=hir-tree)
|
||||
// are only available for Nightly
|
||||
this.compiler.supportsRustMacroExpView = isNightly;
|
||||
@@ -63,6 +65,46 @@ export class RustCompiler extends BaseCompiler {
|
||||
this.linker = this.compilerProps<string>('linker');
|
||||
}
|
||||
|
||||
private isNightly() {
|
||||
return (
|
||||
this.compiler.name === 'nightly' ||
|
||||
this.compiler.semver === 'nightly' ||
|
||||
this.compiler.semver === 'beta' ||
|
||||
this.compiler.semver.includes('master') ||
|
||||
this.compiler.semver.includes('trunk')
|
||||
);
|
||||
}
|
||||
|
||||
override async populatePossibleOverrides() {
|
||||
const possibleEditions = await RustParser.getPossibleEditions(this);
|
||||
if (possibleEditions.length > 0) {
|
||||
let defaultEdition: undefined | string = undefined;
|
||||
if (!this.compiler.semver || this.isNightly()) {
|
||||
defaultEdition = '2021';
|
||||
} else {
|
||||
const compilerVersion = new SemVer(this.compiler.semver);
|
||||
if (compilerVersion.compare('1.56.0') >= 0) {
|
||||
defaultEdition = '2021';
|
||||
}
|
||||
}
|
||||
|
||||
this.compiler.possibleOverrides?.push({
|
||||
name: CompilerOverrideType.edition,
|
||||
display_title: 'Edition',
|
||||
description:
|
||||
'The default edition for Rust compilers is usually 2015. ' +
|
||||
'Some editions might not be available for older compilers.',
|
||||
flags: ['--edition', '<value>'],
|
||||
values: possibleEditions.map(ed => {
|
||||
return {name: ed, value: ed};
|
||||
}),
|
||||
default: defaultEdition,
|
||||
});
|
||||
}
|
||||
|
||||
await super.populatePossibleOverrides();
|
||||
}
|
||||
|
||||
override getSharedLibraryPathsAsArguments(libraries, libDownloadPath) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import {logger} from '../logger.js';
|
||||
import {SPIRVAsmParser} from '../parsers/asm-parser-spirv.js';
|
||||
import * as utils from '../utils.js';
|
||||
import {unwrap} from '../assert.js';
|
||||
import type {ConfiguredOverrides} from '../../types/compilation/compiler-overrides.interfaces.js';
|
||||
|
||||
export class SPIRVCompiler extends BaseCompiler {
|
||||
protected translatorPath: string;
|
||||
@@ -59,6 +60,7 @@ export class SPIRVCompiler extends BaseCompiler {
|
||||
inputFilename: string,
|
||||
outputFilename: string,
|
||||
libraries,
|
||||
overrides: ConfiguredOverrides,
|
||||
) {
|
||||
let options = this.optionsForFilter(filters, outputFilename);
|
||||
backendOptions = backendOptions || {};
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
import {BaseCompiler} from '../base-compiler.js';
|
||||
|
||||
import {ClangParser} from './argument-parsers.js';
|
||||
import {SwiftParser} from './argument-parsers.js';
|
||||
|
||||
export class SwiftCompiler extends BaseCompiler {
|
||||
static get key() {
|
||||
@@ -36,7 +36,7 @@ export class SwiftCompiler extends BaseCompiler {
|
||||
}
|
||||
|
||||
override getArgumentParser() {
|
||||
return ClangParser;
|
||||
return SwiftParser;
|
||||
}
|
||||
|
||||
override isCfgCompiler(/*compilerVersion*/) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
|
||||
import {TendraParser} from './argument-parsers.js';
|
||||
|
||||
import {GCCCompiler} from './gcc.js';
|
||||
|
||||
@@ -36,4 +37,8 @@ export class TenDRACompiler extends GCCCompiler {
|
||||
if (!filters.binary) options = options.concat('-S');
|
||||
return options;
|
||||
}
|
||||
|
||||
protected override getArgumentParser(): any {
|
||||
return TendraParser;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import {AsmParser} from '../parsers/asm-parser.js';
|
||||
import {PELabelReconstructor} from '../pe32-support.js';
|
||||
import * as utils from '../utils.js';
|
||||
import {unwrap} from '../assert.js';
|
||||
import type {ConfiguredOverrides} from '../../types/compilation/compiler-overrides.interfaces.js';
|
||||
|
||||
export class Win32Compiler extends BaseCompiler {
|
||||
static get key() {
|
||||
@@ -50,6 +51,10 @@ export class Win32Compiler extends BaseCompiler {
|
||||
this.binaryAsmParser = new AsmParser(this.compilerProps);
|
||||
}
|
||||
|
||||
override getStdverFlags(): string[] {
|
||||
return ['/std:<value>'];
|
||||
}
|
||||
|
||||
override newTempDir() {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
temp.mkdir({prefix: 'compiler-explorer-compiler', dir: process.env.TMP}, (err, dirPath) => {
|
||||
@@ -98,6 +103,7 @@ export class Win32Compiler extends BaseCompiler {
|
||||
inputFilename: string,
|
||||
outputFilename: string,
|
||||
libraries,
|
||||
overrides: ConfiguredOverrides,
|
||||
) {
|
||||
let options = this.optionsForFilter(filters, outputFilename, userOptions);
|
||||
backendOptions = backendOptions || {};
|
||||
|
||||
@@ -28,10 +28,11 @@ import type {ExecutionOptions} from '../../types/compilation/compilation.interfa
|
||||
import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
|
||||
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
|
||||
import {ArtifactType} from '../../types/tool.interfaces.js';
|
||||
import {BaseCompiler} from '../base-compiler.js';
|
||||
import {BaseCompiler, c_default_target_description} from '../base-compiler.js';
|
||||
import {logger} from '../logger.js';
|
||||
import {AsmParserZ88dk} from '../parsers/asm-parser-z88dk.js';
|
||||
import * as utils from '../utils.js';
|
||||
import {Z88dkParser} from './argument-parsers.js';
|
||||
|
||||
export class z88dkCompiler extends BaseCompiler {
|
||||
static get key() {
|
||||
@@ -44,6 +45,14 @@ export class z88dkCompiler extends BaseCompiler {
|
||||
this.asm = new AsmParserZ88dk(this.compilerProps);
|
||||
}
|
||||
|
||||
protected override getArgumentParser() {
|
||||
return Z88dkParser;
|
||||
}
|
||||
|
||||
override getTargetFlags(): string[] {
|
||||
return ['+<value>'];
|
||||
}
|
||||
|
||||
public override getOutputFilename(dirPath: string, outputFilebase: string, key?: any): string {
|
||||
let filename;
|
||||
if (key && key.backendOptions && key.backendOptions.customOutputFilename) {
|
||||
@@ -71,8 +80,17 @@ export class z88dkCompiler extends BaseCompiler {
|
||||
userOptions: string[],
|
||||
staticLibLinks: string[],
|
||||
) {
|
||||
return userOptions.concat(
|
||||
options,
|
||||
let targetOpt = options.filter(opt => opt.startsWith('+'));
|
||||
const withoutTarget = options.filter(opt => !opt.startsWith('+'));
|
||||
const withoutTargetUser = userOptions.filter(opt => !opt.startsWith('+'));
|
||||
|
||||
if (targetOpt.length === 0) {
|
||||
targetOpt = userOptions.filter(opt => opt.startsWith('+'));
|
||||
}
|
||||
|
||||
return targetOpt.concat(
|
||||
withoutTargetUser,
|
||||
withoutTarget,
|
||||
[this.filename(inputFilename)],
|
||||
libIncludes,
|
||||
libOptions,
|
||||
|
||||
@@ -26,6 +26,7 @@ import path from 'path';
|
||||
|
||||
import Semver from 'semver';
|
||||
import _ from 'underscore';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
|
||||
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
|
||||
|
||||
@@ -28,6 +28,7 @@ import type {CompilerOutputOptions, ParseFiltersAndOutputOptions} from '../../ty
|
||||
import {asSafeVer} from '../utils.js';
|
||||
|
||||
import {ClangCompiler} from './clang.js';
|
||||
import {ZigCxxParser} from './argument-parsers.js';
|
||||
|
||||
export class ZigCXX extends ClangCompiler {
|
||||
private readonly needsForcedBinary: boolean;
|
||||
@@ -43,6 +44,10 @@ export class ZigCXX extends ClangCompiler {
|
||||
Semver.lt(asSafeVer(this.compiler.semver), '0.9.0', true);
|
||||
}
|
||||
|
||||
protected override getArgumentParser(): any {
|
||||
return ZigCxxParser;
|
||||
}
|
||||
|
||||
override preProcess(source: string, filters: CompilerOutputOptions): string {
|
||||
if (this.needsForcedBinary) {
|
||||
// note: zig versions > 0.6 don't emit asm, only binary works - https://github.com/ziglang/zig/issues/8153
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
ExecutionRequestParams,
|
||||
} from './compile.interfaces.js';
|
||||
import {remove} from '../common-utils.js';
|
||||
import {CompilerOverrideOptions} from '../../types/compilation/compiler-overrides.interfaces.js';
|
||||
|
||||
temp.track();
|
||||
|
||||
@@ -266,6 +267,10 @@ export class CompileHandler {
|
||||
}
|
||||
}
|
||||
|
||||
setPossibleToolchains(toolchains: CompilerOverrideOptions) {
|
||||
this.compilerEnv.setPossibleToolchains(toolchains);
|
||||
}
|
||||
|
||||
compilerAliasMatch(compiler, compilerId): boolean {
|
||||
return compiler.compiler.alias && compiler.compiler.alias.includes(compilerId);
|
||||
}
|
||||
|
||||
@@ -23,15 +23,21 @@
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import {splitArguments} from './utils.js';
|
||||
import {PreliminaryCompilerInfo} from '../types/compiler.interfaces.js';
|
||||
import {CompilerOverrideOptions} from '../types/compilation/compiler-overrides.interfaces.js';
|
||||
|
||||
export function getToolchainPath(compilerExe: string | null, compilerOptions?: string): string | false {
|
||||
const options = compilerOptions ? splitArguments(compilerOptions) : [];
|
||||
const existingChain = options.find(elem => elem.includes('--gcc-toolchain='));
|
||||
export const clang_style_toolchain_flag = '--gcc-toolchain=';
|
||||
export const icc_style_toolchain_flag = '--gxx-name=';
|
||||
export const clang_style_sysroot_flag = '--sysroot=';
|
||||
|
||||
export function getToolchainPathWithOptionsArr(compilerExe: string | null, options: string[]): string | false {
|
||||
const existingChain = options.find(elem => elem.includes(clang_style_toolchain_flag));
|
||||
if (existingChain) return existingChain.substring(16);
|
||||
|
||||
const gxxname = options.find(elem => elem.includes('--gxx-name='));
|
||||
const gxxname = options.find(elem => elem.includes(icc_style_toolchain_flag));
|
||||
if (gxxname) {
|
||||
return path.resolve(path.dirname(gxxname.substring(11)), '..');
|
||||
} else if (typeof compilerExe === 'string' && compilerExe.includes('/g++')) {
|
||||
@@ -41,6 +47,111 @@ export function getToolchainPath(compilerExe: string | null, compilerOptions?: s
|
||||
}
|
||||
}
|
||||
|
||||
export function removeToolchainArg(compilerOptions: string[]): string[] {
|
||||
return compilerOptions.filter(elem => !elem.includes('--gcc-toolchain=') && !elem.includes('--gxx-name='));
|
||||
export function getToolchainPath(compilerExe: string | null, compilerOptions?: string): string | false {
|
||||
const options = compilerOptions ? splitArguments(compilerOptions) : [];
|
||||
return getToolchainPathWithOptionsArr(compilerExe, options);
|
||||
}
|
||||
|
||||
export function removeToolchainArg(compilerOptions: string[]): string[] {
|
||||
return compilerOptions.filter(
|
||||
elem => !elem.includes(clang_style_toolchain_flag) && !elem.includes(icc_style_toolchain_flag),
|
||||
);
|
||||
}
|
||||
|
||||
export function removeSysrootArg(compilerOptions: string[]): string[] {
|
||||
return compilerOptions.filter(elem => !elem.includes(clang_style_sysroot_flag));
|
||||
}
|
||||
|
||||
export function replaceToolchainArg(compilerOptions: string[], newPath: string): string[] {
|
||||
return compilerOptions.map(elem => {
|
||||
if (elem.includes(clang_style_toolchain_flag)) {
|
||||
return clang_style_toolchain_flag + path.normalize(newPath);
|
||||
} else if (elem.includes(icc_style_toolchain_flag)) {
|
||||
return icc_style_toolchain_flag + path.normalize(newPath);
|
||||
}
|
||||
|
||||
return elem;
|
||||
});
|
||||
}
|
||||
|
||||
export function replaceSysrootArg(compilerOptions: string[], newPath: string): string[] {
|
||||
return compilerOptions.map(elem => {
|
||||
if (elem.includes(clang_style_sysroot_flag)) {
|
||||
return clang_style_sysroot_flag + path.normalize(newPath);
|
||||
}
|
||||
|
||||
return elem;
|
||||
});
|
||||
}
|
||||
|
||||
export function getToolchainFlagFromOptions(options: string[]): string | false {
|
||||
for (const elem of options) {
|
||||
if (elem.includes(clang_style_toolchain_flag)) return clang_style_toolchain_flag;
|
||||
if (elem.includes(icc_style_toolchain_flag)) return icc_style_toolchain_flag;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function hasToolchainArg(options: string[]): boolean {
|
||||
return !!getToolchainFlagFromOptions(options);
|
||||
}
|
||||
|
||||
export function getSysrootFlagFromOptions(options: string[]): string | false {
|
||||
for (const elem of options) {
|
||||
if (elem.includes(clang_style_sysroot_flag)) return clang_style_sysroot_flag;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function hasSysrootArg(options: string[]): boolean {
|
||||
return !!getSysrootFlagFromOptions(options);
|
||||
}
|
||||
|
||||
export async function getPossibleGccToolchainsFromCompilerInfo(
|
||||
compilers: PreliminaryCompilerInfo[],
|
||||
): Promise<CompilerOverrideOptions> {
|
||||
const overrideOptions: CompilerOverrideOptions = [];
|
||||
for (const compiler of compilers) {
|
||||
if (
|
||||
compiler.compilerCategories?.includes('gcc') &&
|
||||
!compiler.compilerCategories?.includes('mingw') &&
|
||||
!compiler.hidden &&
|
||||
compiler.exe &&
|
||||
path.isAbsolute(compiler.exe)
|
||||
) {
|
||||
try {
|
||||
await fs.stat(compiler.exe);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
||||
const toolchainPath = path.resolve(path.dirname(compiler.exe), '..');
|
||||
if (!overrideOptions.find(opt => opt.value === toolchainPath)) {
|
||||
overrideOptions.push({
|
||||
name: compiler.name,
|
||||
value: toolchainPath,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return overrideOptions;
|
||||
}
|
||||
|
||||
export function getSpecificTargetBasedOnToolchainPath(target: string, toolchainPath: string) {
|
||||
const lastPathBit = path.basename(toolchainPath);
|
||||
if (lastPathBit.startsWith(target)) {
|
||||
return lastPathBit;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
export function getSysrootByToolchainPath(toolchainPath: string): string | undefined {
|
||||
const lastPathBit = path.basename(toolchainPath);
|
||||
const possibleSysrootPath = path.join(toolchainPath, lastPathBit, 'sysroot');
|
||||
if (fs.existsSync(possibleSysrootPath)) {
|
||||
return possibleSysrootPath;
|
||||
}
|
||||
}
|
||||
|
||||
32
static/compiler-shared.interfaces.ts
Normal file
32
static/compiler-shared.interfaces.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2023, 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 type {ConfiguredOverrides} from './compilation/compiler-overrides.interfaces.js';
|
||||
import type {CompilerState} from './panes/compiler.interfaces.js';
|
||||
import type {ExecutorState} from './panes/executor.interfaces.js';
|
||||
|
||||
export interface ICompilerShared {
|
||||
updateState(state: CompilerState | ExecutorState);
|
||||
getOverrides(): ConfiguredOverrides | undefined;
|
||||
}
|
||||
68
static/compiler-shared.ts
Normal file
68
static/compiler-shared.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2023, 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 $ from 'jquery';
|
||||
import type {ICompilerShared} from './compiler-shared.interfaces.js';
|
||||
import {CompilerOverridesWidget} from './widgets/compiler-overrides.js';
|
||||
import type {CompilerState} from './panes/compiler.interfaces.js';
|
||||
import type {ConfiguredOverrides} from './compilation/compiler-overrides.interfaces.js';
|
||||
import type {ExecutorState} from './panes/executor.interfaces.js';
|
||||
|
||||
export class CompilerShared implements ICompilerShared {
|
||||
private domRoot: JQuery<HTMLElement>;
|
||||
private overridesButton: JQuery<HTMLElement>;
|
||||
private overridesWidget: CompilerOverridesWidget;
|
||||
|
||||
constructor(domRoot: JQuery, onChange: () => void) {
|
||||
this.domRoot = domRoot;
|
||||
this.initButtons(onChange);
|
||||
this.initCallbacks();
|
||||
}
|
||||
|
||||
public getOverrides(): ConfiguredOverrides | undefined {
|
||||
return this.overridesWidget.get();
|
||||
}
|
||||
|
||||
public updateState(state: CompilerState | ExecutorState) {
|
||||
this.overridesWidget.setCompiler(state.compiler, state.lang);
|
||||
|
||||
if (state.overrides) {
|
||||
this.overridesWidget.set(state.overrides);
|
||||
} else {
|
||||
this.overridesWidget.setDefaults();
|
||||
}
|
||||
}
|
||||
|
||||
private initButtons(onChange: () => void) {
|
||||
this.overridesButton = this.domRoot.find('.btn.show-overrides');
|
||||
|
||||
this.overridesWidget = new CompilerOverridesWidget(this.domRoot, this.overridesButton, onChange);
|
||||
}
|
||||
|
||||
private initCallbacks() {
|
||||
this.overridesButton.on('click', () => {
|
||||
this.overridesWidget.show();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,8 @@ import {CompilerOutputOptions} from '../types/features/filters.interfaces.js';
|
||||
import {CfgState} from './panes/cfg-view.interfaces.js';
|
||||
import {LLVMOptPipelineViewState} from './panes/llvm-opt-pipeline.interfaces.js';
|
||||
import {GccDumpViewState} from './panes/gccdump-view.interfaces.js';
|
||||
import {PossibleArguments} from './compiler-arguments.interfaces.js';
|
||||
import {ConfiguredOverrides} from './compilation/compiler-overrides.interfaces.js';
|
||||
export const COMPILER_COMPONENT_NAME = 'compiler';
|
||||
export const EXECUTOR_COMPONENT_NAME = 'executor';
|
||||
export const EDITOR_COMPONENT_NAME = 'codeEditor';
|
||||
@@ -90,6 +92,7 @@ export type PopulatedExecutorState = StateWithLanguage &
|
||||
options: unknown;
|
||||
compilationPanelShown: boolean;
|
||||
compilerOutShown: boolean;
|
||||
overrides?: ConfiguredOverrides;
|
||||
};
|
||||
export type ExecutorForTreeState = StateWithLanguage &
|
||||
StateWithTree & {
|
||||
|
||||
@@ -104,6 +104,7 @@ import {
|
||||
EmptyLLVMOptPipelineViewState,
|
||||
PopulatedLLVMOptPipelineViewState,
|
||||
} from './components.interfaces.js';
|
||||
import {ConfiguredOverrides} from './compilation/compiler-overrides.interfaces.js';
|
||||
|
||||
/** Get an empty compiler component. */
|
||||
export function getCompiler(editorId: number, lang: string): ComponentConfig<EmptyCompilerState> {
|
||||
@@ -181,6 +182,7 @@ export function getExecutorWith(
|
||||
libraries: unknown,
|
||||
compilerArgs,
|
||||
treeId: number,
|
||||
overrides?: ConfiguredOverrides,
|
||||
): ComponentConfig<PopulatedExecutorState> {
|
||||
return {
|
||||
type: 'component',
|
||||
@@ -194,6 +196,7 @@ export function getExecutorWith(
|
||||
lang,
|
||||
compilationPanelShown: true,
|
||||
compilerOutShown: true,
|
||||
overrides: overrides,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
97
static/panes/compiler-request.interfaces.ts
Normal file
97
static/panes/compiler-request.interfaces.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
// Copyright (c) 2023, 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 type {LLVMOptPipelineBackendOptions} from '../../types/compilation/llvm-opt-pipeline-output.interfaces.js';
|
||||
import type {PPOptions} from './pp-view.interfaces.js';
|
||||
import type {GccDumpViewSelectedPass} from './gccdump-view.interfaces.js';
|
||||
import type {FiledataPair} from '../../types/compilation/compilation.interfaces.js';
|
||||
import type {ConfiguredOverrides} from '../compilation/compiler-overrides.interfaces.js';
|
||||
|
||||
export type ActiveTools = {
|
||||
id: number;
|
||||
args: string[];
|
||||
stdin: string;
|
||||
};
|
||||
|
||||
export type CompilationRequestOptions = {
|
||||
userArguments: string;
|
||||
compilerOptions: {
|
||||
executorRequest?: boolean;
|
||||
skipAsm?: boolean;
|
||||
producePp?: PPOptions | null;
|
||||
produceAst?: boolean;
|
||||
produceGccDump?: {
|
||||
opened: boolean;
|
||||
pass?: GccDumpViewSelectedPass;
|
||||
treeDump?: boolean;
|
||||
rtlDump?: boolean;
|
||||
ipaDump?: boolean;
|
||||
dumpFlags: any;
|
||||
};
|
||||
produceOptInfo?: boolean;
|
||||
produceCfg?: boolean;
|
||||
produceGnatDebugTree?: boolean;
|
||||
produceGnatDebug?: boolean;
|
||||
produceIr?: boolean;
|
||||
produceLLVMOptPipeline?: LLVMOptPipelineBackendOptions | null;
|
||||
produceDevice?: boolean;
|
||||
produceRustMir?: boolean;
|
||||
produceRustMacroExp?: boolean;
|
||||
produceRustHir?: boolean;
|
||||
produceHaskellCore?: boolean;
|
||||
produceHaskellStg?: boolean;
|
||||
produceHaskellCmm?: boolean;
|
||||
cmakeArgs?: string;
|
||||
customOutputFilename?: string;
|
||||
overrides?: ConfiguredOverrides;
|
||||
};
|
||||
executeParameters: {
|
||||
args: string;
|
||||
stdin: string;
|
||||
};
|
||||
filters: Record<string, boolean>;
|
||||
tools: ActiveTools[];
|
||||
libraries: CompileChildLibraries[];
|
||||
};
|
||||
|
||||
export type CompilationRequest = {
|
||||
source: string;
|
||||
compiler: string;
|
||||
options: CompilationRequestOptions;
|
||||
lang: string | null;
|
||||
files: FiledataPair[];
|
||||
bypassCache?: boolean;
|
||||
};
|
||||
|
||||
export type LangInfo = {
|
||||
compiler: string;
|
||||
options: string;
|
||||
execArgs: string;
|
||||
execStdin: string;
|
||||
};
|
||||
|
||||
export type CompileChildLibraries = {
|
||||
id: string;
|
||||
version: string;
|
||||
};
|
||||
@@ -22,7 +22,9 @@
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import type {ConfiguredOverrides} from '../compilation/compiler-overrides.interfaces.js';
|
||||
import {WidgetState} from '../widgets/libs-widget.interfaces.js';
|
||||
import {MonacoPaneState} from './pane.interfaces.js';
|
||||
|
||||
export type CompilerState = WidgetState & {
|
||||
tree?: number;
|
||||
@@ -33,4 +35,10 @@ export type CompilerState = WidgetState & {
|
||||
deviceViewOpen?: boolean;
|
||||
wantOptInfo?: boolean;
|
||||
lang?: string;
|
||||
overrides?: ConfiguredOverrides;
|
||||
};
|
||||
|
||||
export type CompilerCurrentState = CompilerState &
|
||||
MonacoPaneState & {
|
||||
filters: Record<string, boolean>;
|
||||
};
|
||||
|
||||
@@ -48,7 +48,7 @@ import {CompilerInfo} from '../../types/compiler.interfaces.js';
|
||||
import {MonacoPaneState} from './pane.interfaces.js';
|
||||
import {Hub} from '../hub.js';
|
||||
import {Container} from 'golden-layout';
|
||||
import {CompilerState} from './compiler.interfaces.js';
|
||||
import {CompilerCurrentState, CompilerState} from './compiler.interfaces.js';
|
||||
import {ComponentConfig, ToolViewState} from '../components.interfaces.js';
|
||||
import {LanguageLibs} from '../options.interfaces.js';
|
||||
import {GccDumpFiltersState, GccDumpViewSelectedPass} from './gccdump-view.interfaces.js';
|
||||
@@ -69,6 +69,9 @@ import {CompilerOutputOptions} from '../../types/features/filters.interfaces.js'
|
||||
import {AssemblyDocumentationInstructionSet} from '../../types/features/assembly-documentation.interfaces.js';
|
||||
import {SourceAndFiles} from '../download-service.js';
|
||||
import fileSaver = require('file-saver');
|
||||
import {ICompilerShared} from '../compiler-shared.interfaces.js';
|
||||
import {CompilerShared} from '../compiler-shared.js';
|
||||
import type {ActiveTools, CompilationRequest, CompilationRequestOptions} from './compiler-request.interfaces.js';
|
||||
|
||||
const toolIcons = require.context('../../views/resources/logos', false, /\.(png|svg)$/);
|
||||
|
||||
@@ -100,17 +103,6 @@ function patchOldFilters(filters) {
|
||||
|
||||
const languages = options.languages;
|
||||
|
||||
type CompilerCurrentState = CompilerState &
|
||||
MonacoPaneState & {
|
||||
filters: Record<string, boolean>;
|
||||
};
|
||||
|
||||
type ActiveTools = {
|
||||
id: number;
|
||||
args: string[];
|
||||
stdin: string;
|
||||
};
|
||||
|
||||
type NewToolSettings = {
|
||||
toolId: number;
|
||||
args: string[];
|
||||
@@ -129,52 +121,6 @@ type LinkedCode = {
|
||||
|
||||
type Decorations = Record<string, monaco.editor.IModelDeltaDecoration[]>;
|
||||
|
||||
type CompileRequestOptions = {
|
||||
userArguments: string;
|
||||
compilerOptions: {
|
||||
producePp: PPOptions | null;
|
||||
produceAst: boolean;
|
||||
produceGccDump: {
|
||||
opened: boolean;
|
||||
pass?: GccDumpViewSelectedPass;
|
||||
treeDump?: boolean;
|
||||
rtlDump?: boolean;
|
||||
ipaDump?: boolean;
|
||||
dumpFlags: any;
|
||||
};
|
||||
produceOptInfo: boolean;
|
||||
produceCfg: boolean;
|
||||
produceGnatDebugTree: boolean;
|
||||
produceGnatDebug: boolean;
|
||||
produceIr: boolean;
|
||||
produceLLVMOptPipeline: LLVMOptPipelineBackendOptions | null;
|
||||
produceDevice: boolean;
|
||||
produceRustMir: boolean;
|
||||
produceRustMacroExp: boolean;
|
||||
produceRustHir: boolean;
|
||||
produceHaskellCore: boolean;
|
||||
produceHaskellStg: boolean;
|
||||
produceHaskellCmm: boolean;
|
||||
cmakeArgs?: string;
|
||||
customOutputFilename?: string;
|
||||
};
|
||||
filters: Record<string, boolean>;
|
||||
tools: ActiveTools[];
|
||||
libraries: {
|
||||
id: string;
|
||||
version: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
type CompileRequest = {
|
||||
source: string;
|
||||
compiler: string;
|
||||
options: CompileRequestOptions;
|
||||
lang: string | null;
|
||||
files: FiledataPair[];
|
||||
bypassCache: boolean;
|
||||
};
|
||||
|
||||
type Assembly = {
|
||||
labels?: any[];
|
||||
source?: {
|
||||
@@ -222,8 +168,8 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
private lastTimeTaken: number;
|
||||
private pendingRequestSentAt: number;
|
||||
private pendingCMakeRequestSentAt: number;
|
||||
private nextRequest: CompileRequest | null;
|
||||
private nextCMakeRequest: CompileRequest | null;
|
||||
private nextRequest: CompilationRequest | null;
|
||||
private nextCMakeRequest: CompilationRequest | null;
|
||||
private flagsViewOpen: boolean;
|
||||
private optViewOpen: boolean;
|
||||
private cfgViewOpen: boolean;
|
||||
@@ -327,6 +273,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
private mouseMoveThrottledFunction?: ((e: monaco.editor.IEditorMouseEvent) => void) & _.Cancelable;
|
||||
private cursorSelectionThrottledFunction?: ((e: monaco.editor.ICursorSelectionChangedEvent) => void) & _.Cancelable;
|
||||
private mouseUpThrottledFunction?: ((e: monaco.editor.IEditorMouseEvent) => void) & _.Cancelable;
|
||||
private compilerShared: ICompilerShared;
|
||||
|
||||
// eslint-disable-next-line max-statements
|
||||
constructor(hub: Hub, container: Container, state: MonacoPaneState & CompilerState) {
|
||||
@@ -379,6 +326,8 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
this.onCompilerChange.bind(this),
|
||||
);
|
||||
this.initLibraries(state);
|
||||
this.compilerShared = new CompilerShared(this.domRoot, this.onCompilerOverridesChange.bind(this));
|
||||
this.compilerShared.updateState(state);
|
||||
// MonacoPane's registerCallbacks is not called late enough either
|
||||
this.initCallbacks();
|
||||
// Handle initial settings
|
||||
@@ -700,6 +649,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
libs,
|
||||
currentState.options,
|
||||
treeId ?? 0,
|
||||
currentState.overrides,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -753,7 +703,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
}
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(this.ppButton, createPpView())
|
||||
.createDragSource(this.ppButton, createPpView as any)
|
||||
// @ts-ignore
|
||||
._dragListener.on('dragStart', togglePannerAdder);
|
||||
|
||||
@@ -1225,7 +1175,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
|
||||
this.needsCompile = false;
|
||||
this.compileInfoLabel.text(' - Compiling...');
|
||||
const options: CompileRequestOptions = {
|
||||
const options: CompilationRequestOptions = {
|
||||
userArguments: this.options,
|
||||
compilerOptions: {
|
||||
producePp: this.ppViewOpen ? this.ppOptions : null,
|
||||
@@ -1251,6 +1201,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
produceHaskellCore: this.haskellCoreViewOpen,
|
||||
produceHaskellStg: this.haskellStgViewOpen,
|
||||
produceHaskellCmm: this.haskellCmmViewOpen,
|
||||
overrides: this.getCurrentState().overrides,
|
||||
},
|
||||
filters: this.getEffectiveFilters(),
|
||||
tools: this.getActiveTools(newTools),
|
||||
@@ -1259,6 +1210,10 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
id: item.libId,
|
||||
version: item.versionId,
|
||||
})) ?? [],
|
||||
executeParameters: {
|
||||
args: '',
|
||||
stdin: '',
|
||||
},
|
||||
};
|
||||
|
||||
if (this.sourceTreeId) {
|
||||
@@ -1268,7 +1223,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
}
|
||||
}
|
||||
|
||||
compileFromTree(options: CompileRequestOptions, bypassCache: boolean): void {
|
||||
compileFromTree(options: CompilationRequestOptions, bypassCache: boolean): void {
|
||||
const tree = this.hub.getTreeById(this.sourceTreeId ?? 0);
|
||||
if (!tree) {
|
||||
this.sourceTreeId = null;
|
||||
@@ -1276,7 +1231,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
return;
|
||||
}
|
||||
|
||||
const request: CompileRequest = {
|
||||
const request: CompilationRequest = {
|
||||
source: tree.multifileService.getMainSource(),
|
||||
compiler: this.compiler ? this.compiler.id : '',
|
||||
options: options,
|
||||
@@ -1326,9 +1281,9 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
});
|
||||
}
|
||||
|
||||
compileFromEditorSource(options: CompileRequestOptions, bypassCache: boolean) {
|
||||
compileFromEditorSource(options: CompilationRequestOptions, bypassCache: boolean) {
|
||||
this.compilerService.expandToFiles(this.source).then((sourceAndFiles: SourceAndFiles) => {
|
||||
const request: CompileRequest = {
|
||||
const request: CompilationRequest = {
|
||||
source: sourceAndFiles.source || '',
|
||||
compiler: this.compiler ? this.compiler.id : '',
|
||||
options: options,
|
||||
@@ -1345,7 +1300,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
});
|
||||
}
|
||||
|
||||
sendCMakeCompile(request: CompileRequest) {
|
||||
sendCMakeCompile(request: CompilationRequest) {
|
||||
if (this.pendingCMakeRequestSentAt) {
|
||||
// If we have a request pending, then just store this request to do once the
|
||||
// previous request completes.
|
||||
@@ -1380,7 +1335,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
});
|
||||
}
|
||||
|
||||
sendCompile(request: CompileRequest) {
|
||||
sendCompile(request: CompilationRequest) {
|
||||
const onCompilerResponse = this.onCompileResponse.bind(this);
|
||||
|
||||
if (this.pendingRequestSentAt) {
|
||||
@@ -2008,6 +1963,14 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
}
|
||||
}
|
||||
|
||||
onCompilerOverridesChange(): void {
|
||||
this.updateState();
|
||||
|
||||
if (this.settings.compileOnChange) {
|
||||
this.compile();
|
||||
}
|
||||
}
|
||||
|
||||
onToolSettingsChange(id: number): void {
|
||||
if (this.id === id) {
|
||||
this.compile();
|
||||
@@ -3090,6 +3053,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
selection: this.selection,
|
||||
flagsViewOpen: this.flagsViewOpen,
|
||||
deviceViewOpen: this.deviceViewOpen,
|
||||
overrides: this.compilerShared.getOverrides(),
|
||||
};
|
||||
this.paneRenaming.addState(state);
|
||||
this.fontScale.addState(state);
|
||||
@@ -3650,6 +3614,12 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
}
|
||||
}
|
||||
|
||||
override updateState() {
|
||||
const state = this.getCurrentState();
|
||||
this.container.setState(state);
|
||||
this.compilerShared.updateState(state);
|
||||
}
|
||||
|
||||
override getPaneTag() {
|
||||
const editorId = this.sourceEditorId;
|
||||
const treeId = this.sourceTreeId;
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import {WidgetState} from '../widgets/libs-widget.interfaces.js';
|
||||
import type {ConfiguredOverrides} from '../compilation/compiler-overrides.interfaces.js';
|
||||
import type {WidgetState} from '../widgets/libs-widget.interfaces.js';
|
||||
|
||||
export type ExecutorState = WidgetState & {
|
||||
tree?: number;
|
||||
@@ -38,4 +39,5 @@ export type ExecutorState = WidgetState & {
|
||||
wrap?: boolean;
|
||||
lang?: string;
|
||||
compiler: string;
|
||||
overrides?: ConfiguredOverrides;
|
||||
};
|
||||
|
||||
@@ -45,14 +45,15 @@ import {ExecutorState} from './executor.interfaces.js';
|
||||
import {CompilerInfo} from '../../types/compiler.interfaces.js';
|
||||
import {Language} from '../../types/languages.interfaces.js';
|
||||
import {LanguageLibs} from '../options.interfaces.js';
|
||||
import {LLVMOptPipelineBackendOptions} from '../../types/compilation/llvm-opt-pipeline-output.interfaces.js';
|
||||
import {PPOptions} from './pp-view.interfaces.js';
|
||||
import {FiledataPair, CompilationResult} from '../../types/compilation/compilation.interfaces.js';
|
||||
import {CompilationResult, FiledataPair} from '../../types/compilation/compilation.interfaces.js';
|
||||
import {ResultLine} from '../../types/resultline/resultline.interfaces.js';
|
||||
import {CompilationStatus as CompilerServiceCompilationStatus} from '../compiler-service.interfaces.js';
|
||||
import {CompilerPicker} from '../widgets/compiler-picker.js';
|
||||
import {GccDumpViewSelectedPass} from './gccdump-view.interfaces.js';
|
||||
import {SourceAndFiles} from '../download-service.js';
|
||||
import {ICompilerShared} from '../compiler-shared.interfaces.js';
|
||||
import {CompilerShared} from '../compiler-shared.js';
|
||||
import type {ConfiguredOverrides} from '../compilation/compiler-overrides.interfaces.js';
|
||||
import {CompilationRequest, CompilationRequestOptions, LangInfo} from './compiler-request.interfaces.js';
|
||||
|
||||
const languages = options.languages;
|
||||
|
||||
@@ -69,73 +70,6 @@ function makeAnsiToHtml(color?: string): AnsiToHtml {
|
||||
});
|
||||
}
|
||||
|
||||
type ActiveTools = {
|
||||
id: number;
|
||||
args: string[];
|
||||
stdin: string;
|
||||
};
|
||||
|
||||
type CompilationRequestOptions = {
|
||||
userArguments: string;
|
||||
compilerOptions: {
|
||||
executorRequest?: boolean;
|
||||
skipAsm?: boolean;
|
||||
producePp?: PPOptions | null;
|
||||
produceAst?: boolean;
|
||||
produceGccDump?: {
|
||||
opened: boolean;
|
||||
pass?: GccDumpViewSelectedPass;
|
||||
treeDump?: boolean;
|
||||
rtlDump?: boolean;
|
||||
ipaDump?: boolean;
|
||||
dumpFlags: any;
|
||||
};
|
||||
produceOptInfo?: boolean;
|
||||
produceCfg?: boolean;
|
||||
produceGnatDebugTree?: boolean;
|
||||
produceGnatDebug?: boolean;
|
||||
produceIr?: boolean;
|
||||
produceLLVMOptPipeline?: LLVMOptPipelineBackendOptions | null;
|
||||
produceDevice?: boolean;
|
||||
produceRustMir?: boolean;
|
||||
produceRustMacroExp?: boolean;
|
||||
produceRustHir?: boolean;
|
||||
produceHaskellCore?: boolean;
|
||||
produceHaskellStg?: boolean;
|
||||
produceHaskellCmm?: boolean;
|
||||
cmakeArgs?: string;
|
||||
customOutputFilename?: string;
|
||||
};
|
||||
executeParameters: {
|
||||
args: string;
|
||||
stdin: string;
|
||||
};
|
||||
filters: Record<string, boolean>;
|
||||
tools: ActiveTools[];
|
||||
libraries: CompileChildLibraries[];
|
||||
};
|
||||
|
||||
type CompilationRequest = {
|
||||
source: string;
|
||||
compiler: string;
|
||||
options: CompilationRequestOptions;
|
||||
lang: string | null;
|
||||
files: FiledataPair[];
|
||||
bypassCache?: boolean;
|
||||
};
|
||||
|
||||
type LangInfo = {
|
||||
compiler: string;
|
||||
options: string;
|
||||
execArgs: string;
|
||||
execStdin: string;
|
||||
};
|
||||
|
||||
type CompileChildLibraries = {
|
||||
id: string;
|
||||
version: string;
|
||||
};
|
||||
|
||||
export class Executor extends Pane<ExecutorState> {
|
||||
private contentRoot: JQuery<HTMLElement>;
|
||||
private readonly sourceEditorId: number | null;
|
||||
@@ -190,6 +124,7 @@ export class Executor extends Pane<ExecutorState> {
|
||||
private libsWidget?: LibsWidget;
|
||||
private readonly infoByLang: Record<string, LangInfo | undefined>;
|
||||
private compiler: CompilerInfo | null;
|
||||
private compilerShared: ICompilerShared;
|
||||
|
||||
constructor(hub: Hub, container: Container, state: PaneState & ExecutorState) {
|
||||
super(hub, container, state);
|
||||
@@ -231,11 +166,13 @@ export class Executor extends Pane<ExecutorState> {
|
||||
);
|
||||
|
||||
this.initLibraries(state);
|
||||
this.compilerShared = new CompilerShared(this.domRoot, this.onCompilerOverridesChange.bind(this));
|
||||
this.compilerShared.updateState(state);
|
||||
this.initCallbacks();
|
||||
// Handle initial settings
|
||||
this.onSettingsChange(this.settings);
|
||||
this.updateCompilerInfo();
|
||||
this.saveState();
|
||||
this.updateState();
|
||||
|
||||
if (this.sourceTreeId) {
|
||||
this.compile();
|
||||
@@ -340,6 +277,7 @@ export class Executor extends Pane<ExecutorState> {
|
||||
compilerOptions: {
|
||||
executorRequest: true,
|
||||
skipAsm: true,
|
||||
overrides: this.compilerShared.getOverrides(),
|
||||
},
|
||||
filters: {execute: true},
|
||||
tools: [],
|
||||
@@ -900,7 +838,7 @@ export class Executor extends Pane<ExecutorState> {
|
||||
}
|
||||
|
||||
onLibsChanged(): void {
|
||||
this.saveState();
|
||||
this.updateState();
|
||||
this.compile();
|
||||
}
|
||||
|
||||
@@ -920,13 +858,13 @@ export class Executor extends Pane<ExecutorState> {
|
||||
}
|
||||
|
||||
onFontScale(): void {
|
||||
this.saveState();
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
initListeners(): void {
|
||||
// this.filters.on('change', _.bind(this.onFilterChange, this));
|
||||
this.fontScale.on('change', this.onFontScale.bind(this));
|
||||
this.paneRenaming.on('renamePane', this.saveState.bind(this));
|
||||
this.paneRenaming.on('renamePane', this.updateState.bind(this));
|
||||
this.toggleWrapButton.on('change', this.onToggleWrapChange.bind(this));
|
||||
|
||||
this.container.on('destroy', this.close, this);
|
||||
@@ -967,7 +905,7 @@ export class Executor extends Pane<ExecutorState> {
|
||||
} else {
|
||||
this.hidePanel(button, panel);
|
||||
}
|
||||
this.saveState();
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
initCallbacks(): void {
|
||||
@@ -1051,7 +989,7 @@ export class Executor extends Pane<ExecutorState> {
|
||||
|
||||
onOptionsChange(options: string): void {
|
||||
this.options = options;
|
||||
this.saveState();
|
||||
this.updateState();
|
||||
if (this.shouldEmitExecutionOnFieldChange()) {
|
||||
this.compile();
|
||||
}
|
||||
@@ -1059,7 +997,14 @@ export class Executor extends Pane<ExecutorState> {
|
||||
|
||||
onExecArgsChange(args: string): void {
|
||||
this.executionArguments = args;
|
||||
this.saveState();
|
||||
this.updateState();
|
||||
if (this.shouldEmitExecutionOnFieldChange()) {
|
||||
this.compile();
|
||||
}
|
||||
}
|
||||
|
||||
onCompilerOverridesChange(): void {
|
||||
this.updateState();
|
||||
if (this.shouldEmitExecutionOnFieldChange()) {
|
||||
this.compile();
|
||||
}
|
||||
@@ -1067,7 +1012,7 @@ export class Executor extends Pane<ExecutorState> {
|
||||
|
||||
onExecStdinChange(newStdin: string): void {
|
||||
this.executionStdin = newStdin;
|
||||
this.saveState();
|
||||
this.updateState();
|
||||
if (this.shouldEmitExecutionOnFieldChange()) {
|
||||
this.compile();
|
||||
}
|
||||
@@ -1103,16 +1048,16 @@ export class Executor extends Pane<ExecutorState> {
|
||||
onCompilerChange(value: string): void {
|
||||
this.compiler = this.hub.compilerService.findCompiler(this.currentLangId, value);
|
||||
this.updateLibraries();
|
||||
this.saveState();
|
||||
this.updateState();
|
||||
this.compile();
|
||||
this.updateCompilerUI();
|
||||
}
|
||||
|
||||
onToggleWrapChange(): void {
|
||||
const state = this.currentState();
|
||||
const state = this.getCurrentState();
|
||||
this.contentRoot.toggleClass('wrap', state.wrap);
|
||||
this.wrapButton.prop('title', '[' + (state.wrap ? 'ON' : 'OFF') + '] ' + this.wrapTitle);
|
||||
this.saveState();
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
sendExecutor(): void {
|
||||
@@ -1137,7 +1082,7 @@ export class Executor extends Pane<ExecutorState> {
|
||||
}
|
||||
}
|
||||
|
||||
currentState(): ExecutorState & PaneState {
|
||||
override getCurrentState(): ExecutorState & PaneState {
|
||||
const state: ExecutorState & PaneState = {
|
||||
id: this.id,
|
||||
compilerName: '',
|
||||
@@ -1154,6 +1099,7 @@ export class Executor extends Pane<ExecutorState> {
|
||||
argsPanelShown: !this.panelArgs.hasClass('d-none'),
|
||||
stdinPanelShown: !this.panelStdin.hasClass('d-none'),
|
||||
wrap: this.toggleWrapButton.get().wrap,
|
||||
overrides: this.compilerShared.getOverrides(),
|
||||
};
|
||||
|
||||
this.paneRenaming.addState(state);
|
||||
@@ -1161,8 +1107,10 @@ export class Executor extends Pane<ExecutorState> {
|
||||
return state;
|
||||
}
|
||||
|
||||
saveState(): void {
|
||||
this.container.setState(this.currentState());
|
||||
override updateState(): void {
|
||||
const state = this.getCurrentState();
|
||||
this.container.setState(state);
|
||||
this.compilerShared.updateState(state);
|
||||
}
|
||||
|
||||
getCompilerName(): string {
|
||||
@@ -1327,7 +1275,7 @@ export class Executor extends Pane<ExecutorState> {
|
||||
this.initLangAndCompiler({compilerName: '', id: 0, lang: newLangId, compiler: info?.compiler ?? ''});
|
||||
this.updateCompilersSelector(info);
|
||||
this.updateCompilerUI();
|
||||
this.saveState();
|
||||
this.updateState();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -665,6 +665,61 @@ div.populararguments div.dropdown-menu {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
#overrides-selection .modal-body {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#overrides-selection .override-search-button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
#overrides-selection .overrides-how-to-use {
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
#overrides-selection .overrides-selected-col {
|
||||
padding: 0 15px 0 0;
|
||||
min-width: 250px;
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
#overrides-selection .overrides-results-col {
|
||||
padding: 0 0 0 0;
|
||||
min-width: 450px;
|
||||
max-width: 650px;
|
||||
}
|
||||
|
||||
#overrides-selection .override-results-items .card {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
#overrides-selection.mobile .overrides-results-col {
|
||||
min-width: 250px;
|
||||
max-width: 450px;
|
||||
}
|
||||
|
||||
#overrides-selection .overrides-results-col span.override {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#overrides-selection .overrides-results-col span.override-fav {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#overrides-selection .overrides-favorites-col {
|
||||
padding: 0 0 0 15px;
|
||||
min-width: 325px;
|
||||
max-width: 350px;
|
||||
}
|
||||
|
||||
#overrides-selection .overrides-favorites-col button {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
#overrides-selection.mobile .overrides-favorites-col {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ces-content-root {
|
||||
min-height: 100px;
|
||||
max-height: calc(
|
||||
|
||||
@@ -28,7 +28,8 @@ body {
|
||||
background-color: #333 !important;
|
||||
}
|
||||
|
||||
input {
|
||||
input,
|
||||
textarea {
|
||||
color: #eee !important;
|
||||
background-color: #474747;
|
||||
border: 0 !important;
|
||||
|
||||
380
static/widgets/compiler-overrides.ts
Normal file
380
static/widgets/compiler-overrides.ts
Normal file
@@ -0,0 +1,380 @@
|
||||
// Copyright (c) 2023, 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 $ from 'jquery';
|
||||
import {
|
||||
CompilerOverrideType,
|
||||
ConfiguredOverride,
|
||||
ConfiguredOverrides,
|
||||
EnvVarOverrides,
|
||||
} from '../../types/compilation/compiler-overrides.interfaces.js';
|
||||
import {options} from '../options.js';
|
||||
import {CompilerInfo} from '../compiler.interfaces.js';
|
||||
import * as local from '../local.js';
|
||||
|
||||
const FAV_OVERRIDES_STORE_KEY = 'favoverrides';
|
||||
|
||||
export type CompilerOverridesChangeCallback = () => void;
|
||||
|
||||
type FavOverride = {
|
||||
name: CompilerOverrideType;
|
||||
value: string;
|
||||
meta: string;
|
||||
};
|
||||
|
||||
type FavOverrides = FavOverride[];
|
||||
|
||||
export class CompilerOverridesWidget {
|
||||
private domRoot: JQuery;
|
||||
private popupDomRoot: JQuery<HTMLElement>;
|
||||
private envVarsInput: JQuery<HTMLElement>;
|
||||
private dropdownButton: JQuery;
|
||||
private onChangeCallback: CompilerOverridesChangeCallback;
|
||||
private configured: ConfiguredOverrides = [];
|
||||
private compiler: CompilerInfo | undefined;
|
||||
|
||||
constructor(domRoot: JQuery, dropdownButton: JQuery, onChangeCallback: CompilerOverridesChangeCallback) {
|
||||
this.domRoot = domRoot;
|
||||
this.popupDomRoot = $('#overrides-selection');
|
||||
this.dropdownButton = dropdownButton;
|
||||
this.envVarsInput = this.popupDomRoot.find('.envvars');
|
||||
this.onChangeCallback = onChangeCallback;
|
||||
}
|
||||
|
||||
private loadStateFromUI(): ConfiguredOverrides {
|
||||
const overrides: ConfiguredOverrides = [];
|
||||
|
||||
const envOverrides = this.getEnvOverrides();
|
||||
if (envOverrides.length > 0) {
|
||||
overrides.push({
|
||||
name: CompilerOverrideType.env,
|
||||
values: envOverrides,
|
||||
});
|
||||
}
|
||||
|
||||
const selects = this.popupDomRoot.find('select');
|
||||
for (const select of selects) {
|
||||
const jqSelect = $(select);
|
||||
const name = jqSelect.attr('name');
|
||||
const val = jqSelect.val();
|
||||
if (val) {
|
||||
overrides.push({
|
||||
name: name as CompilerOverrideType,
|
||||
value: val.toString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return overrides;
|
||||
}
|
||||
|
||||
private envvarsToString(envVars: EnvVarOverrides): string {
|
||||
return envVars.map(env => `${env.name}=${env.value}`).join('\n');
|
||||
}
|
||||
|
||||
private stringToEnvvars(envVars: string): EnvVarOverrides {
|
||||
return envVars
|
||||
.split('\n')
|
||||
.map(env => {
|
||||
const arr = env.split('=');
|
||||
if (arr[0]) {
|
||||
return {
|
||||
name: arr[0],
|
||||
value: arr[1],
|
||||
};
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.filter(Boolean) as EnvVarOverrides;
|
||||
}
|
||||
|
||||
private getEnvOverrides(): EnvVarOverrides {
|
||||
return this.stringToEnvvars(this.envVarsInput.val() as string);
|
||||
}
|
||||
|
||||
private selectOverrideFromFave(event) {
|
||||
const elem = $(event.target).parent();
|
||||
const name = elem.data('ov-name');
|
||||
const value = elem.data('ov-value');
|
||||
|
||||
const possibleOverride = this.compiler?.possibleOverrides?.find(ov => ov.name === name);
|
||||
if (possibleOverride) {
|
||||
const override = possibleOverride.values.find(v => v.value === value);
|
||||
if (override) {
|
||||
const currentOverrides = this.loadStateFromUI();
|
||||
const configOv = currentOverrides.find(ov => ov.name === name);
|
||||
if (configOv) {
|
||||
configOv.value = value;
|
||||
} else {
|
||||
currentOverrides.push({
|
||||
name: name,
|
||||
value: value,
|
||||
});
|
||||
}
|
||||
|
||||
this.loadStateIntoUI(currentOverrides);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private newFavoriteOverrideDiv(fave: FavOverride) {
|
||||
const div = $('#overrides-favorite-tpl').children().clone();
|
||||
const prefix = fave.name + ': ';
|
||||
div.find('.overrides-name').html(prefix + fave.value);
|
||||
div.data('ov-name', fave.name);
|
||||
div.data('ov-value', fave.value);
|
||||
div.on('click', this.selectOverrideFromFave.bind(this));
|
||||
return div;
|
||||
}
|
||||
|
||||
private loadFavoritesIntoUI() {
|
||||
const favoritesDiv = this.popupDomRoot.find('.overrides-favorites');
|
||||
favoritesDiv.html('');
|
||||
|
||||
const faves = this.getFavorites();
|
||||
for (const fave of faves) {
|
||||
const div: any = this.newFavoriteOverrideDiv(fave);
|
||||
favoritesDiv.append(div);
|
||||
}
|
||||
}
|
||||
|
||||
private addToFavorites(override: ConfiguredOverride) {
|
||||
if (!override.value) return;
|
||||
|
||||
const faves = this.getFavorites();
|
||||
|
||||
const fave: FavOverride = {
|
||||
name: override.name,
|
||||
value: override.value,
|
||||
meta: this.compiler?.baseName || this.compiler?.groupName || this.compiler?.name || this.compiler?.id || '',
|
||||
};
|
||||
|
||||
faves.push(fave);
|
||||
|
||||
this.setFavorites(faves);
|
||||
}
|
||||
|
||||
private removeFromFavorites(override: ConfiguredOverride) {
|
||||
if (!override.value) return;
|
||||
|
||||
const faves = this.getFavorites();
|
||||
const faveIdx = faves.findIndex(f => f.name === override.name && f.value === override.value);
|
||||
if (faveIdx !== -1) {
|
||||
faves.splice(faveIdx, 1);
|
||||
this.setFavorites(faves);
|
||||
}
|
||||
}
|
||||
|
||||
private isAFavorite(override: ConfiguredOverride) {
|
||||
if (!override.value) return false;
|
||||
|
||||
const faves = this.getFavorites();
|
||||
const fave = faves.find(f => f.name === override.name && f.value === override.value);
|
||||
return !!fave;
|
||||
}
|
||||
|
||||
private loadStateIntoUI(configured: ConfiguredOverrides) {
|
||||
this.envVarsInput.val('');
|
||||
|
||||
for (const config of configured) {
|
||||
if (config.name === CompilerOverrideType.env) {
|
||||
this.envVarsInput.val(this.envvarsToString(config.values || []));
|
||||
}
|
||||
}
|
||||
|
||||
const container = this.popupDomRoot.find('.possible-overrides');
|
||||
container.html('');
|
||||
if (this.compiler && this.compiler.possibleOverrides) {
|
||||
for (const possibleOverride of this.compiler.possibleOverrides) {
|
||||
const card = $('#possible-override').children().clone();
|
||||
card.find('.override-name').html(possibleOverride.display_title);
|
||||
card.find('.override-description').html(possibleOverride.description);
|
||||
|
||||
const select = card.find<HTMLSelectElement>('.override select');
|
||||
select.attr('name', possibleOverride.name);
|
||||
|
||||
const faveButton = card.find('.override-fav-button');
|
||||
const faveStar = faveButton.find('.override-fav-btn-icon');
|
||||
faveButton.hide();
|
||||
|
||||
const config = configured.find(c => c.name === possibleOverride.name);
|
||||
|
||||
let option = $('<option />');
|
||||
select.append(option);
|
||||
|
||||
for (const value of possibleOverride.values) {
|
||||
option = $('<option />');
|
||||
option.html(value.name);
|
||||
option.val(value.value);
|
||||
|
||||
if (config && config.value && config.value === value.value) {
|
||||
option.attr('selected', 'selected');
|
||||
|
||||
if (this.isAFavorite(config)) {
|
||||
faveStar.removeClass('far').addClass('fas');
|
||||
}
|
||||
|
||||
faveButton.show();
|
||||
}
|
||||
|
||||
select.append(option);
|
||||
}
|
||||
|
||||
select.off('change').on('change', () => {
|
||||
const option = select.find('option:selected');
|
||||
if (option.length > 0) {
|
||||
const value = option.val()?.toString();
|
||||
const name = possibleOverride.name;
|
||||
|
||||
const ov: ConfiguredOverride = {
|
||||
name: name,
|
||||
value: value,
|
||||
};
|
||||
|
||||
if (this.isAFavorite(ov)) {
|
||||
faveStar.removeClass('far').addClass('fas');
|
||||
} else {
|
||||
faveStar.removeClass('fas').addClass('far');
|
||||
}
|
||||
|
||||
if (ov.value !== '') {
|
||||
faveButton.show();
|
||||
} else {
|
||||
faveButton.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
faveButton.on('click', () => {
|
||||
const option = select.find('option:selected');
|
||||
if (option.length > 0) {
|
||||
const value = option.val()?.toString();
|
||||
const name = possibleOverride.name;
|
||||
|
||||
const ov: ConfiguredOverride = {name, value};
|
||||
if (this.isAFavorite(ov)) {
|
||||
this.removeFromFavorites(ov);
|
||||
faveStar.removeClass('fas').addClass('far');
|
||||
} else {
|
||||
this.addToFavorites(ov);
|
||||
faveStar.removeClass('far').addClass('fas');
|
||||
}
|
||||
}
|
||||
|
||||
this.loadFavoritesIntoUI();
|
||||
});
|
||||
|
||||
container.append(card);
|
||||
}
|
||||
}
|
||||
|
||||
this.loadFavoritesIntoUI();
|
||||
}
|
||||
|
||||
set(configured: ConfiguredOverrides) {
|
||||
this.configured = configured;
|
||||
this.updateButton();
|
||||
}
|
||||
|
||||
setDefaults() {
|
||||
this.configured = [];
|
||||
|
||||
if (this.compiler && this.compiler.possibleOverrides) {
|
||||
for (const ov of this.compiler.possibleOverrides) {
|
||||
if (ov.name !== CompilerOverrideType.env && ov.default) {
|
||||
this.configured.push({
|
||||
name: ov.name,
|
||||
value: ov.default,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.updateButton();
|
||||
}
|
||||
|
||||
setCompiler(compilerId: string, languageId?: string) {
|
||||
this.compiler = options.compilers.find(c => c.id === compilerId);
|
||||
}
|
||||
|
||||
get(): ConfiguredOverrides | undefined {
|
||||
if (this.compiler) {
|
||||
return this.configured;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private getFavorites(): FavOverrides {
|
||||
return JSON.parse(local.get(FAV_OVERRIDES_STORE_KEY, '[]'));
|
||||
}
|
||||
|
||||
private setFavorites(faves: FavOverrides) {
|
||||
local.set(FAV_OVERRIDES_STORE_KEY, JSON.stringify(faves));
|
||||
}
|
||||
|
||||
private updateButton() {
|
||||
const selected = this.get();
|
||||
if (selected && selected.length > 0) {
|
||||
this.dropdownButton
|
||||
.addClass('btn-success')
|
||||
.removeClass('btn-light')
|
||||
.prop(
|
||||
'title',
|
||||
'Current overrides:\n' +
|
||||
selected
|
||||
.map(ov => {
|
||||
let line = '- ' + ov.name;
|
||||
if (ov.value) {
|
||||
line += ' = ' + ov.value;
|
||||
}
|
||||
return line;
|
||||
})
|
||||
.join('\n'),
|
||||
);
|
||||
} else {
|
||||
this.dropdownButton.removeClass('btn-success').addClass('btn-light').prop('title', 'Overrides');
|
||||
}
|
||||
}
|
||||
|
||||
show() {
|
||||
this.loadStateIntoUI(this.configured);
|
||||
|
||||
const lastOverrides = JSON.stringify(this.configured);
|
||||
|
||||
const popup = this.popupDomRoot.modal();
|
||||
// popup is shared, so clear the events first
|
||||
popup.off('hidden.bs.modal').on('hidden.bs.modal', () => {
|
||||
this.configured = this.loadStateFromUI();
|
||||
|
||||
const newOverrides = JSON.stringify(this.configured);
|
||||
|
||||
if (lastOverrides !== newOverrides) {
|
||||
this.updateButton();
|
||||
this.onChangeCallback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import {BuildEnvSetupBase} from '../lib/buildenvsetup/index.js';
|
||||
import {CompilationEnvironment} from '../lib/compilation-env.js';
|
||||
import {Win32Compiler} from '../lib/compilers/win32.js';
|
||||
import * as exec from '../lib/exec.js';
|
||||
import {CompilerOverrideType, ConfiguredOverrides} from '../types/compilation/compiler-overrides.interfaces.js';
|
||||
import {CompilerInfo} from '../types/compiler.interfaces.js';
|
||||
|
||||
import {
|
||||
@@ -222,6 +223,7 @@ describe('Compiler execution', function () {
|
||||
inputFilename,
|
||||
outputFilename,
|
||||
libraries,
|
||||
[],
|
||||
);
|
||||
args.should.deep.equal([
|
||||
'-g',
|
||||
@@ -250,6 +252,7 @@ describe('Compiler execution', function () {
|
||||
inputFilename,
|
||||
outputFilename,
|
||||
libraries,
|
||||
[],
|
||||
);
|
||||
win32args.should.deep.equal([
|
||||
'/nologo',
|
||||
@@ -282,6 +285,39 @@ describe('Compiler execution', function () {
|
||||
buildenv.compilerSupportsX86.should.equal(true);
|
||||
});
|
||||
|
||||
it('compiler overrides should be sanitized', () => {
|
||||
const original_overrides: ConfiguredOverrides = [
|
||||
{
|
||||
name: CompilerOverrideType.env,
|
||||
values: [
|
||||
{
|
||||
name: 'somevar',
|
||||
value: '123',
|
||||
},
|
||||
{
|
||||
name: 'ABC$#%@6@5',
|
||||
value: '456',
|
||||
},
|
||||
{
|
||||
name: 'LD_PRELOAD',
|
||||
value: '/path/to/my/malloc.so /bin/ls',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const sanitized = compiler.sanitizeCompilerOverrides(original_overrides);
|
||||
|
||||
const execOptions = compiler.getDefaultExecOptions();
|
||||
|
||||
compiler.applyOverridesToExecOptions(execOptions, sanitized);
|
||||
|
||||
Object.keys(execOptions.env).should.include('SOMEVAR');
|
||||
execOptions.env['SOMEVAR'].should.equal('123');
|
||||
Object.keys(execOptions.env).should.not.include('LD_PRELOAD');
|
||||
Object.keys(execOptions.env).should.not.include('ABC$#%@6@5');
|
||||
});
|
||||
|
||||
// it('should compile', async () => {
|
||||
// const execStub = stub(compiler, 'exec');
|
||||
// stubOutCallToExec(
|
||||
|
||||
@@ -23,7 +23,14 @@
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import {CompilerArguments} from '../../lib/compiler-arguments.js';
|
||||
import {BaseParser, ClangParser, GCCParser, PascalParser} from '../../lib/compilers/argument-parsers.js';
|
||||
import {
|
||||
BaseParser,
|
||||
ClangParser,
|
||||
GCCParser,
|
||||
ICCParser,
|
||||
PascalParser,
|
||||
VCParser,
|
||||
} from '../../lib/compilers/argument-parsers.js';
|
||||
import {FakeCompiler} from '../../lib/compilers/fake-for-test.js';
|
||||
import {makeCompilationEnvironment, should} from '../utils.js';
|
||||
|
||||
@@ -124,7 +131,7 @@ describe('clang parser', () => {
|
||||
});
|
||||
it('should handle options', () => {
|
||||
return ClangParser.parse(
|
||||
makeCompiler('-fno-crash-diagnostics\n-fsave-optimization-record\n-fcolor-diagnostics'),
|
||||
makeCompiler(' -fno-crash-diagnostics\n -fsave-optimization-record\n -fcolor-diagnostics'),
|
||||
).should.eventually.satisfy(result => {
|
||||
return Promise.all([
|
||||
result.compiler.supportsOptOutput.should.equals(true),
|
||||
@@ -151,7 +158,7 @@ describe('popular compiler arguments', () => {
|
||||
|
||||
before(() => {
|
||||
compiler = makeCompiler(
|
||||
'-fsave-optimization-record\n-x\n-g\n-fcolor-diagnostics\n-O<number> optimization level\n-std=<c++11,c++14,c++17z>',
|
||||
' -fsave-optimization-record\n -x\n -g\n -fcolor-diagnostics\n -O<number> Optimization level\n -std=<c++11,c++14,c++17z>',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -160,7 +167,7 @@ describe('popular compiler arguments', () => {
|
||||
return compiler.should.satisfy(compiler => {
|
||||
return Promise.all([
|
||||
compiler.possibleArguments.getPopularArguments().should.deep.equal({
|
||||
'-O<number>': {description: 'optimization level', timesused: 0},
|
||||
'-O<number>': {description: 'Optimization level', timesused: 0},
|
||||
'-fcolor-diagnostics': {description: '', timesused: 0},
|
||||
'-fsave-optimization-record': {description: '', timesused: 0},
|
||||
'-g': {description: '', timesused: 0},
|
||||
@@ -192,7 +199,7 @@ describe('popular compiler arguments', () => {
|
||||
return compiler.should.satisfy(compiler => {
|
||||
return Promise.all([
|
||||
compiler.possibleArguments.getPopularArguments(['-std=c++14', '-g', '--hello']).should.deep.equal({
|
||||
'-O<number>': {description: 'optimization level', timesused: 0},
|
||||
'-O<number>': {description: 'Optimization level', timesused: 0},
|
||||
'-fcolor-diagnostics': {description: '', timesused: 0},
|
||||
'-fsave-optimization-record': {description: '', timesused: 0},
|
||||
'-x': {description: '', timesused: 0},
|
||||
@@ -202,3 +209,66 @@ describe('popular compiler arguments', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('VC argument parser', () => {
|
||||
it('Should extract stdversions', () => {
|
||||
const lines = [
|
||||
' /helloWorld',
|
||||
' /std:<c++14|c++17|c++20|c++latest> C++ standard version',
|
||||
' c++14 - ISO/IEC 14882:2014 (default)',
|
||||
' c++17 - ISO/IEC 14882:2017',
|
||||
' c++20 - ISO/IEC 14882:2020',
|
||||
' c++latest - latest draft standard (feature set subject to change)',
|
||||
' /something:<else> Something Else',
|
||||
' /etc Etcetera',
|
||||
];
|
||||
const stdvers = VCParser.extractPossibleStdvers(lines);
|
||||
stdvers.should.deep.equal([
|
||||
{
|
||||
name: 'c++14: ISO/IEC 14882:2014 (default)',
|
||||
value: 'c++14',
|
||||
},
|
||||
{
|
||||
name: 'c++17: ISO/IEC 14882:2017',
|
||||
value: 'c++17',
|
||||
},
|
||||
{
|
||||
name: 'c++20: ISO/IEC 14882:2020',
|
||||
value: 'c++20',
|
||||
},
|
||||
{
|
||||
name: 'c++latest: latest draft standard (feature set subject to change)',
|
||||
value: 'c++latest',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ICC argument parser', () => {
|
||||
it('Should extract stdversions', () => {
|
||||
const lines = [
|
||||
'-test',
|
||||
'-std=<std>',
|
||||
' enable language support for <std>, as described below',
|
||||
' c99 conforms to ISO/IEC 9899:1999 standard for C programs',
|
||||
' c++11 enables C++11 support for C++ programs',
|
||||
' gnu++98 conforms to 1998 ISO C++ standard plus GNU extensions',
|
||||
'-etc',
|
||||
];
|
||||
const stdvers = ICCParser.extractPossibleStdvers(lines);
|
||||
stdvers.should.deep.equal([
|
||||
{
|
||||
name: 'c99: conforms to ISO/IEC 9899:1999 standard for C programs',
|
||||
value: 'c99',
|
||||
},
|
||||
{
|
||||
name: 'c++11: enables C++11 support for C++ programs',
|
||||
value: 'c++11',
|
||||
},
|
||||
{
|
||||
name: 'gnu++98: conforms to 1998 ISO C++ standard plus GNU extensions',
|
||||
value: 'gnu++98',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,6 +22,13 @@
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import {
|
||||
getToolchainFlagFromOptions,
|
||||
getToolchainPathWithOptionsArr,
|
||||
hasToolchainArg,
|
||||
removeToolchainArg,
|
||||
replaceToolchainArg,
|
||||
} from '../lib/toolchain-utils.js';
|
||||
import {CompilerDropinTool} from '../lib/tooling/compiler-dropin-tool.js';
|
||||
|
||||
import {path} from './utils.js';
|
||||
@@ -172,4 +179,62 @@ describe('CompilerDropInTool', () => {
|
||||
'-pthread',
|
||||
]);
|
||||
});
|
||||
|
||||
it('More toolchain magic', () => {
|
||||
const options = [
|
||||
'-gdwarf-4',
|
||||
'-g',
|
||||
'-o',
|
||||
'output.s',
|
||||
'-mllvm',
|
||||
'--x86-asm-syntax=intel',
|
||||
'-S',
|
||||
'--gcc-toolchain=/opt/compiler-explorer/gcc-12.2.0',
|
||||
'-fcolor-diagnostics',
|
||||
'-fno-crash-diagnostics',
|
||||
'/app/example.cpp',
|
||||
];
|
||||
|
||||
hasToolchainArg(options).should.be.true;
|
||||
|
||||
getToolchainFlagFromOptions(options).should.equal('--gcc-toolchain=');
|
||||
|
||||
const newOptions = removeToolchainArg(options);
|
||||
hasToolchainArg(newOptions).should.be.false;
|
||||
});
|
||||
|
||||
it('Should be able to swap toolchain', () => {
|
||||
const exe = '/opt/compiler-explorer/clang-16.0.0/bin/clang++';
|
||||
const options = [
|
||||
'-gdwarf-4',
|
||||
'-g',
|
||||
'-o',
|
||||
'output.s',
|
||||
'-mllvm',
|
||||
'--x86-asm-syntax=intel',
|
||||
'-S',
|
||||
'--gcc-toolchain=/opt/compiler-explorer/gcc-12.2.0',
|
||||
'-fcolor-diagnostics',
|
||||
'-fno-crash-diagnostics',
|
||||
'/app/example.cpp',
|
||||
];
|
||||
|
||||
const toolchain = getToolchainPathWithOptionsArr(exe, options);
|
||||
toolchain.should.equals('/opt/compiler-explorer/gcc-12.2.0');
|
||||
|
||||
const replacedOptions = replaceToolchainArg(options, '/opt/compiler-explorer/gcc-11.1.0');
|
||||
replacedOptions.should.deep.equal([
|
||||
'-gdwarf-4',
|
||||
'-g',
|
||||
'-o',
|
||||
'output.s',
|
||||
'-mllvm',
|
||||
'--x86-asm-syntax=intel',
|
||||
'-S',
|
||||
'--gcc-toolchain=/opt/compiler-explorer/gcc-11.1.0',
|
||||
'-fcolor-diagnostics',
|
||||
'-fno-crash-diagnostics',
|
||||
'/app/example.cpp',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -123,6 +123,7 @@ export type ExecutionOptions = {
|
||||
ldPath?: string[];
|
||||
appHome?: string;
|
||||
customCwd?: string;
|
||||
createAndUseTempDir?: boolean;
|
||||
// Stdin
|
||||
input?: any;
|
||||
killChild?: () => void;
|
||||
|
||||
68
types/compilation/compiler-overrides.interfaces.ts
Normal file
68
types/compilation/compiler-overrides.interfaces.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2023, 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.
|
||||
|
||||
export enum CompilerOverrideType {
|
||||
stdlib = 'stdlib',
|
||||
gcclib = 'gcclib',
|
||||
toolchain = 'toolchain',
|
||||
arch = 'arch',
|
||||
env = 'env',
|
||||
edition = 'edition',
|
||||
stdver = 'stdver',
|
||||
}
|
||||
|
||||
export type CompilerOverrideTypes = Set<CompilerOverrideType>;
|
||||
|
||||
export type CompilerOverrideOption = {
|
||||
name: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type CompilerOverrideOptions = Array<CompilerOverrideOption>;
|
||||
|
||||
export type CompilerOverrideNameAndOptions = {
|
||||
name: CompilerOverrideType;
|
||||
display_title: string;
|
||||
description: string;
|
||||
flags: string[];
|
||||
values: CompilerOverrideOptions;
|
||||
default?: string;
|
||||
};
|
||||
|
||||
export type AllCompilerOverrideOptions = Array<CompilerOverrideNameAndOptions>;
|
||||
|
||||
export type EnvVarOverride = {
|
||||
name: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type EnvVarOverrides = Array<EnvVarOverride>;
|
||||
|
||||
export type ConfiguredOverride = {
|
||||
name: CompilerOverrideType;
|
||||
value?: string;
|
||||
values?: EnvVarOverrides;
|
||||
};
|
||||
|
||||
export type ConfiguredOverrides = Array<ConfiguredOverride>;
|
||||
@@ -22,6 +22,7 @@
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import {AllCompilerOverrideOptions} from './compilation/compiler-overrides.interfaces.js';
|
||||
import {ICompilerArguments} from './compiler-arguments.interfaces.js';
|
||||
import {Language, LanguageKey} from './languages.interfaces.js';
|
||||
import {Library} from './libraries/libraries.interfaces.js';
|
||||
@@ -79,6 +80,9 @@ export type CompilerInfo = {
|
||||
supportsCfg?: boolean;
|
||||
supportsGnatDebugViews?: boolean;
|
||||
supportsLibraryCodeFilter?: boolean;
|
||||
supportsMarch?: boolean;
|
||||
supportsTarget?: boolean;
|
||||
supportsTargetIs?: boolean;
|
||||
executionWrapper: string;
|
||||
executionWrapperArgs: string[];
|
||||
postProcess: string[];
|
||||
@@ -114,6 +118,7 @@ export type CompilerInfo = {
|
||||
target: string;
|
||||
path: string;
|
||||
};
|
||||
possibleOverrides?: AllCompilerOverrideOptions;
|
||||
disabledFilters: string[];
|
||||
optArg?: string;
|
||||
externalparser: any;
|
||||
|
||||
@@ -20,6 +20,8 @@ include history
|
||||
|
||||
include library-selection
|
||||
|
||||
include overrides-selection
|
||||
|
||||
include timing
|
||||
|
||||
include jsbeebemu
|
||||
|
||||
34
views/popups/overrides-selection.pug
Normal file
34
views/popups/overrides-selection.pug
Normal file
@@ -0,0 +1,34 @@
|
||||
#overrides-selection.modal.fade.gl_keep(tabindex="-1" role="dialog")
|
||||
.modal-dialog.modal-lg
|
||||
.modal-content
|
||||
.modal-header
|
||||
h5.modal-title Compiler overrides
|
||||
button.close(type="button" data-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
span(aria-hidden="true")
|
||||
| ×
|
||||
.modal-body
|
||||
.card
|
||||
.card-body
|
||||
.container
|
||||
.row
|
||||
.col-lg.overrides-how-to-use
|
||||
| To override a compiler's defaults, you can change the following options.
|
||||
| Note that this might lead to errors and unsupported situations.
|
||||
| These also only apply to compilation, not for executing your code.
|
||||
.row
|
||||
.col-lg
|
||||
.row
|
||||
.overrides-results-col.col-md
|
||||
.override-results.items
|
||||
.card
|
||||
.card-header
|
||||
span
|
||||
b.override-name Compiler environment variables
|
||||
.card-body
|
||||
span.description One environment variable per line, KEY=VALUE, that will be set during compilation.
|
||||
span.custom-override
|
||||
textarea.envvars(cols="30")
|
||||
.possible-overrides.items
|
||||
.overrides-favorites-col.col-md
|
||||
h6 Favorites
|
||||
.overrides-favorites
|
||||
@@ -43,6 +43,10 @@ mixin newPaneButton(classId, text, title, icon)
|
||||
button.btn.btn-sm.btn-light.show-libs(title="Include libs" aria-label="Toggle libraries dropdown")
|
||||
span.fas.fa-book
|
||||
span.dp-text.hideable Libraries
|
||||
.btn-group.btn-group-sm(role="group" aria-label="Compiler overrides")
|
||||
button.btn.btn-sm.btn-light.show-overrides(title="Overrides" aria-label="Configure overrides for standards and architectures etc")
|
||||
span.fas.fa-wrench
|
||||
span.dp-text.hideable Overrides
|
||||
.btn-group.btn-group-sm(role="group")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle.add-pane(type="button" title="Add a new pane" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Add new element for this compiler" data-cy="new-compiler-dropdown-btn")
|
||||
span.fas.fa-plus
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
button.btn.btn-sm.btn-light.show-libs(title="Include libs" aria-label="Toggle libraries dropdown")
|
||||
span.fas.fa-book
|
||||
span.dp-text.hideable Libraries
|
||||
button.btn.btn-sm.btn-light.show-overrides(title="Overrides" aria-label="Configure overrides for standards and architectures etc")
|
||||
span.fas.fa-wrench
|
||||
span.dp-text.hideable Overrides
|
||||
button.btn.btn-sm.btn-light.toggle-compilation.active(title="Compiler options" aria-label="Toggle compiler options input")
|
||||
span.fas.fa-cogs
|
||||
span.hideable Compilation
|
||||
|
||||
@@ -48,6 +48,10 @@ mixin monacopane(id)
|
||||
|
||||
include widgets/tree-editor-tpl
|
||||
|
||||
include widgets/possible-override-tpl
|
||||
|
||||
include widgets/overrides-favorite-tpl
|
||||
|
||||
+monacopane("opt")
|
||||
|
||||
+monacopane("flags")
|
||||
|
||||
3
views/templates/widgets/overrides-favorite-tpl.pug
Normal file
3
views/templates/widgets/overrides-favorite-tpl.pug
Normal file
@@ -0,0 +1,3 @@
|
||||
#overrides-favorite-tpl
|
||||
div.mb-1
|
||||
button.btn.btn-md.btn-outline-primary.overrides-name
|
||||
11
views/templates/widgets/possible-override-tpl.pug
Normal file
11
views/templates/widgets/possible-override-tpl.pug
Normal file
@@ -0,0 +1,11 @@
|
||||
#possible-override
|
||||
.card
|
||||
.card-header
|
||||
span.override-name
|
||||
span.override
|
||||
select.custom-select.custom-select-sm
|
||||
.card-body
|
||||
p.override-description
|
||||
span.override-fav
|
||||
button.btn.btn-sm.override-fav-button
|
||||
span.override-fav-btn-icon.far.fa-star
|
||||
Reference in New Issue
Block a user