aboutsummaryrefslogtreecommitdiff
path: root/lib/compilers
diff options
context:
space:
mode:
authornickpdemarco <nickpdemarco@gmail.com>2023-10-11 14:43:05 -0400
committernickpdemarco <nickpdemarco@gmail.com>2023-10-11 14:43:05 -0400
commit9cda199e40c920fcc9c53082b0dabb17d31a8b7f (patch)
treea4e9a03a9feea17376f5990e19c12818d32ec95e /lib/compilers
parent55a2b1455f823026c78b9219f93799af00ef60ae (diff)
parent10796b3696cf1eef928de8c750b4d3350ee0c2db (diff)
downloadcompiler-explorer-9cda199e40c920fcc9c53082b0dabb17d31a8b7f.tar.gz
compiler-explorer-9cda199e40c920fcc9c53082b0dabb17d31a8b7f.zip
Merge main, resolve conflicts with vala
Diffstat (limited to 'lib/compilers')
-rw-r--r--lib/compilers/_all.ts15
-rw-r--r--lib/compilers/ada.ts15
-rw-r--r--lib/compilers/analysis-tool.ts3
-rw-r--r--lib/compilers/argument-parsers.ts817
-rw-r--r--lib/compilers/assembly.ts3
-rw-r--r--lib/compilers/avrgcc6502.ts2
-rw-r--r--lib/compilers/beebasm.ts2
-rw-r--r--lib/compilers/c3c.ts33
-rw-r--r--lib/compilers/carbon.ts6
-rw-r--r--lib/compilers/cc65.ts13
-rw-r--r--lib/compilers/circle.ts15
-rw-r--r--lib/compilers/circt.ts1
-rw-r--r--lib/compilers/clang.ts119
-rw-r--r--lib/compilers/clangcl.ts22
-rw-r--r--lib/compilers/clean.ts2
-rw-r--r--lib/compilers/clspv.ts2
-rw-r--r--lib/compilers/compcert.ts31
-rw-r--r--lib/compilers/dart.ts2
-rw-r--r--lib/compilers/dosbox-compiler.ts2
-rw-r--r--lib/compilers/dotnet.ts315
-rw-r--r--lib/compilers/edg.ts42
-rw-r--r--lib/compilers/flang.ts5
-rw-r--r--lib/compilers/fortran.ts11
-rw-r--r--lib/compilers/gcccobol.ts31
-rw-r--r--lib/compilers/gnucobol.ts35
-rw-r--r--lib/compilers/golang.ts33
-rw-r--r--lib/compilers/haskell.ts6
-rw-r--r--lib/compilers/hlsl.ts15
-rw-r--r--lib/compilers/hook.ts6
-rw-r--r--lib/compilers/ispc.ts18
-rw-r--r--lib/compilers/java.ts14
-rw-r--r--lib/compilers/julia.ts4
-rw-r--r--lib/compilers/kotlin.ts3
-rw-r--r--lib/compilers/llvm-mos.ts9
-rw-r--r--lib/compilers/mlir.ts23
-rw-r--r--lib/compilers/movfuscator.ts47
-rw-r--r--lib/compilers/mrustc.ts2
-rw-r--r--lib/compilers/nasm.ts3
-rw-r--r--lib/compilers/nvcc.ts26
-rw-r--r--lib/compilers/nvcpp.ts129
-rw-r--r--lib/compilers/osaca.ts1
-rw-r--r--lib/compilers/pascal-win.ts4
-rw-r--r--lib/compilers/pascal.ts8
-rw-r--r--lib/compilers/pony.ts21
-rw-r--r--lib/compilers/ptxas.ts4
-rw-r--r--lib/compilers/python.ts2
-rw-r--r--lib/compilers/racket.ts6
-rw-r--r--lib/compilers/rga.ts2
-rw-r--r--lib/compilers/ruby.ts2
-rw-r--r--lib/compilers/rust.ts45
-rw-r--r--lib/compilers/snowball.ts95
-rw-r--r--lib/compilers/solidity.ts4
-rw-r--r--lib/compilers/spirv.ts25
-rw-r--r--lib/compilers/swift.ts14
-rw-r--r--lib/compilers/tendra.ts5
-rw-r--r--lib/compilers/tic2000.ts70
-rw-r--r--lib/compilers/turboc.ts4
-rw-r--r--lib/compilers/typescript-native.ts126
-rw-r--r--lib/compilers/v.ts230
-rw-r--r--lib/compilers/v8.ts63
-rw-r--r--lib/compilers/vala.ts109
-rw-r--r--lib/compilers/win32-mingw-clang.ts114
-rw-r--r--lib/compilers/win32-mingw-gcc.ts114
-rw-r--r--lib/compilers/win32.ts12
-rw-r--r--lib/compilers/wine-vc.ts9
-rw-r--r--lib/compilers/wsl-vc.ts11
-rw-r--r--lib/compilers/z88dk.ts26
-rw-r--r--lib/compilers/zig.ts1
-rw-r--r--lib/compilers/zigcxx.ts5
69 files changed, 2685 insertions, 329 deletions
diff --git a/lib/compilers/_all.ts b/lib/compilers/_all.ts
index efb91b8d0..03593ba60 100644
--- a/lib/compilers/_all.ts
+++ b/lib/compilers/_all.ts
@@ -27,6 +27,7 @@ export {AnalysisTool} from './analysis-tool.js';
export {AssemblyCompiler} from './assembly.js';
export {AvrGcc6502Compiler} from './avrgcc6502.js';
export {BeebAsmCompiler} from './beebasm.js';
+export {C3Compiler} from './c3c.js';
export {CarbonCompiler} from './carbon.js';
export {Cc65Compiler} from './cc65.js';
export {CircleCompiler} from './circle.js';
@@ -37,7 +38,10 @@ export {ClangCLCompiler} from './clangcl.js';
export {ClangCudaCompiler} from './clang.js';
export {ClangHipCompiler} from './clang.js';
export {ClangIntelCompiler} from './clang.js';
+export {ClangHexagonCompiler} from './clang.js';
+export {ClangDxcCompiler} from './clang.js';
export {CleanCompiler} from './clean.js';
+export {CompCertCompiler} from './compcert.js';
export {CppFrontCompiler} from './cppfront.js';
export {CprocCompiler} from './cproc.js';
export {CLSPVCompiler} from './clspv.js';
@@ -46,6 +50,7 @@ export {CSharpCompiler} from './dotnet.js';
export {DartCompiler} from './dart.js';
export {DefaultCompiler} from './default.js';
export {DMDCompiler} from './dmd.js';
+export {EDGCompiler} from './edg.js';
export {EllccCompiler} from './ellcc.js';
export {ErlangCompiler} from './erlang.js';
export {EWARMCompiler} from './ewarm.js';
@@ -57,6 +62,7 @@ export {FPCCompiler} from './pascal.js';
export {FSharpCompiler} from './dotnet.js';
export {GCCCompiler} from './gcc.js';
export {GCCRSCompiler} from './gccrs.js';
+export {GCCCobolCompiler} from './gcccobol.js';
export {GnuCobolCompiler} from './gnucobol.js';
export {GolangCompiler} from './golang.js';
export {HaskellCompiler} from './haskell.js';
@@ -71,13 +77,16 @@ export {LDCCompiler} from './ldc.js';
export {LLCCompiler} from './llc.js';
export {LLVMmcaTool} from './llvm-mca.js';
export {LLVMMOSCompiler} from './llvm-mos.js';
+export {MovfuscatorCompiler} from './movfuscator.js';
export {MLIRCompiler} from './mlir.js';
export {GM2Compiler} from './gm2.js';
export {MrustcCompiler} from './mrustc.js';
+export {SnowballCompiler} from './snowball.js';
export {NasmCompiler} from './nasm.js';
export {NimCompiler} from './nim.js';
export {NvccCompiler} from './nvcc.js';
export {NvrtcCompiler} from './nvrtc.js';
+export {NvcppCompiler} from './nvcpp.js';
export {OCamlCompiler} from './ocaml.js';
export {OptCompiler} from './opt.js';
export {OSACATool} from './osaca.js';
@@ -97,14 +106,20 @@ export {SolidityCompiler} from './solidity.js';
export {SPIRVCompiler} from './spirv.js';
export {SwiftCompiler} from './swift.js';
export {TenDRACompiler} from './tendra.js';
+export {TIC2000} from './tic2000.js';
export {TinyCCompiler} from './tinyc.js';
export {ToitCompiler} from './toit.js';
export {TurboCCompiler} from './turboc.js';
export {TypeScriptNativeCompiler} from './typescript-native.js';
+export {VCompiler} from './v.js';
+export {ValaCompiler} from './vala.js';
export {VBCompiler} from './dotnet.js';
+export {V8Compiler} from './v8.js';
export {Win32Compiler} from './win32.js';
export {Win32Vc6Compiler} from './win32-vc6.js';
export {Win32VcCompiler} from './win32-vc.js';
+export {Win32MingWGcc} from './win32-mingw-gcc.js';
+export {Win32MingWClang} from './win32-mingw-clang.js';
export {WineVcCompiler} from './wine-vc.js';
export {WslVcCompiler} from './wsl-vc.js';
export {ValCompiler} from './val.js';
diff --git a/lib/compilers/ada.ts b/lib/compilers/ada.ts
index be8434596..a379449ea 100644
--- a/lib/compilers/ada.ts
+++ b/lib/compilers/ada.ts
@@ -24,11 +24,13 @@
// POSSIBILITY OF SUCH DAMAGE.
import path from 'path';
+import {unwrap} from '../assert.js';
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() {
@@ -37,9 +39,17 @@ export class AdaCompiler extends BaseCompiler {
constructor(info: PreliminaryCompilerInfo, env) {
super(info, env);
+
+ this.outputFilebase = 'example';
+
this.compiler.supportsGccDump = true;
this.compiler.removeEmptyGccDump = true;
+ // this is not showing-up in the --help, so argument parser doesn't
+ // automatically detect the support.
+ this.compiler.stackUsageArg = '-fstack-usage';
+ this.compiler.supportsStackUsageOutput = true;
+
// used for all GNAT related panes (Expanded code, Tree)
this.compiler.supportsGnatDebugViews = true;
}
@@ -76,6 +86,7 @@ export class AdaCompiler extends BaseCompiler {
inputFilename: string,
outputFilename: string,
libraries,
+ overrides: ConfiguredOverrides,
) {
backendOptions = backendOptions || {};
@@ -99,6 +110,10 @@ export class AdaCompiler extends BaseCompiler {
gnatmake_opts.push(`--RTS=${this.compiler.adarts}`);
}
+ if (this.compiler.supportsStackUsageOutput && backendOptions.produceStackUsageInfo) {
+ gnatmake_opts.push(unwrap(this.compiler.stackUsageArg));
+ }
+
if (!filters.execute && backendOptions.produceGnatDebug && this.compiler.supportsGnatDebugViews)
// This is using stdout
gnatmake_opts.push('-gnatGL');
diff --git a/lib/compilers/analysis-tool.ts b/lib/compilers/analysis-tool.ts
index c7d96afd1..073540d1d 100644
--- a/lib/compilers/analysis-tool.ts
+++ b/lib/compilers/analysis-tool.ts
@@ -35,7 +35,7 @@ export class AnalysisTool extends BaseCompiler {
super(
{
// Default is to disable all "cosmetic" filters
- disabledFilters: ['labels', 'directives', 'commentOnly', 'trim'],
+ disabledFilters: ['labels', 'directives', 'commentOnly', 'trim', 'debugCalls'],
...info,
},
env,
@@ -56,6 +56,7 @@ export class AnalysisTool extends BaseCompiler {
libraryCode: false,
trim: false,
binaryObject: false,
+ debugCalls: false,
};
}
}
diff --git a/lib/compilers/argument-parsers.ts b/lib/compilers/argument-parsers.ts
index b87d59a5e..4586a7eb4 100644
--- a/lib/compilers/argument-parsers.ts
+++ b/lib/compilers/argument-parsers.ts
@@ -30,49 +30,108 @@ import _ from 'underscore';
import {logger} from '../logger.js';
import * as props from '../properties.js';
import * as utils from '../utils.js';
+import fs from 'fs-extra';
+import {CompilerOverrideOptions} from '../../types/compilation/compiler-overrides.interfaces.js';
export class BaseParser {
+ static setCompilerSettingsFromOptions(compiler, options) {}
+
static hasSupport(options, forOption) {
return _.keys(options).find(option => option.includes(forOption));
}
- static parseLines(stdout, optionRegex: RegExp) {
+ static hasSupportStartsWith(options, forOption) {
+ return _.keys(options).find(option => option.startsWith(forOption));
+ }
+
+ static getExamplesRoot(): string {
+ return props.get('builtin', 'sourcePath', './examples/');
+ }
+
+ static getDefaultExampleFilename() {
+ return 'c++/default.cpp';
+ }
+
+ static getExampleFilepath(): string {
+ let filename = path.join(this.getExamplesRoot(), this.getDefaultExampleFilename());
+ if (!path.isAbsolute(filename)) filename = path.join(process.cwd(), filename);
+
+ return filename;
+ }
+
+ static parseLines(stdout, optionWithDescRegex: RegExp, optionWithoutDescRegex?: RegExp) {
let previousOption: false | string = false;
const options = {};
utils.eachLine(stdout, line => {
- const match = line.match(optionRegex);
- if (!match) {
- if (previousOption && line.trim().length > 0) {
- if (options[previousOption].description.endsWith('-'))
- options[previousOption].description += line.trim();
- else {
- if (options[previousOption].description.length > 0)
- options[previousOption].description += ' ' + line.trim();
- else options[previousOption].description = line.trim();
- }
- } else {
- previousOption = false;
+ const match1 = line.match(optionWithDescRegex);
+ if (match1 && match1[1] && match1[2]) {
+ previousOption = match1[1].trim();
+ if (previousOption) {
+ options[previousOption] = {
+ description: this.spaceCompress(match1[2].trim()),
+ timesused: 0,
+ };
}
return;
+ } else if (optionWithoutDescRegex) {
+ const match2 = line.match(optionWithoutDescRegex);
+ if (match2 && match2[1]) {
+ previousOption = match2[1].trim();
+
+ if (previousOption) {
+ options[previousOption] = {
+ description: '',
+ timesused: 0,
+ };
+ }
+ return;
+ }
}
- if (match) previousOption = match[1];
- if (previousOption) {
- options[previousOption] = {
- description: match[2].trim(),
- timesused: 0,
- };
+ if (previousOption && line.trim().length > 0) {
+ if (options[previousOption].description.endsWith('-'))
+ options[previousOption].description += line.trim();
+ else {
+ if (options[previousOption].description.length > 0) {
+ const combined = options[previousOption].description + ' ' + line.trim();
+ options[previousOption].description = combined;
+ } else {
+ options[previousOption].description = line.trim();
+ }
+ }
+
+ options[previousOption].description = this.spaceCompress(options[previousOption].description);
+ } else {
+ previousOption = false;
}
});
return options;
}
+ static spaceCompress(text: string): string {
+ return text.replaceAll(' ', ' ');
+ }
+
+ static async getPossibleTargets(compiler): Promise<string[]> {
+ return [];
+ }
+
+ static async getPossibleStdvers(compiler): Promise<CompilerOverrideOptions> {
+ return [];
+ }
+
+ static async getPossibleEditions(compiler): Promise<string[]> {
+ return [];
+ }
+
static async getOptions(compiler, helpArg) {
- const optionFinder = /^\s*(--?[\d+,<=>[\]a-z|-]*)\s*(.*)/i;
+ const optionFinder1 = /^ *(--?[#\d+,<=>[\]a-z|-]* ?[\d+,<=>[\]a-z|-]*) +(.*)/i;
+ const optionFinder2 = /^ *(--?[#\d+,<=>[\]a-z|-]* ?[\d+,<=>[\]a-z|-]*)/i;
const result = await compiler.execCompilerCached(compiler.compiler.exe, [helpArg]);
- const options = result.code === 0 ? BaseParser.parseLines(result.stdout + result.stderr, optionFinder) : {};
+ const options =
+ result.code === 0 ? this.parseLines(result.stdout + result.stderr, optionFinder1, optionFinder2) : {};
compiler.possibleArguments.populateOptions(options);
return options;
}
@@ -83,22 +142,30 @@ export class BaseParser {
}
export class GCCParser extends BaseParser {
- static async setCompilerSettingsFromOptions(compiler, options) {
+ static async checkAndSetMasmIntelIfSupported(compiler) {
+ // -masm= may be available but unsupported by the compiler.
+ const res = await compiler.execCompilerCached(compiler.compiler.exe, [
+ '-fsyntax-only',
+ '--target-help',
+ '-masm=intel',
+ ]);
+ if (res.code === 0) {
+ compiler.compiler.intelAsm = '-masm=intel';
+ compiler.compiler.supportsIntel = true;
+ }
+ }
+
+ static override async setCompilerSettingsFromOptions(compiler, options) {
const keys = _.keys(options);
logger.debug(`gcc-like compiler options: ${keys.join(' ')}`);
- if (BaseParser.hasSupport(options, '-masm=')) {
- // -masm= may be available but unsupported by the compiler.
- const res = await compiler.execCompilerCached(compiler.compiler.exe, [
- '-fsyntax-only',
- '--target-help',
- '-masm=intel',
- ]);
- if (res.code === 0) {
- compiler.compiler.intelAsm = '-masm=intel';
- compiler.compiler.supportsIntel = true;
- }
+ if (this.hasSupport(options, '-masm=')) {
+ await this.checkAndSetMasmIntelIfSupported(compiler);
+ }
+ if (this.hasSupport(options, '-fstack-usage')) {
+ compiler.compiler.stackUsageArg = '-fstack-usage';
+ compiler.compiler.supportsStackUsageOutput = true;
}
- if (BaseParser.hasSupport(options, '-fdiagnostics-color')) {
+ if (this.hasSupport(options, '-fdiagnostics-color')) {
if (compiler.compiler.options) compiler.compiler.options += ' ';
compiler.compiler.options += '-fdiagnostics-color=always';
}
@@ -111,46 +178,100 @@ export class GCCParser extends BaseParser {
// not produce anything.
compiler.compiler.removeEmptyGccDump = true;
}
+ if (this.hasSupportStartsWith(options, '-march=')) compiler.compiler.supportsMarch = true;
+ if (this.hasSupportStartsWith(options, '--target=')) compiler.compiler.supportsTargetIs = true;
+ if (this.hasSupportStartsWith(options, '--target ')) compiler.compiler.supportsTarget = true;
}
static override async parse(compiler) {
const results = await Promise.all([
- GCCParser.getOptions(compiler, '-fsyntax-only --help'),
- GCCParser.getOptions(compiler, '-fsyntax-only --target-help'),
- GCCParser.getOptions(compiler, '-fsyntax-only --help=common'),
- GCCParser.getOptions(compiler, '-fsyntax-only --help=warnings'),
- GCCParser.getOptions(compiler, '-fsyntax-only --help=optimizers'),
+ this.getOptions(compiler, '-fsyntax-only --help'),
+ this.getOptions(compiler, '-fsyntax-only --target-help'),
+ this.getOptions(compiler, '-fsyntax-only --help=common'),
+ this.getOptions(compiler, '-fsyntax-only --help=warnings'),
+ this.getOptions(compiler, '-fsyntax-only --help=optimizers'),
+ this.getOptions(compiler, '-fsyntax-only --help=target'),
]);
const options = Object.assign({}, ...results);
await this.setCompilerSettingsFromOptions(compiler, options);
return compiler;
}
+ static override async getPossibleTargets(compiler): Promise<string[]> {
+ const re = /Known valid arguments for -march= option:\s+(.*)/;
+ const result = await compiler.execCompilerCached(compiler.compiler.exe, ['-fsyntax-only', '--target-help']);
+ const match = result.stdout.match(re);
+ if (match) {
+ return match[1].split(' ');
+ } else {
+ return [];
+ }
+ }
+
+ static getLanguageSpecificHelpFlags(): string[] {
+ return ['-fsyntax-only', '--help=c++'];
+ }
+
+ static override async getPossibleStdvers(compiler): Promise<CompilerOverrideOptions> {
+ const possible: CompilerOverrideOptions = [];
+ const options = await this.getOptionsStrict(compiler, this.getLanguageSpecificHelpFlags());
+ for (const opt in options) {
+ if (opt.startsWith('-std=') && !options[opt].description?.startsWith('Deprecated')) {
+ const stdver = opt.substring(5);
+ possible.push({
+ name: stdver + ': ' + options[opt].description,
+ value: stdver,
+ });
+ }
+ }
+ return possible;
+ }
+
static override async getOptions(compiler, helpArg) {
- const optionFinder = /^\s*(--?[\d+,<=>[\]a-z|-]*)\s*(.*)/i;
+ const optionFinder1 = /^ *(--?[#\d+,<=>[\]a-z|-]* ?[\d+,<=>[\]a-z|-]*) +(.*)/i;
+ const optionFinder2 = /^ *(--?[#\d+,<=>[\]a-z|-]* ?[\d+,<=>[\]a-z|-]*)/i;
const result = await compiler.execCompilerCached(compiler.compiler.exe, helpArg.split(' '));
- const options = result.code === 0 ? BaseParser.parseLines(result.stdout + result.stderr, optionFinder) : {};
+ const options =
+ result.code === 0 ? this.parseLines(result.stdout + result.stderr, optionFinder1, optionFinder2) : {};
compiler.possibleArguments.populateOptions(options);
return options;
}
+
+ static async getOptionsStrict(compiler, helpArgs: string[]) {
+ const optionFinder = /^ {2}(--?[\d+,<=>[\]a-z|-]*) *(.*)/i;
+ const result = await compiler.execCompilerCached(compiler.compiler.exe, helpArgs);
+ return result.code === 0 ? this.parseLines(result.stdout + result.stderr, optionFinder) : {};
+ }
}
export class ClangParser extends BaseParser {
static mllvmOptions = new Set<string>();
- static setCompilerSettingsFromOptions(compiler, options) {
- logger.debug(`clang-like compiler options: ${_.keys(options).join(' ')}`);
- if (BaseParser.hasSupport(options, '-fsave-optimization-record')) {
+ static override setCompilerSettingsFromOptions(compiler, options) {
+ const keys = _.keys(options);
+ logger.debug(`clang-like compiler options: ${keys.join(' ')}`);
+
+ if (keys.length === 0) {
+ logger.error(`compiler options appear empty for ${compiler.compiler.id}`);
+ }
+
+ if (this.hasSupport(options, '-fsave-optimization-record')) {
compiler.compiler.optArg = '-fsave-optimization-record';
compiler.compiler.supportsOptOutput = true;
}
- if (BaseParser.hasSupport(options, '-emit-llvm')) {
+ if (this.hasSupport(options, '-fstack-usage')) {
+ compiler.compiler.stackUsageArg = '-fstack-usage';
+ compiler.compiler.supportsStackUsageOutput = true;
+ }
+
+ if (this.hasSupport(options, '-emit-llvm')) {
compiler.compiler.supportsIrView = true;
compiler.compiler.irArg = ['-Xclang', '-emit-llvm', '-fsyntax-only'];
+ compiler.compiler.minIrArgs = ['-emit-llvm'];
}
if (
- BaseParser.hasSupport(options, '-mllvm') &&
+ this.hasSupport(options, '-mllvm') &&
this.mllvmOptions.has('--print-before-all') &&
this.mllvmOptions.has('--print-after-all')
) {
@@ -161,76 +282,239 @@ export class ClangParser extends BaseParser {
if (this.mllvmOptions.has('--print-module-scope')) {
compiler.compiler.llvmOptModuleScopeArg = ['-mllvm', '-print-module-scope'];
}
- if (BaseParser.hasSupport(options, '-fno-discard-value-names')) {
+ if (this.hasSupport(options, '-fno-discard-value-names')) {
compiler.compiler.llvmOptNoDiscardValueNamesArg = ['-fno-discard-value-names'];
}
}
- if (BaseParser.hasSupport(options, '-fcolor-diagnostics')) compiler.compiler.options += ' -fcolor-diagnostics';
- if (BaseParser.hasSupport(options, '-fno-crash-diagnostics'))
- compiler.compiler.options += ' -fno-crash-diagnostics';
+ if (this.hasSupport(options, '-fcolor-diagnostics')) compiler.compiler.options += ' -fcolor-diagnostics';
+ if (this.hasSupport(options, '-fno-crash-diagnostics')) compiler.compiler.options += ' -fno-crash-diagnostics';
+
+ if (this.hasSupportStartsWith(options, '--target=')) compiler.compiler.supportsTargetIs = true;
+ if (this.hasSupportStartsWith(options, '--target ')) compiler.compiler.supportsTarget = true;
+ }
+
+ static getMainHelpOptions(): string[] {
+ return ['--help'];
+ }
+
+ static getHiddenHelpOptions(exampleFile: string): string[] {
+ return ['-mllvm', '--help-list-hidden', exampleFile, '-c'];
+ }
+
+ static getStdVersHelpOptions(exampleFile: string): string[] {
+ return ['-std=c++9999999', exampleFile, '-c'];
+ }
+
+ static getTargetsHelpOptions(): string[] {
+ return ['--print-targets'];
}
static override async parse(compiler) {
try {
- const options = await ClangParser.getOptions(compiler, '--help');
+ const options = await this.getOptions(compiler, this.getMainHelpOptions().join(' '));
- const EXAMPLES_PATH = props.get('builtin', 'sourcePath', './examples/');
- let filename = path.join(EXAMPLES_PATH, 'c++/default.cpp');
- if (!path.isAbsolute(filename)) filename = path.join(process.cwd(), filename);
+ const filename = this.getExampleFilepath();
this.mllvmOptions = new Set(
- _.keys(await ClangParser.getOptions(compiler, `-mllvm --help-list-hidden ${filename} -c`, false)),
+ _.keys(await this.getOptions(compiler, this.getHiddenHelpOptions(filename).join(' '), false, true)),
);
this.setCompilerSettingsFromOptions(compiler, options);
return compiler;
} catch (error) {
- logger.error('Error while trying to generate llvm backend arguments');
- logger.debug(error);
+ logger.error(`Error while trying to generate llvm backend arguments for ${compiler.compiler.id}: ${error}`);
+ return null;
}
}
- static override async getOptions(compiler, helpArg, populate = true) {
- const optionFinder = /^\s*(--?[\d+,<=>[\]a-z|-]*)\s*(.*)/i;
- const result = await compiler.execCompilerCached(compiler.compiler.exe, helpArg.split(' '));
- const options = result.code === 0 ? BaseParser.parseLines(result.stdout + result.stderr, optionFinder) : {};
- if (populate) {
- compiler.possibleArguments.populateOptions(options);
+ static getRegexMatchesAsStdver(match, maxToMatch): CompilerOverrideOptions {
+ if (!match) return [];
+ if (!match[maxToMatch]) return [];
+
+ const arr: CompilerOverrideOptions = [];
+
+ for (let i = 1; i < maxToMatch; i++) {
+ if (!match[i]) return [];
+
+ arr.push({
+ name: match[i] + ': ' + match[maxToMatch],
+ value: match[i],
+ });
+ }
+
+ return arr;
+ }
+
+ static extractPossibleStdvers(lines: string[]): CompilerOverrideOptions {
+ const possible: CompilerOverrideOptions = [];
+ const re1 = /note: use '([\w\d+:]*)' for '(.*)' standard/;
+ const re2 = /note: use '([\w\d+:]*)' or '([\w\d+:]*)' for '(.*)' standard/;
+ const re3 = /note: use '([\w\d+:]*)', '([\w\d+:]*)', or '([\w\d+:]*)' for '(.*)' standard/;
+ const re4 = /note: use '([\w\d+:]*)', '([\w\d+:]*)', '([\w\d+:]*)', or '([\w\d+:]*)' for '(.*)' standard/;
+ for (const line of lines) {
+ let match = line.match(re1);
+ let stdvers = this.getRegexMatchesAsStdver(match, 2);
+ possible.push(...stdvers);
+ if (stdvers.length > 0) continue;
+
+ match = line.match(re2);
+ stdvers = this.getRegexMatchesAsStdver(match, 3);
+ possible.push(...stdvers);
+ if (stdvers.length > 0) continue;
+
+ match = line.match(re3);
+ stdvers = this.getRegexMatchesAsStdver(match, 4);
+ possible.push(...stdvers);
+ if (stdvers.length > 0) continue;
+
+ match = line.match(re4);
+ stdvers = this.getRegexMatchesAsStdver(match, 5);
+ possible.push(...stdvers);
}
+ return possible;
+ }
+
+ static override async getPossibleStdvers(compiler): Promise<CompilerOverrideOptions> {
+ let possible: CompilerOverrideOptions = [];
+
+ // clang doesn't have a --help option to get the std versions, we'll have to compile with a fictional stdversion to coax a response
+ const filename = this.getExampleFilepath();
+
+ const result = await compiler.execCompilerCached(compiler.compiler.exe, this.getStdVersHelpOptions(filename), {
+ ...compiler.getDefaultExecOptions(),
+ createAndUseTempDir: true,
+ });
+ if (result.stderr) {
+ const lines = utils.splitLines(result.stderr);
+
+ possible = this.extractPossibleStdvers(lines);
+ possible.sort((a, b) => {
+ return a.value === b.value ? 0 : a.value > b.value ? 1 : -1;
+ });
+ }
+
+ return possible;
+ }
+
+ static extractPossibleTargets(lines: string[]): string[] {
+ const re = /\s+([\w-]*)\s*-\s.*/;
+ return lines
+ .map(line => {
+ const match = line.match(re);
+ if (match) {
+ return match[1];
+ } else {
+ return false;
+ }
+ })
+ .filter(Boolean) as string[];
+ }
+
+ static override async getPossibleTargets(compiler): Promise<string[]> {
+ const result = await compiler.execCompilerCached(compiler.compiler.exe, this.getTargetsHelpOptions());
+ return this.extractPossibleTargets(utils.splitLines(result.stdout));
+ }
+
+ static override async getOptions(compiler, helpArg, populate = true, isolate = false) {
+ const optionFinderWithDesc = /^ {2}?(--?[#\d+,<=>[\]a-zA-Z|-]*\s?[\d+,<=>[\]a-zA-Z|-]*)\s+([A-Z].*)/;
+ const optionFinderWithoutDesc = /^ {2}?(--?[#\d+,<=>[\]a-z|-]*\s?[\d+,<=>[\]a-z|-]*)/i;
+ const execOptions = isolate ?? {...compiler.getDefaultExecOptions(), createAndUseTempDir: true};
+ const result = await compiler.execCompilerCached(compiler.compiler.exe, helpArg.split(' '), execOptions);
+ const options =
+ result.code === 0
+ ? this.parseLines(result.stdout + result.stderr, optionFinderWithDesc, optionFinderWithoutDesc)
+ : {};
+ if (populate) compiler.possibleArguments.populateOptions(options);
return options;
}
}
+export class GCCCParser extends GCCParser {
+ static override getLanguageSpecificHelpFlags(): string[] {
+ return ['-fsyntax-only', '--help=c'];
+ }
+
+ static override getDefaultExampleFilename() {
+ return 'c/default.c';
+ }
+}
+
+export class ClangCParser extends ClangParser {
+ static override getDefaultExampleFilename() {
+ return 'c/default.c';
+ }
+
+ static override getStdVersHelpOptions(exampleFile: string): string[] {
+ return ['-std=c9999999', exampleFile, '-c'];
+ }
+}
+
+export class CircleParser extends ClangParser {
+ static override async getOptions(compiler, helpArg) {
+ const optionFinder1 = /^ +(--?[#\d,<=>[\]a-z|_.-]*) +- (.*)/i;
+ const optionFinder2 = /^ +(--?[#\d,<=>[\]a-z|_.-]*)/i;
+ const result = await compiler.execCompilerCached(compiler.compiler.exe, helpArg.split(' '));
+ const options = result.code === 0 ? this.parseLines(result.stdout, optionFinder1, optionFinder2) : {};
+ compiler.possibleArguments.populateOptions(options);
+ return options;
+ }
+
+ static override async getPossibleStdvers(compiler): Promise<CompilerOverrideOptions> {
+ const possible: CompilerOverrideOptions = [];
+ const optionFinder = /^ {4}=([\w+]*) +- +(.*)/i;
+ const result = await compiler.execCompilerCached(compiler.compiler.exe, ['--help']);
+ let isInStdVerSection = false;
+ for (const line of utils.splitLines(result.stdout)) {
+ if (!isInStdVerSection && line.startsWith(' --std=')) {
+ isInStdVerSection = true;
+ continue;
+ } else if (isInStdVerSection && line.startsWith(' --')) {
+ break;
+ }
+
+ if (!isInStdVerSection) continue;
+
+ const match = line.match(optionFinder);
+ if (match) {
+ const stdver = match[1];
+ const desc = match[2];
+ possible.push({
+ name: stdver + ': ' + desc,
+ value: stdver,
+ });
+ }
+ }
+ return possible;
+ }
+}
+
export class LDCParser extends BaseParser {
- static setCompilerSettingsFromOptions(compiler, options) {
- if (BaseParser.hasSupport(options, '--fsave-optimization-record')) {
+ static override setCompilerSettingsFromOptions(compiler, options) {
+ if (this.hasSupport(options, '--fsave-optimization-record')) {
compiler.compiler.optArg = '--fsave-optimization-record';
compiler.compiler.supportsOptOutput = true;
}
- if (
- BaseParser.hasSupport(options, '--print-before-all') &&
- BaseParser.hasSupport(options, '--print-after-all')
- ) {
+ if (this.hasSupport(options, '--print-before-all') && this.hasSupport(options, '--print-after-all')) {
compiler.compiler.supportsLLVMOptPipelineView = true;
compiler.compiler.llvmOptArg = ['--print-before-all', '--print-after-all'];
compiler.compiler.llvmOptModuleScopeArg = [];
compiler.compiler.llvmOptNoDiscardValueNamesArg = [];
- if (BaseParser.hasSupport(options, '--print-module-scope')) {
+ if (this.hasSupport(options, '--print-module-scope')) {
compiler.compiler.llvmOptModuleScopeArg = ['--print-module-scope'];
}
- if (BaseParser.hasSupport(options, '--fno-discard-value-names')) {
+ if (this.hasSupport(options, '--fno-discard-value-names')) {
compiler.compiler.llvmOptNoDiscardValueNamesArg = ['--fno-discard-value-names'];
}
}
- if (BaseParser.hasSupport(options, '--enable-color')) {
+ if (this.hasSupport(options, '--enable-color')) {
compiler.compiler.options += ' --enable-color';
}
}
static override async parse(compiler) {
- const options = await LDCParser.getOptions(compiler, '--help-hidden');
+ const options = await this.getOptions(compiler, '--help-hidden');
this.setCompilerSettingsFromOptions(compiler, options);
return compiler;
}
@@ -238,7 +522,7 @@ export class LDCParser extends BaseParser {
static override async getOptions(compiler, helpArg, populate = true) {
const optionFinder = /^\s*(--?[\d+,<=>[\]a-z|-]*)\s*(.*)/i;
const result = await compiler.execCompilerCached(compiler.compiler.exe, helpArg.split(' '));
- const options = result.code === 0 ? BaseParser.parseLines(result.stdout + result.stderr, optionFinder) : {};
+ const options = result.code === 0 ? this.parseLines(result.stdout + result.stderr, optionFinder) : {};
if (populate) {
compiler.possibleArguments.populateOptions(options);
}
@@ -248,28 +532,96 @@ export class LDCParser extends BaseParser {
export class ErlangParser extends BaseParser {
static override async parse(compiler) {
- await ErlangParser.getOptions(compiler, '-help');
+ await this.getOptions(compiler, '-help');
return compiler;
}
}
export class PascalParser extends BaseParser {
static override async parse(compiler) {
- await PascalParser.getOptions(compiler, '-help');
+ await this.getOptions(compiler, '-help');
+ return compiler;
+ }
+}
+
+export class ICCParser extends GCCParser {
+ static override async setCompilerSettingsFromOptions(compiler, options) {
+ const keys = _.keys(options);
+ if (this.hasSupport(options, '-masm=')) {
+ compiler.compiler.intelAsm = '-masm=intel';
+ compiler.compiler.supportsIntel = true;
+ }
+ if (this.hasSupport(options, '-fdiagnostics-color')) {
+ if (compiler.compiler.options) compiler.compiler.options += ' ';
+ compiler.compiler.options += '-fdiagnostics-color=always';
+ }
+ if (_.find(keys, key => key.startsWith('-fdump-'))) {
+ compiler.compiler.supportsGccDump = true;
+ compiler.compiler.removeEmptyGccDump = true;
+ }
+ if (this.hasSupportStartsWith(options, '-march=')) compiler.compiler.supportsMarch = true;
+ if (this.hasSupportStartsWith(options, '--target=')) compiler.compiler.supportsTargetIs = true;
+ if (this.hasSupportStartsWith(options, '--target ')) compiler.compiler.supportsTarget = true;
+ }
+
+ static extractPossibleStdvers(lines: string[]): CompilerOverrideOptions {
+ const stdverRe = /-std=<std>/;
+ const descRe = /^\s{12}([\w\d+]*)\s+(.*)/;
+ const possible: CompilerOverrideOptions = [];
+ let foundStdver = false;
+ let skipLine = false;
+ for (const line of lines) {
+ if (skipLine) {
+ skipLine = false;
+ continue;
+ }
+
+ if (!foundStdver) {
+ const match = line.match(stdverRe);
+ if (match) {
+ foundStdver = true;
+ skipLine = true;
+ }
+ } else {
+ const descMatch = line.match(descRe);
+ if (descMatch) {
+ possible.push({
+ name: descMatch[1] + ': ' + descMatch[2],
+ value: descMatch[1],
+ });
+ } else {
+ break;
+ }
+ }
+ }
+ return possible;
+ }
+
+ static override async getPossibleStdvers(compiler): Promise<CompilerOverrideOptions> {
+ const result = await compiler.execCompilerCached(compiler.compiler.exe, ['--help']);
+ const lines = utils.splitLines(result.stdout);
+
+ return this.extractPossibleStdvers(lines);
+ }
+
+ static override async parse(compiler) {
+ const results = await Promise.all([this.getOptions(compiler, '-fsyntax-only --help')]);
+ const options = Object.assign({}, ...results);
+ await this.setCompilerSettingsFromOptions(compiler, options);
return compiler;
}
}
export class ISPCParser extends BaseParser {
- static async setCompilerSettingsFromOptions(compiler, options) {
- if (BaseParser.hasSupport(options, '--x86-asm-syntax')) {
+ static override async setCompilerSettingsFromOptions(compiler, options) {
+ if (this.hasSupport(options, '--x86-asm-syntax')) {
compiler.compiler.intelAsm = '--x86-asm-syntax=intel';
compiler.compiler.supportsIntel = true;
}
}
static override async parse(compiler) {
- const options = await ISPCParser.getOptions(compiler, '--help');
+ const options = await this.getOptions(compiler, '--help');
await this.setCompilerSettingsFromOptions(compiler, options);
return compiler;
}
@@ -277,7 +629,7 @@ export class ISPCParser extends BaseParser {
static override async getOptions(compiler, helpArg) {
const result = await compiler.execCompilerCached(compiler.compiler.exe, [helpArg]);
const optionFinder = /^\s*\[(--?[\d\s()+,/<=>a-z{|}-]*)]\s*(.*)/i;
- const options = result.code === 0 ? BaseParser.parseLines(result.stdout + result.stderr, optionFinder) : {};
+ const options = result.code === 0 ? this.parseLines(result.stdout + result.stderr, optionFinder) : {};
compiler.possibleArguments.populateOptions(options);
return options;
}
@@ -285,28 +637,28 @@ export class ISPCParser extends BaseParser {
export class JavaParser extends BaseParser {
static override async parse(compiler) {
- await JavaParser.getOptions(compiler, '-help');
+ await this.getOptions(compiler, '-help');
return compiler;
}
}
export class KotlinParser extends BaseParser {
static override async parse(compiler) {
- await KotlinParser.getOptions(compiler, '-help');
+ await this.getOptions(compiler, '-help');
return compiler;
}
}
export class ScalaParser extends BaseParser {
static override async parse(compiler) {
- await ScalaParser.getOptions(compiler, '-help');
+ await this.getOptions(compiler, '-help');
return compiler;
}
}
export class VCParser extends BaseParser {
static override async parse(compiler) {
- await VCParser.getOptions(compiler, '/help');
+ await this.getOptions(compiler, '/help');
return compiler;
}
@@ -364,6 +716,43 @@ export class VCParser extends BaseParser {
return options;
}
+ static extractPossibleStdvers(lines: string[]): CompilerOverrideOptions {
+ const stdverRe = /\/std:<(.*)>\s.*/;
+ const descRe = /(c\+\+.*) - (.*)/;
+ const possible: CompilerOverrideOptions = [];
+ const stdverValues: string[] = [];
+ for (const line of lines) {
+ if (stdverValues.length === 0) {
+ const match = line.match(stdverRe);
+ if (match) {
+ stdverValues.push(...match[1].split('|'));
+ }
+ } else {
+ const descMatch = line.match(descRe);
+ if (descMatch) {
+ if (stdverValues.includes(descMatch[1])) {
+ possible.push({
+ name: descMatch[1] + ': ' + descMatch[2],
+ value: descMatch[1],
+ });
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ return possible;
+ }
+
+ static override async getPossibleStdvers(compiler): Promise<CompilerOverrideOptions> {
+ const result = await compiler.execCompilerCached(compiler.compiler.exe, ['/help']);
+ const lines = utils.splitLines(result.stdout);
+
+ return this.extractPossibleStdvers(lines);
+ }
+
static override async getOptions(compiler, helpArg) {
const result = await compiler.execCompilerCached(compiler.compiler.exe, [helpArg]);
const optionFinder = /^\s*(\/[\w#+,.:<=>[\]{|}-]*)\s*(.*)/i;
@@ -374,24 +763,94 @@ export class VCParser extends BaseParser {
}
export class RustParser extends BaseParser {
- static async setCompilerSettingsFromOptions(compiler, options) {
- if (BaseParser.hasSupport(options, '--color')) {
+ static override async setCompilerSettingsFromOptions(compiler, options) {
+ if (this.hasSupport(options, '--color')) {
if (compiler.compiler.options) compiler.compiler.options += ' ';
compiler.compiler.options += '--color=always';
}
+ if (this.hasSupportStartsWith(options, '--target=')) compiler.compiler.supportsTargetIs = true;
+ if (this.hasSupportStartsWith(options, '--target ')) compiler.compiler.supportsTarget = true;
}
static override async parse(compiler) {
const results = await Promise.all([
- RustParser.getOptions(compiler, '--help'),
- RustParser.getOptions(compiler, '-C help'),
- RustParser.getOptions(compiler, '--help -v'),
+ this.getOptions(compiler, '--help'),
+ this.getOptions(compiler, '-C help'),
+ this.getOptions(compiler, '--help -v'),
]);
const options = Object.assign({}, ...results);
await this.setCompilerSettingsFromOptions(compiler, options);
return compiler;
}
+ static override async getPossibleEditions(compiler): Promise<string[]> {
+ const result = await compiler.execCompilerCached(compiler.compiler.exe, ['--help']);
+ const re = /--edition ([\d|]*)/;
+
+ const match = result.stdout.match(re);
+ if (match && match[1]) {
+ return match[1].split('|');
+ }
+
+ return [];
+ }
+
+ static override async getPossibleTargets(compiler): Promise<string[]> {
+ const result = await compiler.execCompilerCached(compiler.compiler.exe, ['--print', 'target-list']);
+ return utils.splitLines(result.stdout).filter(Boolean);
+ }
+
+ static parseRustHelpLines(stdout) {
+ let previousOption: false | string = false;
+ const options = {};
+
+ const doubleOptionFinder = /^\s{4}(-\w, --\w*\s?[\w[\]:=]*)\s*(.*)/i;
+ const singleOptionFinder = /^\s{8}(--[\w-]*\s?[\w[\]:=|-]*)\s*(.*)/i;
+ const singleComplexOptionFinder = /^\s{4}(-\w*\s?[\w[\]:=]*)\s*(.*)/i;
+
+ utils.eachLine(stdout, line => {
+ let description = '';
+
+ const match1 = line.match(doubleOptionFinder);
+ const match2 = line.match(singleOptionFinder);
+ const match3 = line.match(singleComplexOptionFinder);
+ if (!match1 && !match2 && !match3) {
+ if (previousOption && line.trim().length > 0) {
+ if (options[previousOption].description.endsWith('-'))
+ options[previousOption].description += line.trim();
+ else {
+ if (options[previousOption].description.length > 0)
+ options[previousOption].description += ' ' + line.trim();
+ else options[previousOption].description = line.trim();
+ }
+ } else {
+ previousOption = false;
+ }
+ return;
+ } else {
+ if (match1) {
+ previousOption = match1[1].trim();
+ if (match1[2]) description = match1[2].trim();
+ } else if (match2) {
+ previousOption = match2[1].trim();
+ if (match2[2]) description = match2[2].trim();
+ } else if (match3) {
+ previousOption = match3[1].trim();
+ if (match3[2]) description = match3[2].trim();
+ }
+ }
+
+ if (previousOption) {
+ options[previousOption] = {
+ description: description,
+ timesused: 0,
+ };
+ }
+ });
+
+ return options;
+ }
+
static override async getOptions(compiler, helpArg) {
const result = await compiler.execCompilerCached(compiler.compiler.exe, helpArg.split(' '));
let options = {};
@@ -399,11 +858,9 @@ export class RustParser extends BaseParser {
if (helpArg === '-C help') {
const optionFinder = /^\s*(-c\s*[\d=a-z-]*)\s--\s(.*)/i;
- options = BaseParser.parseLines(result.stdout + result.stderr, optionFinder);
+ options = this.parseLines(result.stdout + result.stderr, optionFinder);
} else {
- const optionFinder = /^\s*(--?[\d+,<=>[\]a-z|-]*)\s*(.*)/i;
-
- options = BaseParser.parseLines(result.stdout + result.stderr, optionFinder);
+ options = this.parseRustHelpLines(result.stdout + result.stderr);
}
}
compiler.possibleArguments.populateOptions(options);
@@ -413,42 +870,42 @@ export class RustParser extends BaseParser {
export class MrustcParser extends BaseParser {
static override async parse(compiler) {
- await MrustcParser.getOptions(compiler, '--help');
+ await this.getOptions(compiler, '--help');
return compiler;
}
}
export class NimParser extends BaseParser {
static override async parse(compiler) {
- await NimParser.getOptions(compiler, '-help');
+ await this.getOptions(compiler, '-help');
return compiler;
}
}
export class CrystalParser extends BaseParser {
static override async parse(compiler) {
- await CrystalParser.getOptions(compiler, 'build');
+ await this.getOptions(compiler, 'build');
return compiler;
}
}
export class TypeScriptNativeParser extends BaseParser {
static override async parse(compiler) {
- await TypeScriptNativeParser.getOptions(compiler, '--help');
+ await this.getOptions(compiler, '--help');
return compiler;
}
}
export class TurboCParser extends BaseParser {
static override async parse(compiler) {
- await TurboCParser.getOptions(compiler, '');
+ await this.getOptions(compiler, '');
return compiler;
}
}
export class ToitParser extends BaseParser {
static override async parse(compiler) {
- await ToitParser.getOptions(compiler, '-help');
+ await this.getOptions(compiler, '-help');
return compiler;
}
}
@@ -461,13 +918,171 @@ export class JuliaParser extends BaseParser {
compiler.compilerWrapperPath,
helpArg,
]);
- const options = result.code === 0 ? BaseParser.parseLines(result.stdout + result.stderr, optionFinder) : {};
+ const options = result.code === 0 ? this.parseLines(result.stdout + result.stderr, optionFinder) : {};
compiler.possibleArguments.populateOptions(options);
return options;
}
static override async parse(compiler) {
- await JuliaParser.getOptions(compiler, '--help');
+ await this.getOptions(compiler, '--help');
return compiler;
}
}
+
+export class Z88dkParser extends BaseParser {
+ static override async getPossibleTargets(compiler): Promise<string[]> {
+ const configPath = path.join(path.dirname(compiler.compiler.exe), '../share/z88dk/lib/config');
+ const targets: string[] = [];
+ const dir = await fs.readdir(configPath);
+ dir.forEach(filename => {
+ if (filename.toLowerCase().endsWith('.cfg')) {
+ targets.push(filename.substring(0, filename.length - 4));
+ }
+ });
+ return targets;
+ }
+}
+
+export class ZigCxxParser extends ClangParser {
+ static override getMainHelpOptions(): string[] {
+ return ['c++', '--help'];
+ }
+
+ static override getHiddenHelpOptions(exampleFile: string): string[] {
+ return ['c++', '-mllvm', '--help-list-hidden', exampleFile, '-S', '-o', '/tmp/output.s'];
+ }
+
+ static override getStdVersHelpOptions(exampleFile: string): string[] {
+ return ['c++', '-std=c++9999999', exampleFile, '-S', '-o', '/tmp/output.s'];
+ }
+
+ static override getTargetsHelpOptions(): string[] {
+ return ['c++', '--print-targets'];
+ }
+}
+
+export class GccFortranParser extends GCCParser {
+ static override getDefaultExampleFilename() {
+ return 'fortran/default.f90';
+ }
+
+ static override getLanguageSpecificHelpFlags(): string[] {
+ return ['-fsyntax-only', '--help=fortran'];
+ }
+}
+
+export class FlangParser extends ClangParser {
+ static override getDefaultExampleFilename() {
+ return 'fortran/default.f90';
+ }
+
+ static override hasSupport(options, param) {
+ // param is available but we get a warning, so lets not use it
+ if (param === '-fcolor-diagnostics') return undefined;
+
+ return BaseParser.hasSupport(options, param);
+ }
+
+ static override extractPossibleStdvers(lines: string[]): CompilerOverrideOptions {
+ const possible: CompilerOverrideOptions = [];
+ const re1 = /error: Only -std=([\w\d+]*) is allowed currently./;
+ for (const line of lines) {
+ const match = line.match(re1);
+ if (match && match[1]) {
+ possible.push({
+ name: match[1],
+ value: match[1],
+ });
+ }
+ }
+ return possible;
+ }
+}
+
+export class GHCParser extends GCCParser {
+ static override async parse(compiler) {
+ const results = await Promise.all([this.getOptions(compiler, '--help')]);
+ const options = Object.assign({}, ...results);
+ await this.setCompilerSettingsFromOptions(compiler, options);
+ return compiler;
+ }
+
+ static override async getOptions(compiler, helpArg) {
+ const optionFinder1 = /^ {4}(-[\w[\]]+)\s+(.*)/i;
+ const optionFinder2 = /^ {4}(-[\w[\]]+)/;
+ const result = await compiler.execCompilerCached(compiler.compiler.exe, helpArg.split(' '));
+ const options = result.code === 0 ? this.parseLines(result.stdout, optionFinder1, optionFinder2) : {};
+
+ compiler.possibleArguments.populateOptions(options);
+ return options;
+ }
+}
+
+export class SwiftParser extends ClangParser {
+ static override async parse(compiler) {
+ const results = await Promise.all([this.getOptions(compiler, '--help')]);
+ const options = Object.assign({}, ...results);
+ this.setCompilerSettingsFromOptions(compiler, options);
+ return compiler;
+ }
+
+ static override async getPossibleStdvers(compiler): Promise<CompilerOverrideOptions> {
+ return [];
+ }
+
+ static override async getPossibleTargets(compiler): Promise<string[]> {
+ return [];
+ }
+}
+
+export class TendraParser extends GCCParser {
+ static override async parse(compiler) {
+ const results = await Promise.all([this.getOptions(compiler, '--help')]);
+ const options = Object.assign({}, ...results);
+ await this.setCompilerSettingsFromOptions(compiler, options);
+ return compiler;
+ }
+
+ static override async getOptions(compiler, helpArg) {
+ const optionFinder = /^ *(-[#\d+,<=>[\]a-z|-]* ?[\d+,<=>[\]a-z|-]*) : +(.*)/i;
+ const result = await compiler.execCompilerCached(compiler.compiler.exe, helpArg.split(' '));
+ const options = this.parseLines(result.stdout + result.stderr, optionFinder);
+ compiler.possibleArguments.populateOptions(options);
+ return options;
+ }
+
+ static override async getPossibleStdvers(compiler): Promise<CompilerOverrideOptions> {
+ return [];
+ }
+
+ static override async getPossibleTargets(compiler): Promise<string[]> {
+ return [];
+ }
+}
+
+export class GolangParser extends GCCParser {
+ static override getDefaultExampleFilename() {
+ return 'go/default.go';
+ }
+
+ static override async parse(compiler) {
+ const results = await Promise.all([
+ this.getOptions(compiler, 'build -o ./output.s "-gcflags=-S --help" ' + this.getExampleFilepath()),
+ ]);
+ const options = Object.assign({}, ...results);
+ await this.setCompilerSettingsFromOptions(compiler, options);
+ return compiler;
+ }
+
+ static override async getOptions(compiler, helpArg) {
+ const optionFinder1 = /^\s*(--?[#\d+,<=>[\]a-z|-]* ?[\d+,<=>[\]a-z|-]*)\s+(.*)/i;
+ const optionFinder2 = /^\s*(--?[#\d+,<=>[\]a-z|-]* ?[\d+,<=>[\]a-z|-]*)/i;
+ const result = await compiler.execCompilerCached(compiler.compiler.exe, utils.splitArguments(helpArg), {
+ ...compiler.getDefaultExecOptions(),
+ createAndUseTempDir: true,
+ });
+ const options = this.parseLines(result.stdout + result.stderr, optionFinder1, optionFinder2);
+ compiler.possibleArguments.populateOptions(options);
+ return options;
+ }
+}
diff --git a/lib/compilers/assembly.ts b/lib/compilers/assembly.ts
index 7b64dd5bd..ff08ffee3 100644
--- a/lib/compilers/assembly.ts
+++ b/lib/compilers/assembly.ts
@@ -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,
),
);
diff --git a/lib/compilers/avrgcc6502.ts b/lib/compilers/avrgcc6502.ts
index 653cf2314..c293e69c9 100644
--- a/lib/compilers/avrgcc6502.ts
+++ b/lib/compilers/avrgcc6502.ts
@@ -70,7 +70,7 @@ export class AvrGcc6502Compiler extends BaseCompiler {
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
) {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
diff --git a/lib/compilers/beebasm.ts b/lib/compilers/beebasm.ts
index 60ee212be..e4b425476 100644
--- a/lib/compilers/beebasm.ts
+++ b/lib/compilers/beebasm.ts
@@ -56,7 +56,7 @@ export class BeebAsmCompiler extends BaseCompiler {
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
) {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
diff --git a/lib/compilers/c3c.ts b/lib/compilers/c3c.ts
new file mode 100644
index 000000000..a812583ae
--- /dev/null
+++ b/lib/compilers/c3c.ts
@@ -0,0 +1,33 @@
+import path from 'path';
+import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
+import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
+import {BaseCompiler} from '../base-compiler.js';
+
+export class C3Compiler extends BaseCompiler {
+ static get key() {
+ return 'c3c';
+ }
+
+ constructor(info: PreliminaryCompilerInfo, env) {
+ super(info, env);
+ this.compiler.supportsIrView = true;
+ this.compiler.irArg = ['--emit-llvm'];
+ }
+
+ override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: string) {
+ return [
+ 'compile-only',
+ '-g',
+ '-l',
+ 'pthread',
+ '--no-strip-unused',
+ '--no-obj',
+ '--no-emit-stdlib',
+ '--emit-asm',
+ ];
+ }
+
+ override getIrOutputFilename(inputFilename: string): string {
+ return this.filename(path.dirname(inputFilename) + '/output.ll');
+ }
+}
diff --git a/lib/compilers/carbon.ts b/lib/compilers/carbon.ts
index deaa65a5c..f99e4c0d6 100644
--- a/lib/compilers/carbon.ts
+++ b/lib/compilers/carbon.ts
@@ -47,9 +47,9 @@ export class CarbonCompiler extends BaseCompiler {
return ['--color', `--trace_file=${outputFilename}`];
}
- override processAsm(result, filters, options): ParsedAsmResult {
+ override async processAsm(result, filters, options): Promise<ParsedAsmResult> {
// Really should write a custom parser, but for now just don't filter anything.
- return super.processAsm(
+ return await super.processAsm(
result,
{
labels: false,
@@ -63,6 +63,7 @@ export class CarbonCompiler extends BaseCompiler {
intel: false,
libraryCode: false,
trim: false,
+ debugCalls: false,
},
options,
);
@@ -95,6 +96,7 @@ export class CarbonCompiler extends BaseCompiler {
},
};
result.stdout = [];
+ result.languageId = 'no-highlight';
}
return result;
}
diff --git a/lib/compilers/cc65.ts b/lib/compilers/cc65.ts
index 1d35f7339..2042bad17 100644
--- a/lib/compilers/cc65.ts
+++ b/lib/compilers/cc65.ts
@@ -121,6 +121,19 @@ export class Cc65Compiler extends BaseCompiler {
await this.addArtifactToResult(res, nesFile, ArtifactType.nesrom);
}
+ if (result.compilationOptions?.includes('c64') && (await utils.fileExists(outputFilename))) {
+ if (!outputFilename.endsWith('.prg')) {
+ await this.addArtifactToResult(
+ res,
+ outputFilename,
+ ArtifactType.c64prg,
+ path.basename(outputFilename) + '.prg',
+ );
+ } else {
+ await this.addArtifactToResult(res, outputFilename, ArtifactType.c64prg);
+ }
+ }
+
return res;
}
diff --git a/lib/compilers/circle.ts b/lib/compilers/circle.ts
index 49d5dff38..5bf81259d 100644
--- a/lib/compilers/circle.ts
+++ b/lib/compilers/circle.ts
@@ -25,12 +25,18 @@
import path from 'path';
import {BaseCompiler} from '../base-compiler.js';
+import {CircleParser} from './argument-parsers.js';
+import {ExecutionOptions} from '../../types/compilation/compilation.interfaces.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) {
@@ -48,13 +54,18 @@ export class CircleCompiler extends BaseCompiler {
return path.join(dirPath, outputFilebase);
}
- override runCompiler(compiler, options, inputFilename, execOptions) {
+ override async runCompiler(
+ compiler,
+ options,
+ inputFilename,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
+ ) {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
}
execOptions.customCwd = path.dirname(inputFilename);
- return super.runCompiler(compiler, options, inputFilename, execOptions);
+ return await super.runCompiler(compiler, options, inputFilename, execOptions);
}
}
diff --git a/lib/compilers/circt.ts b/lib/compilers/circt.ts
index 0331db196..bd8110007 100644
--- a/lib/compilers/circt.ts
+++ b/lib/compilers/circt.ts
@@ -47,6 +47,7 @@ export class CIRCTCompiler extends BaseCompiler {
'directives',
'commentOnly',
'trim',
+ 'debugCalls',
],
...compilerInfo,
},
diff --git a/lib/compilers/clang.ts b/lib/compilers/clang.ts
index d161e0f98..a5534aa36 100644
--- a/lib/compilers/clang.ts
+++ b/lib/compilers/clang.ts
@@ -27,13 +27,16 @@ import path from 'path';
import _ from 'underscore';
-import type {ExecutionOptions} from '../../types/compilation/compilation.interfaces.js';
+import type {BypassCache, CompilationResult, ExecutionOptions} from '../../types/compilation/compilation.interfaces.js';
import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
import type {ExecutableExecutionOptions, UnprocessedExecResult} from '../../types/execution/execution.interfaces.js';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {BaseCompiler} from '../base-compiler.js';
import {AmdgpuAsmParser} from '../parsers/asm-parser-amdgpu.js';
import {SassAsmParser} from '../parsers/asm-parser-sass.js';
+import {HexagonAsmParser} from '../parsers/asm-parser-hexagon.js';
+import * as utils from '../utils.js';
+import {ArtifactType} from '../../types/tool.interfaces.js';
const offloadRegexp = /^#\s+__CLANG_OFFLOAD_BUNDLE__(__START__|__END__)\s+(.*)$/gm;
@@ -68,10 +71,37 @@ export class ClangCompiler extends BaseCompiler {
}
}
+ override isCfgCompiler() {
+ return true;
+ }
+
+ async addTimeTraceToResult(result: CompilationResult, dirPath: string, outputFilename: string) {
+ let timeTraceJson = '';
+ const outputExt = path.extname(outputFilename);
+ if (outputExt) {
+ timeTraceJson = outputFilename.replace(outputExt, '.json');
+ } else {
+ timeTraceJson += '.json';
+ }
+ const jsonFilepath = path.join(dirPath, timeTraceJson);
+ if (await utils.fileExists(jsonFilepath)) {
+ this.addArtifactToResult(
+ result,
+ jsonFilepath,
+ ArtifactType.timetrace,
+ 'Trace events JSON',
+ (buffer: Buffer) => {
+ return buffer.toString('utf-8').startsWith('{"traceEvents":[');
+ },
+ );
+ }
+ }
+
override runExecutable(executable, executeParameters: ExecutableExecutionOptions, homeDir) {
if (this.asanSymbolizerPath) {
executeParameters.env = {
ASAN_SYMBOLIZER_PATH: this.asanSymbolizerPath,
+ MSAN_SYMBOLIZER_PATH: this.asanSymbolizerPath,
...executeParameters.env,
};
}
@@ -88,20 +118,61 @@ export class ClangCompiler extends BaseCompiler {
return options;
}
- override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: string) {
+ override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: string, userOptions?: string[]) {
const options = super.optionsForFilter(filters, outputFilename);
return this.forceDwarf4UnlessOverridden(options);
}
- override runCompiler(compiler: string, options: string[], inputFilename: string, execOptions: ExecutionOptions) {
+ override async afterCompilation(
+ result,
+ doExecute,
+ key,
+ executeParameters,
+ tools,
+ backendOptions,
+ filters,
+ options,
+ optOutput,
+ stackUsageOutput,
+ bypassCache: BypassCache,
+ customBuildPath?,
+ ) {
+ const compilationInfo = this.getCompilationInfo(key, result, customBuildPath);
+
+ const dirPath = path.dirname(compilationInfo.outputFilename);
+ const filename = path.basename(compilationInfo.outputFilename);
+ await this.addTimeTraceToResult(result, dirPath, filename);
+
+ return super.afterCompilation(
+ result,
+ doExecute,
+ key,
+ executeParameters,
+ tools,
+ backendOptions,
+ filters,
+ options,
+ optOutput,
+ stackUsageOutput,
+ bypassCache,
+ customBuildPath,
+ );
+ }
+
+ override async runCompiler(
+ compiler: string,
+ options: string[],
+ inputFilename: string,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
+ ) {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
}
execOptions.customCwd = path.dirname(inputFilename);
- return super.runCompiler(compiler, options, inputFilename, execOptions);
+ return await super.runCompiler(compiler, options, inputFilename, execOptions);
}
async splitDeviceCode(assembly) {
@@ -200,7 +271,7 @@ export class ClangCudaCompiler extends ClangCompiler {
override async objdump(outputFilename, result, maxSize) {
// For nvdisasm.
- const args = [outputFilename, '-c', '-g', '-hex'];
+ const args = [...this.compiler.objdumperArgs, outputFilename, '-c', '-g', '-hex'];
const execOptions = {maxOutput: maxSize, customCwd: path.dirname(outputFilename)};
const objResult = await this.exec(this.compiler.objdumper, args, execOptions);
@@ -246,7 +317,7 @@ export class ClangIntelCompiler extends ClangCompiler {
}
}
- override getDefaultExecOptions(): ExecutionOptions {
+ override getDefaultExecOptions(): ExecutionOptions & {env: Record<string, string>} {
const opts = super.getDefaultExecOptions();
opts.env.PATH = process.env.PATH + path.delimiter + path.dirname(this.compiler.exe);
@@ -261,3 +332,39 @@ export class ClangIntelCompiler extends ClangCompiler {
return super.runExecutable(executable, executeParameters, homeDir);
}
}
+
+export class ClangHexagonCompiler extends ClangCompiler {
+ static override get key() {
+ return 'clang-hexagon';
+ }
+
+ constructor(info: PreliminaryCompilerInfo, env) {
+ super(info, env);
+
+ this.asm = new HexagonAsmParser();
+ }
+}
+
+export class ClangDxcCompiler extends ClangCompiler {
+ static override get key() {
+ return 'clang-dxc';
+ }
+
+ constructor(info: PreliminaryCompilerInfo, env) {
+ super(info, env);
+
+ this.compiler.supportsIntel = false;
+ this.compiler.irArg = ['-Xclang', '-emit-llvm'];
+ // dxc mode doesn't have -fsave-optimization-record or -fstack-usage
+ this.compiler.supportsOptOutput = false;
+ this.compiler.supportsStackUsageOutput = false;
+ }
+
+ override optionsForFilter(
+ filters: ParseFiltersAndOutputOptions,
+ outputFilename: string,
+ userOptions?: string[],
+ ): string[] {
+ return ['--driver-mode=dxc', '-Zi', '-Qembed_debug', '-Fc', this.filename(outputFilename)];
+ }
+}
diff --git a/lib/compilers/clangcl.ts b/lib/compilers/clangcl.ts
index 0d1866bc2..6b65a4f85 100644
--- a/lib/compilers/clangcl.ts
+++ b/lib/compilers/clangcl.ts
@@ -29,6 +29,7 @@ import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.in
import {Win32Compiler} from './win32.js';
import {unwrap} from '../assert.js';
+import {LLVMIrBackendOptions} from '../../types/compilation/ir.interfaces.js';
export class ClangCLCompiler extends Win32Compiler {
static override get key() {
@@ -40,11 +41,18 @@ export class ClangCLCompiler extends Win32Compiler {
this.compiler.supportsIrView = true;
this.compiler.irArg = ['-Xclang', '-emit-llvm'];
+ this.compiler.minIrArgs = ['-emit-llvm'];
this.compiler.supportsIntel = false;
this.compiler.includeFlag = '/clang:-isystem';
}
- override async generateIR(inputFilename: string, options: string[], filters: ParseFiltersAndOutputOptions) {
+ override async generateIR(
+ inputFilename: string,
+ options: string[],
+ irOptions: LLVMIrBackendOptions,
+ produceCfg: boolean,
+ filters: ParseFiltersAndOutputOptions,
+ ) {
// These options make Clang produce an IR
const newOptions = options
.filter(option => option !== '/FA' && !option.startsWith('/Fa'))
@@ -56,13 +64,17 @@ export class ClangCLCompiler extends Win32Compiler {
const output = await this.runCompiler(this.compiler.exe, newOptions, this.filename(inputFilename), execOptions);
if (output.code !== 0) {
- return [{text: 'Failed to run compiler to get IR code'}];
+ return {
+ asm: [{text: 'Failed to run compiler to get IR code'}],
+ };
}
- const ir = await this.processIrOutput(output, filters);
- return ir.asm;
+ const ir = await this.processIrOutput(output, irOptions, filters);
+ return {
+ asm: ir.asm,
+ };
}
- override getIrOutputFilename(inputFilename: string, filters: ParseFiltersAndOutputOptions): string {
+ override getIrOutputFilename(inputFilename: string): string {
return this.filename(path.dirname(inputFilename) + '/output.s.obj');
}
diff --git a/lib/compilers/clean.ts b/lib/compilers/clean.ts
index ca1debdae..43d8a0c6f 100644
--- a/lib/compilers/clean.ts
+++ b/lib/compilers/clean.ts
@@ -106,7 +106,7 @@ export class CleanCompiler extends BaseCompiler {
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
) {
const tmpDir = path.dirname(inputFilename);
const moduleName = path.basename(inputFilename, '.icl');
diff --git a/lib/compilers/clspv.ts b/lib/compilers/clspv.ts
index 28c5d7ddb..9b276f299 100644
--- a/lib/compilers/clspv.ts
+++ b/lib/compilers/clspv.ts
@@ -66,7 +66,7 @@ export class CLSPVCompiler extends BaseCompiler {
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
) {
const sourceDir = path.dirname(inputFilename);
const spvBinFilename = this.getPrimaryOutputFilename(sourceDir, this.outputFilebase);
diff --git a/lib/compilers/compcert.ts b/lib/compilers/compcert.ts
new file mode 100644
index 000000000..e1e7dc837
--- /dev/null
+++ b/lib/compilers/compcert.ts
@@ -0,0 +1,31 @@
+// 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 {BaseCompiler} from '../base-compiler.js';
+
+export class CompCertCompiler extends BaseCompiler {
+ static get key() {
+ return 'compcert';
+ }
+}
diff --git a/lib/compilers/dart.ts b/lib/compilers/dart.ts
index b64762092..de67ec8b9 100644
--- a/lib/compilers/dart.ts
+++ b/lib/compilers/dart.ts
@@ -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);
diff --git a/lib/compilers/dosbox-compiler.ts b/lib/compilers/dosbox-compiler.ts
index 59f0847c5..b4b08c716 100644
--- a/lib/compilers/dosbox-compiler.ts
+++ b/lib/compilers/dosbox-compiler.ts
@@ -155,7 +155,7 @@ export class DosboxCompiler extends BaseCompiler {
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
) {
return super.runCompiler(
compiler,
diff --git a/lib/compilers/dotnet.ts b/lib/compilers/dotnet.ts
index 95ac84ad7..2c9c9a0b4 100644
--- a/lib/compilers/dotnet.ts
+++ b/lib/compilers/dotnet.ts
@@ -40,6 +40,8 @@ import * as exec from '../exec.js';
import {DotNetAsmParser} from '../parsers/asm-parser-dotnet.js';
import * as utils from '../utils.js';
+const AssemblyName = 'CompilerExplorer';
+
class DotNetCompiler extends BaseCompiler {
private readonly sdkBaseDir: string;
private readonly sdkVersion: string;
@@ -47,10 +49,12 @@ class DotNetCompiler extends BaseCompiler {
private readonly buildConfig: string;
private readonly clrBuildDir: string;
private readonly langVersion: string;
+ private readonly corerunPath: string;
+ private readonly disassemblyLoaderPath: string;
private readonly crossgen2Path: string;
private readonly sdkMajorVersion: number;
- private crossgen2VersionString: string;
+ private versionString: string;
constructor(compilerInfo: PreliminaryCompilerInfo, env) {
super(compilerInfo, env);
@@ -66,9 +70,11 @@ class DotNetCompiler extends BaseCompiler {
this.clrBuildDir = this.compilerProps<string>(`compiler.${this.compiler.id}.clrDir`);
this.langVersion = this.compilerProps<string>(`compiler.${this.compiler.id}.langVersion`);
+ this.corerunPath = path.join(this.clrBuildDir, 'corerun');
this.crossgen2Path = path.join(this.clrBuildDir, 'crossgen2', 'crossgen2');
this.asm = new DotNetAsmParser();
- this.crossgen2VersionString = '';
+ this.versionString = '';
+ this.disassemblyLoaderPath = path.join(this.clrBuildDir, 'DisassemblyLoader', 'DisassemblyLoader.dll');
}
get compilerOptions() {
@@ -86,6 +92,9 @@ class DotNetCompiler extends BaseCompiler {
'--singlemethodgenericarg',
'--codegenopt',
'--codegen-options',
+ '--maxgenericcycle',
+ '--maxgenericcyclebreadth',
+ '--max-vectort-bitwidth',
];
}
@@ -99,6 +108,11 @@ class DotNetCompiler extends BaseCompiler {
'--optimize-space',
'--Ot',
'--optimize-time',
+ '--enable-generic-cycle-detection',
+ '--inputbubble',
+ '--compilebubblegenerics',
+ '--aot',
+ '--crossgen2',
];
}
@@ -107,7 +121,7 @@ class DotNetCompiler extends BaseCompiler {
<PropertyGroup>
<TargetFramework>${this.targetFramework}</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
- <AssemblyName>CompilerExplorer</AssemblyName>
+ <AssemblyName>${AssemblyName}</AssemblyName>
<LangVersion>${this.langVersion}</LangVersion>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<Nullable>enable</Nullable>
@@ -115,15 +129,20 @@ class DotNetCompiler extends BaseCompiler {
</PropertyGroup>
<ItemGroup>
<Compile Include="${sourceFile}" />
+ <Reference Include="DisassemblyLoader" HintPath="${this.disassemblyLoaderPath}" />
</ItemGroup>
</Project>
`;
- const projectFilePath = path.join(programDir, `CompilerExplorer${this.lang.extensions[0]}proj`);
+ const projectFilePath = path.join(programDir, `${AssemblyName}${this.lang.extensions[0]}proj`);
await fs.writeFile(projectFilePath, projectFileContent);
}
- setCompilerExecOptions(execOptions: ExecutionOptions, programDir: string) {
+ setCompilerExecOptions(
+ execOptions: ExecutionOptions & {env: Record<string, string>},
+ programDir: string,
+ skipNuget: boolean = false,
+ ) {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
}
@@ -138,13 +157,16 @@ class DotNetCompiler extends BaseCompiler {
// directory here.
execOptions.env.DOTNET_CLI_HOME = programDir;
execOptions.env.DOTNET_ROOT = path.join(this.clrBuildDir, '.dotnet');
- // Place nuget packages in the output directory.
- execOptions.env.NUGET_PACKAGES = path.join(programDir, '.nuget');
// Try to be less chatty
execOptions.env.DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 'true';
execOptions.env.DOTNET_NOLOGO = 'true';
execOptions.customCwd = programDir;
+
+ if (!skipNuget) {
+ // Place nuget packages in the output directory.
+ execOptions.env.NUGET_PACKAGES = path.join(programDir, '.nuget');
+ }
}
override async buildExecutable(compiler, options, inputFilename, execOptions) {
@@ -152,7 +174,7 @@ class DotNetCompiler extends BaseCompiler {
const inputFilenameSafe = this.filename(inputFilename);
const sourceFile = path.basename(inputFilenameSafe);
await this.writeProjectfile(dirPath, true, sourceFile);
- return await this.buildToDll(compiler, options, inputFilename, execOptions);
+ return await this.buildToDll(compiler, inputFilename, execOptions);
}
override async doCompilation(inputFilename, dirPath, key, options, filters, backendOptions, libraries, tools) {
@@ -164,9 +186,8 @@ class DotNetCompiler extends BaseCompiler {
async buildToDll(
compiler: string,
- options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
): Promise<CompilationResult> {
const programDir = path.dirname(inputFilename);
const nugetConfigPath = path.join(programDir, 'nuget.config');
@@ -194,51 +215,203 @@ class DotNetCompiler extends BaseCompiler {
return compilerResult;
}
+ async publishAot(
+ compiler: string,
+ ilcOptions: string[],
+ ilcSwitches: string[],
+ inputFilename: string,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
+ ): Promise<CompilationResult> {
+ const programDir = path.dirname(inputFilename);
+
+ this.setCompilerExecOptions(execOptions, programDir, true);
+
+ // serialize ['a', 'b', 'c;d', '*e*'] into a=b;c%3Bd=%2Ae%2A;
+ const msbuildOptions = ilcOptions
+ .map(val => val.replaceAll('*', '%2A').replaceAll(';', '%3B'))
+ .reduce((acc, val, idx) => (idx % 2 === 0 ? (acc ? `${acc}${val}` : `${val}`) : `${acc}=${val};`), '');
+
+ // serialize ['a', 'b', 'c', 'd'] into a;b;c;d
+ const msbuildSwitches = ilcSwitches.join(';');
+
+ const toolVersion = await fs.readFile(`${this.clrBuildDir}/aot/package-version.txt`, 'utf8');
+ const jitOutFile = `${programDir}/jitout`;
+
+ ilcOptions.push('--codegenopt', `JitDisasmAssemblies=${AssemblyName}`);
+
+ await fs.writeFile(
+ path.join(programDir, `${AssemblyName}${this.lang.extensions[0]}proj`),
+ `<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <TargetFramework>${this.targetFramework}</TargetFramework>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <AssemblyName>${AssemblyName}</AssemblyName>
+ <LangVersion>${this.langVersion}</LangVersion>
+ <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
+ <Nullable>enable</Nullable>
+ <OutputType>Library</OutputType>
+ <RuntimeIdentifier>linux-x64</RuntimeIdentifier>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="${path.basename(this.filename(inputFilename))}" />
+ <PackageReference
+ Include="Microsoft.DotNet.ILCompiler;runtime.linux-x64.Microsoft.DotNet.ILCompiler"
+ Version="${toolVersion}" />
+ <IlcArg Include="${msbuildOptions}${msbuildSwitches};--codegenopt=JitStdOutFile=${jitOutFile}" />
+ </ItemGroup>
+ </Project>`,
+ );
+
+ // prettier-ignore
+ const publishOptions = ['publish', '-c', this.buildConfig, '-v', 'q', '--nologo', '/clp:NoSummary',
+ '--property', 'PublishAot=true', '--packages', `${this.clrBuildDir}/aot`];
+
+ // .NET 7 doesn't support JitStdOutFile, so higher max output is needed for stdout
+ execOptions.maxOutput = 1024 * 1024 * 1024;
+
+ const compilerResult = await super.runCompiler(compiler, publishOptions, inputFilename, execOptions);
+ if (compilerResult.code !== 0) {
+ return compilerResult;
+ }
+
+ await fs.createFile(this.getOutputFilename(programDir, this.outputFilebase));
+
+ const version = '// ilc ' + toolVersion;
+ const output = await fs.readFile(jitOutFile);
+
+ // .NET 7 doesn't support JitStdOutFile, so read from stdout
+ const outputString = output.length ? output.toString().split('\n') : compilerResult.stdout.map(o => o.text);
+
+ await fs.writeFile(
+ this.getOutputFilename(programDir, this.outputFilebase),
+ `${version}\n\n${outputString.reduce((a, n) => `${a}\n${n}`, '')}`,
+ );
+
+ return compilerResult;
+ }
+
override async runCompiler(
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
): Promise<CompilationResult> {
- const crossgen2Options: string[] = [];
- const configurableOptions = this.configurableOptions;
+ const corerunArgs: string[] = [];
+ // prettier-ignore
+ const toolOptions: string[] = [
+ '--codegenopt',
+ this.sdkMajorVersion === 6 ? 'NgenDisasm=*' : 'JitDisasm=*',
+ '--codegenopt',
+ this.sdkMajorVersion < 8 ? 'JitDiffableDasm=1' : 'JitDisasmDiffable=1',
+ '--parallelism', '1',
+ ];
+ const toolSwitches: string[] = [];
const programDir = path.dirname(inputFilename);
const programOutputPath = path.join(programDir, 'bin', this.buildConfig, this.targetFramework);
const programDllPath = path.join(programOutputPath, 'CompilerExplorer.dll');
+ // prettier-ignore
+ const envVarFileContents = [
+ 'DOTNET_EnableWriteXorExecute=0',
+ 'DOTNET_JitDisasm=*',
+ 'DOTNET_JitDisasmAssemblies=CompilerExplorer',
+ 'DOTNET_TieredCompilation=0',
+ this.sdkMajorVersion < 8 ? 'DOTNET_JitDiffableDasm=1' : 'DOTNET_JitDisasmDiffable=1',
+ ];
+ let isAot = false;
+ let isCrossgen2 = this.sdkMajorVersion === 6;
- for (const configurableOption of configurableOptions) {
- const optionIndex = options.indexOf(configurableOption);
- if (optionIndex === -1 || optionIndex === options.length - 1) {
+ while (options.length > 0) {
+ const currentOption = options.shift();
+ if (!currentOption) {
continue;
}
- crossgen2Options.push(options[optionIndex], options[optionIndex + 1]);
- }
- const configurableSwitches = this.configurableSwitches;
- for (const configurableSwitch of configurableSwitches) {
- const switchIndex = options.indexOf(configurableSwitch);
- if (switchIndex === -1) {
- continue;
+ if (currentOption === '-e' || currentOption === '--env') {
+ const envVar = options.shift();
+ if (envVar) {
+ const [name] = envVar.split('=');
+ const normalizedName = name.trim().toUpperCase();
+ if (
+ normalizedName === 'DOTNET_JITDISASM' ||
+ normalizedName === 'DOTNET_JITDUMP' ||
+ normalizedName === 'DOTNET_JITDISASMASSEMBILES'
+ ) {
+ continue;
+ }
+ envVarFileContents.push(envVar);
+ }
+ } else if (currentOption === '-p' || currentOption === '--property') {
+ const property = options.shift();
+ if (property) {
+ corerunArgs.push('-p', property);
+ }
+ } else if (this.configurableSwitches.indexOf(currentOption) !== -1) {
+ if (currentOption === '--aot') {
+ isAot = true;
+ } else if (currentOption === '--crossgen2') {
+ isCrossgen2 = true;
+ } else {
+ toolSwitches.push(currentOption);
+ }
+ } else if (this.configurableOptions.indexOf(currentOption) !== -1) {
+ const value = options.shift();
+ if (value) {
+ toolOptions.push(currentOption, value);
+ }
}
- crossgen2Options.push(options[switchIndex]);
}
this.setCompilerExecOptions(execOptions, programDir);
- const compilerResult = await this.buildToDll(compiler, options, inputFilename, execOptions);
- if (compilerResult.code !== 0) {
- return compilerResult;
- }
+ let compilerResult;
- const crossgen2Result = await this.runCrossgen2(
- execOptions,
- this.clrBuildDir,
- programDllPath,
- crossgen2Options,
- this.getOutputFilename(programDir, this.outputFilebase),
- );
+ if (isAot) {
+ if (!fs.existsSync(`${this.clrBuildDir}/aot`)) {
+ return {
+ code: -1,
+ timedOut: false,
+ didExecute: false,
+ stdout: [],
+ stderr: [{text: '--aot is not supported with this version.'}],
+ };
+ }
+
+ compilerResult = await this.publishAot(compiler, toolOptions, toolSwitches, inputFilename, execOptions);
+ } else {
+ compilerResult = await this.buildToDll(compiler, inputFilename, execOptions);
+ if (compilerResult.code !== 0) {
+ return compilerResult;
+ }
- if (crossgen2Result.code !== 0) {
- return crossgen2Result;
+ if (isCrossgen2) {
+ const crossgen2Result = await this.runCrossgen2(
+ execOptions,
+ this.clrBuildDir,
+ programDllPath,
+ toolOptions,
+ toolSwitches,
+ this.getOutputFilename(programDir, this.outputFilebase),
+ );
+
+ if (crossgen2Result.code !== 0) {
+ return crossgen2Result;
+ }
+ } else {
+ const envVarFilePath = path.join(programDir, '.env');
+ await fs.writeFile(envVarFilePath, envVarFileContents.join('\n'));
+
+ const corerunResult = await this.runCorerunForDisasm(
+ execOptions,
+ this.clrBuildDir,
+ envVarFilePath,
+ programDllPath,
+ corerunArgs,
+ this.getOutputFilename(programDir, this.outputFilebase),
+ );
+
+ if (corerunResult.code !== 0) {
+ return corerunResult;
+ }
+ }
}
return compilerResult;
@@ -256,7 +429,7 @@ class DotNetCompiler extends BaseCompiler {
): Promise<BasicExecutionResult> {
const programDir = path.dirname(executable);
const programOutputPath = path.join(programDir, 'bin', this.buildConfig, this.targetFramework);
- const programDllPath = path.join(programOutputPath, 'CompilerExplorer.dll');
+ const programDllPath = path.join(programOutputPath, `${AssemblyName}.dll`);
const execOptions = this.getDefaultExecOptions();
execOptions.maxOutput = maxSize;
execOptions.timeoutMs = this.env.ceProps('binaryExecTimeoutMs', 2000);
@@ -269,9 +442,8 @@ class DotNetCompiler extends BaseCompiler {
execOptions.env.CORE_ROOT = this.clrBuildDir;
execOptions.input = executeParameters.stdin;
const execArgs = ['-p', 'System.Runtime.TieredCompilation=false', programDllPath, ...executeParameters.args];
- const corerun = path.join(this.clrBuildDir, 'corerun');
try {
- const execResult: UnprocessedExecResult = await exec.sandbox(corerun, execArgs, execOptions);
+ const execResult: UnprocessedExecResult = await exec.sandbox(this.corerunPath, execArgs, execOptions);
return this.processExecutionResult(execResult);
} catch (err: UnprocessedExecResult | any) {
if (err.code && err.stderr) {
@@ -287,51 +459,70 @@ class DotNetCompiler extends BaseCompiler {
}
}
- async ensureCrossgen2Version(execOptions: ExecutionOptions) {
- if (!this.crossgen2VersionString) {
- this.crossgen2VersionString = '// crossgen2 ';
-
+ async checkRuntimeVersion() {
+ if (!this.versionString) {
const versionFilePath = `${this.clrBuildDir}/version.txt`;
- const versionResult = await this.exec(this.crossgen2Path, ['--version'], execOptions);
- if (versionResult.code === 0) {
- this.crossgen2VersionString += versionResult.stdout;
- } else if (fs.existsSync(versionFilePath)) {
+ if (fs.existsSync(versionFilePath)) {
const versionString = await fs.readFile(versionFilePath);
- this.crossgen2VersionString += versionString;
+ this.versionString = versionString.toString();
} else {
- this.crossgen2VersionString += '<unknown version>';
+ this.versionString = '<unknown version>';
}
}
}
+ async runCorerunForDisasm(
+ execOptions: ExecutionOptions,
+ coreRoot: string,
+ envPath: string,
+ dllPath: string,
+ options: string[],
+ outputPath: string,
+ ) {
+ await this.checkRuntimeVersion();
+
+ const corerunOptions = ['--clr-path', coreRoot, '--env', envPath].concat([
+ ...options,
+ this.disassemblyLoaderPath,
+ dllPath,
+ ]);
+ const compilerExecResult = await this.exec(this.corerunPath, corerunOptions, execOptions);
+ const result = this.transformToCompilationResult(compilerExecResult, dllPath);
+
+ await fs.writeFile(
+ outputPath,
+ `// coreclr ${this.versionString}\n\n${result.stdout.map(o => o.text).reduce((a, n) => `${a}\n${n}`, '')}`,
+ );
+
+ return result;
+ }
+
async runCrossgen2(
execOptions: ExecutionOptions,
bclPath: string,
dllPath: string,
- options: string[],
+ toolOptions: string[],
+ toolSwitches: string[],
outputPath: string,
) {
- await this.ensureCrossgen2Version(execOptions);
+ await this.checkRuntimeVersion();
- /* eslint-disable */
+ // prettier-ignore
const crossgen2Options = [
'-r', path.join(bclPath, '/'),
+ '-r', this.disassemblyLoaderPath,
dllPath,
- '-o', 'CompilerExplorer.r2r.dll',
- '--codegenopt', this.sdkMajorVersion < 7 ? 'NgenDisasm=*' : 'JitDisasm=*',
- '--codegenopt', this.sdkMajorVersion < 8 ? 'JitDiffableDasm=1' : 'JitDisasmDiffable=1',
- '--parallelism', '1',
- '--inputbubble',
- '--compilebubblegenerics',
- ].concat(options);
- /* eslint-enable */
+ '-o', `${AssemblyName}.r2r.dll`,
+ ].concat(toolOptions).concat(toolSwitches);
const compilerExecResult = await this.exec(this.crossgen2Path, crossgen2Options, execOptions);
const result = this.transformToCompilationResult(compilerExecResult, dllPath);
await fs.writeFile(
outputPath,
- `${this.crossgen2VersionString}\n\n${result.stdout.map(o => o.text).reduce((a, n) => `${a}\n${n}`, '')}`,
+ `// crossgen2 ${this.versionString}\n\n${result.stdout
+ .map(o => o.text)
+ .reduce((a, n) => `${a}\n${n}`, '')}`,
);
return result;
diff --git a/lib/compilers/edg.ts b/lib/compilers/edg.ts
new file mode 100644
index 000000000..7d2d785aa
--- /dev/null
+++ b/lib/compilers/edg.ts
@@ -0,0 +1,42 @@
+// 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 {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
+import {BaseCompiler} from '../base-compiler.js';
+
+export class EDGCompiler extends BaseCompiler {
+ constructor(info: PreliminaryCompilerInfo, env) {
+ super(info, env);
+ }
+
+ static get key() {
+ return 'edg';
+ }
+
+ override getSharedLibraryPathsAsArguments() {
+ // EDG does not have an equivalent to -Wl,-rpath in its driver, return
+ // an empty list.
+ return [];
+ }
+}
diff --git a/lib/compilers/flang.ts b/lib/compilers/flang.ts
index 17a1165d0..669715084 100644
--- a/lib/compilers/flang.ts
+++ b/lib/compilers/flang.ts
@@ -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) {
diff --git a/lib/compilers/fortran.ts b/lib/compilers/fortran.ts
index 5f13eb4ac..da2e9b53a 100644
--- a/lib/compilers/fortran.ts
+++ b/lib/compilers/fortran.ts
@@ -27,17 +27,26 @@ 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[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
): Promise<CompilationResult> {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
diff --git a/lib/compilers/gcccobol.ts b/lib/compilers/gcccobol.ts
new file mode 100644
index 000000000..5c8664cb9
--- /dev/null
+++ b/lib/compilers/gcccobol.ts
@@ -0,0 +1,31 @@
+// 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 {GCCCompiler} from './gcc.js';
+
+export class GCCCobolCompiler extends GCCCompiler {
+ static override get key() {
+ return 'gcccobol';
+ }
+}
diff --git a/lib/compilers/gnucobol.ts b/lib/compilers/gnucobol.ts
index 65582e8bd..04a2d537e 100644
--- a/lib/compilers/gnucobol.ts
+++ b/lib/compilers/gnucobol.ts
@@ -22,14 +22,11 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
-import _ from 'underscore';
-
import path from 'path';
-import type {CompilationResult, ExecutionOptions} from '../../types/compilation/compilation.interfaces.js';
+import type {ExecutionOptions} from '../../types/compilation/compilation.interfaces.js';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {BaseCompiler} from '../base-compiler.js';
-import * as utils from '../utils.js';
import {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
import {CompilationEnvironment} from '../compilation-env.js';
@@ -53,8 +50,12 @@ export class GnuCobolCompiler extends BaseCompiler {
}
override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: string) {
- let options = ['-o', this.filename(outputFilename), '-I', this.includeDir, '-L', this.libDir];
- if (!filters.binary) options = options.concat('-S');
+ let options = ['-o', this.filename(outputFilename), '-I', this.includeDir, '-L', this.libDir, '-A', '-g'];
+ if (this.compiler.intelAsm && filters.intel && !filters.binary && !filters.binaryObject) {
+ options = options.concat(this.compiler.intelAsm.split(' '));
+ }
+ if (!filters.binary && !filters.binaryObject) options = options.concat('-S');
+ else if (filters.binaryObject) options = options.concat('-c');
else options = options.concat('-x');
return options;
}
@@ -63,7 +64,7 @@ export class GnuCobolCompiler extends BaseCompiler {
return 'asm';
}
- override getDefaultExecOptions(): ExecutionOptions {
+ override getDefaultExecOptions(): ExecutionOptions & {env: Record<string, string>} {
const result = super.getDefaultExecOptions();
result.env.COB_CONFIG_DIR = this.configDir;
result.env.COB_COPY_DIR = this.copyDir;
@@ -95,6 +96,26 @@ export class GnuCobolCompiler extends BaseCompiler {
return objdumpResult;
}
+ override getOutputFilename(dirPath: string, outputFilebase: string, key?: any): string {
+ let filename;
+ if (key && key.backendOptions && key.backendOptions.customOutputFilename) {
+ filename = key.backendOptions.customOutputFilename;
+ } else if (key.filters.binary) {
+ // note: interesting fact about gnucobol, if you name the outputfile output.s it will always output assembly
+ filename = outputFilebase;
+ } else if (key.filters.binaryObject) {
+ filename = `${outputFilebase}.o`;
+ } else {
+ filename = `${outputFilebase}.s`;
+ }
+
+ if (dirPath) {
+ return path.join(dirPath, filename);
+ } else {
+ return filename;
+ }
+ }
+
override getExecutableFilename(dirPath: string, outputFilebase: string) {
return path.join(dirPath, outputFilebase);
}
diff --git a/lib/compilers/golang.ts b/lib/compilers/golang.ts
index 1914b3806..903278461 100644
--- a/lib/compilers/golang.ts
+++ b/lib/compilers/golang.ts
@@ -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.
@@ -60,9 +60,20 @@ export class GolangCompiler extends BaseCompiler {
constructor(compilerInfo: PreliminaryCompilerInfo, env) {
super(compilerInfo, env);
- const goroot = this.compilerProps<string | undefined>(`compiler.${this.compiler.id}.goroot`);
- const goarch = this.compilerProps<string | undefined>(`compiler.${this.compiler.id}.goarch`);
- const goos = this.compilerProps<string | undefined>(`compiler.${this.compiler.id}.goos`);
+ const group = this.compiler.group;
+
+ const goroot = this.compilerProps<string | undefined>(
+ 'goroot',
+ this.compilerProps<string | undefined>(`group.${group}.goroot`),
+ );
+ const goarch = this.compilerProps<string | undefined>(
+ 'goarch',
+ this.compilerProps<string | undefined>(`group.${group}.goarch`),
+ );
+ const goos = this.compilerProps<string | undefined>(
+ 'goos',
+ this.compilerProps<string | undefined>(`group.${group}.goos`),
+ );
this.GOENV = {};
if (goroot) {
@@ -215,7 +226,7 @@ export class GolangCompiler extends BaseCompiler {
result.asm = this.convertNewGoL(out);
result.stderr = [];
result.stdout = utils.parseOutput(logging, result.inputFilename);
- return Promise.all([result, '']);
+ return Promise.all([result, '', '']);
}
override getSharedLibraryPathsAsArguments() {
@@ -245,13 +256,19 @@ export class GolangCompiler extends BaseCompiler {
}
override getDefaultExecOptions() {
- return {
+ const options = {
...super.getDefaultExecOptions(),
+ };
+
+ options.env = {
+ ...options.env,
...this.GOENV,
};
+
+ return options;
}
- override getArgumentParser() {
- return ClangParser;
+ override getArgumentParser(): any {
+ return GolangParser;
}
}
diff --git a/lib/compilers/haskell.ts b/lib/compilers/haskell.ts
index 4446127e7..de5f054d8 100644
--- a/lib/compilers/haskell.ts
+++ b/lib/compilers/haskell.ts
@@ -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;
}
}
diff --git a/lib/compilers/hlsl.ts b/lib/compilers/hlsl.ts
index e7be44b58..7050355c1 100644
--- a/lib/compilers/hlsl.ts
+++ b/lib/compilers/hlsl.ts
@@ -26,8 +26,10 @@ import path from 'path';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {BaseCompiler} from '../base-compiler.js';
+import {SPIRVAsmParser} from '../parsers/asm-parser-spirv.js';
export class HLSLCompiler extends BaseCompiler {
+ protected spirvAsm: SPIRVAsmParser;
static get key() {
return 'hlsl';
}
@@ -36,6 +38,7 @@ export class HLSLCompiler extends BaseCompiler {
super(info, env);
this.compiler.supportsIntel = false;
+ this.spirvAsm = new SPIRVAsmParser(this.compilerProps);
}
/* eslint-disable no-unused-vars */
@@ -71,4 +74,16 @@ export class HLSLCompiler extends BaseCompiler {
override getIrOutputFilename(inputFilename: string) {
return this.getOutputFilename(path.dirname(inputFilename), this.outputFilebase).replace('.s', '.dxil');
}
+
+ override async processAsm(result, filters, options) {
+ if (this.isSpirv(result.asm)) {
+ return this.spirvAsm.processAsm(result.asm, filters);
+ }
+
+ return super.processAsm(result, filters, options);
+ }
+
+ isSpirv(code) {
+ return code.startsWith('; SPIR-V');
+ }
}
diff --git a/lib/compilers/hook.ts b/lib/compilers/hook.ts
index c731cc530..14eb27b8d 100644
--- a/lib/compilers/hook.ts
+++ b/lib/compilers/hook.ts
@@ -64,7 +64,7 @@ export class HookCompiler extends BaseCompiler {
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
): Promise<CompilationResult> {
const dirPath = path.dirname(inputFilename);
const outputFilename = this.getOutputFilename(dirPath);
@@ -72,10 +72,10 @@ export class HookCompiler extends BaseCompiler {
return super.runCompiler(compiler, options, inputFilename, execOptions);
}
- override processAsm(result, filters, options) {
+ override async processAsm(result, filters, options) {
// Ignoring `trim` filter because it is not supported by Hook.
filters.trim = false;
- const _result = super.processAsm(result, filters, options);
+ const _result = await super.processAsm(result, filters, options);
const commentRegex = /^\s*;(.*)/;
const instructionRegex = /^\s{2}(\d+)(.*)/;
const asm = _result.asm;
diff --git a/lib/compilers/ispc.ts b/lib/compilers/ispc.ts
index bfd097abd..c44fdb20a 100644
--- a/lib/compilers/ispc.ts
+++ b/lib/compilers/ispc.ts
@@ -32,6 +32,7 @@ import {asSafeVer} from '../utils.js';
import {ISPCParser} from './argument-parsers.js';
import {unwrap} from '../assert.js';
+import {LLVMIrBackendOptions} from '../../types/compilation/ir.interfaces.js';
export class ISPCCompiler extends BaseCompiler {
static get key() {
@@ -56,9 +57,20 @@ export class ISPCCompiler extends BaseCompiler {
return options;
}
- override async generateIR(inputFilename: string, options: string[], filters: ParseFiltersAndOutputOptions) {
- const newOptions = [...options, ...unwrap(this.compiler.irArg), '-o', this.getIrOutputFilename(inputFilename)];
- return super.generateIR(inputFilename, newOptions, filters);
+ override async generateIR(
+ inputFilename: string,
+ options: string[],
+ irOptions: LLVMIrBackendOptions,
+ produceCfg: boolean,
+ filters: ParseFiltersAndOutputOptions,
+ ) {
+ const newOptions = [
+ ...options,
+ ...unwrap(this.compiler.irArg),
+ '-o',
+ this.getIrOutputFilename(inputFilename, filters),
+ ];
+ return super.generateIR(inputFilename, newOptions, irOptions, produceCfg, filters);
}
override getArgumentParser() {
diff --git a/lib/compilers/java.ts b/lib/compilers/java.ts
index bfcc19e76..429e2f513 100644
--- a/lib/compilers/java.ts
+++ b/lib/compilers/java.ts
@@ -35,6 +35,7 @@ import {logger} from '../logger.js';
import * as utils from '../utils.js';
import {JavaParser} from './argument-parsers.js';
+import {BypassCache} from '../../types/compilation/compilation.interfaces.js';
export class JavaCompiler extends BaseCompiler {
static get key() {
@@ -48,7 +49,7 @@ export class JavaCompiler extends BaseCompiler {
super(
{
// Default is to disable all "cosmetic" filters
- disabledFilters: ['labels', 'directives', 'commentOnly', 'trim'],
+ disabledFilters: ['labels', 'directives', 'commentOnly', 'trim', 'debugCalls'],
...compilerInfo,
},
env,
@@ -70,6 +71,7 @@ export class JavaCompiler extends BaseCompiler {
.filter(f => f.endsWith('.class'))
.map(async classFile => {
const args = [
+ ...this.compiler.objdumperArgs,
// Prints out disassembled code, i.e., the instructions that comprise the Java bytecodes,
// for each of the methods in the class.
'-c',
@@ -127,7 +129,7 @@ export class JavaCompiler extends BaseCompiler {
}
override async handleInterpreting(key, executeParameters) {
- const compileResult = await this.getOrBuildExecutable(key);
+ const compileResult = await this.getOrBuildExecutable(key, BypassCache.None);
if (compileResult.code === 0) {
executeParameters.args = [
'-Xss136K', // Reduce thread stack size
@@ -236,7 +238,7 @@ export class JavaCompiler extends BaseCompiler {
return this.filterUserOptionsWithArg(userOptions, oneArgForbiddenList);
}
- override processAsm(result) {
+ override async processAsm(result) {
// Handle "error" documents.
if (!result.asm.includes('\n') && result.asm[0] === '<') {
return [{text: result.asm, source: null}];
@@ -349,7 +351,11 @@ export class JavaCompiler extends BaseCompiler {
method.instructions[currentInstr].instrOffset !== instrOffset
) {
if (currentSourceLine === -1) {
- logger.error('Skipping over instruction even though currentSourceLine == -1');
+ // TODO: Triage for #2986
+ logger.error(
+ 'Skipping over instruction even though currentSourceLine == -1',
+ JSON.stringify(method.instructions.slice(0, currentInstr + 10)),
+ );
} else {
// instructions without explicit line number get assigned the last explicit/same line number
method.instructions[currentInstr].sourceLine = currentSourceLine;
diff --git a/lib/compilers/julia.ts b/lib/compilers/julia.ts
index c72a52b98..292fcd31d 100644
--- a/lib/compilers/julia.ts
+++ b/lib/compilers/julia.ts
@@ -58,7 +58,7 @@ export class JuliaCompiler extends BaseCompiler {
return [];
}
- override processAsm(result, filters, options) {
+ override async processAsm(result, filters, options) {
const lineRe = /^<(\d+) (\d+) ([^ ]+) ([^>]*)>$/;
const bytecodeLines = result.asm.split('\n');
const bytecodeResult: ParsedAsmResultLine[] = [];
@@ -108,7 +108,7 @@ export class JuliaCompiler extends BaseCompiler {
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
): Promise<CompilationResult> {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
diff --git a/lib/compilers/kotlin.ts b/lib/compilers/kotlin.ts
index 0b5cce585..9b1bab103 100644
--- a/lib/compilers/kotlin.ts
+++ b/lib/compilers/kotlin.ts
@@ -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 {BypassCache} from '../../types/compilation/compilation.interfaces.js';
import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
@@ -98,7 +99,7 @@ export class KotlinCompiler extends JavaCompiler {
...key,
options: ['-include-runtime', '-d', 'example.jar'],
};
- const compileResult = await this.getOrBuildExecutable(alteredKey);
+ const compileResult = await this.getOrBuildExecutable(alteredKey, BypassCache.None);
executeParameters.args = [
'-Xss136K', // Reduce thread stack size
'-XX:CICompilerCount=2', // Reduce JIT compilation threads. 2 is minimum
diff --git a/lib/compilers/llvm-mos.ts b/lib/compilers/llvm-mos.ts
index 473e93263..9ff68a784 100644
--- a/lib/compilers/llvm-mos.ts
+++ b/lib/compilers/llvm-mos.ts
@@ -90,6 +90,15 @@ export class LLVMMOSCompiler extends ClangCompiler {
if (await utils.fileExists(nesFile)) {
await this.addArtifactToResult(res, nesFile, ArtifactType.nesrom);
}
+ } else if (this.compiler.exe.includes('c64')) {
+ let prgFile = outputFilename;
+ if (outputFilename.endsWith('.elf')) {
+ prgFile = outputFilename.substr(0, outputFilename.length - 4);
+ }
+
+ if (await utils.fileExists(prgFile)) {
+ await this.addArtifactToResult(res, prgFile, ArtifactType.c64prg);
+ }
}
return res;
diff --git a/lib/compilers/mlir.ts b/lib/compilers/mlir.ts
index 51bd6da88..59d5d5439 100644
--- a/lib/compilers/mlir.ts
+++ b/lib/compilers/mlir.ts
@@ -48,6 +48,7 @@ export class MLIRCompiler extends BaseCompiler {
'directives',
'commentOnly',
'trim',
+ 'debugCalls',
],
...compilerInfo,
},
@@ -78,4 +79,26 @@ export class MLIRCompiler extends BaseCompiler {
): any[] {
return [];
}
+
+ override async processAsm(result, filters, options) {
+ // at some point maybe a custom parser can be written, for now just don't filter anything
+ return super.processAsm(
+ result,
+ {
+ labels: false,
+ binary: false,
+ commentOnly: false,
+ demangle: false,
+ optOutput: false,
+ directives: false,
+ dontMaskFilenames: false,
+ execute: false,
+ intel: false,
+ libraryCode: false,
+ trim: false,
+ debugCalls: false,
+ },
+ options,
+ );
+ }
}
diff --git a/lib/compilers/movfuscator.ts b/lib/compilers/movfuscator.ts
new file mode 100644
index 000000000..3a0ddf69a
--- /dev/null
+++ b/lib/compilers/movfuscator.ts
@@ -0,0 +1,47 @@
+// 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 {ExecutionOptions} from '../../types/compilation/compilation.interfaces.js';
+import {BaseCompiler} from '../base-compiler.js';
+import * as exec from '../exec.js';
+
+export class MovfuscatorCompiler extends BaseCompiler {
+ static get key() {
+ return 'movfuscator';
+ }
+
+ override isCfgCompiler(compilerVersion: string) {
+ return true;
+ }
+
+ override async exec(filepath: string, args: string[], execOptions: ExecutionOptions) {
+ return await exec.execute(filepath, args, {
+ ...execOptions,
+ env: {
+ MOVBUILDDIR: '/opt/compiler-explorer/movfuscator-trunk/build',
+ ...execOptions.env,
+ },
+ });
+ }
+}
diff --git a/lib/compilers/mrustc.ts b/lib/compilers/mrustc.ts
index 2e67ae600..5bb54825e 100644
--- a/lib/compilers/mrustc.ts
+++ b/lib/compilers/mrustc.ts
@@ -60,7 +60,7 @@ export class MrustcCompiler extends BaseCompiler {
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
) {
// mrustc will always invoke a C compiler on its C output to create a final exec/object.
// There's no easy way to disable this last step, so simply faking it with 'true' works.
diff --git a/lib/compilers/nasm.ts b/lib/compilers/nasm.ts
index 14b4d043e..f591ff362 100644
--- a/lib/compilers/nasm.ts
+++ b/lib/compilers/nasm.ts
@@ -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;
diff --git a/lib/compilers/nvcc.ts b/lib/compilers/nvcc.ts
index e293de18d..91b261d1c 100644
--- a/lib/compilers/nvcc.ts
+++ b/lib/compilers/nvcc.ts
@@ -36,6 +36,7 @@ import {SassAsmParser} from '../parsers/asm-parser-sass.js';
import {asSafeVer} from '../utils.js';
import {ClangParser} from './argument-parsers.js';
+import _ from 'underscore';
export class NvccCompiler extends BaseCompiler {
static get key() {
@@ -56,7 +57,7 @@ export class NvccCompiler extends BaseCompiler {
// * would be nice to try and filter unused `.func`s from e.g. clang output
override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: string, userOptions?: string[]) {
- const opts = ['-o', this.filename(outputFilename), '-g', '-lineinfo'];
+ const opts = ['-o', this.filename(outputFilename), '-g', '-lineinfo', '--keep-device-functions'];
if (!filters.execute) {
opts.push('-c', '-keep', '-keep-dir', Path.dirname(outputFilename));
if (!filters.binary) {
@@ -102,15 +103,34 @@ export class NvccCompiler extends BaseCompiler {
override async postProcess(result, outputFilename: string, filters: ParseFiltersAndOutputOptions) {
const maxSize = this.env.ceProps('max-asm-size', 64 * 1024 * 1024);
const optPromise = result.hasOptOutput ? this.processOptOutput(result.optPath) : Promise.resolve('');
+ const postProcess = _.compact(this.compiler.postProcess);
const asmPromise = (
filters.binary
? this.objdump(outputFilename, {}, maxSize, filters.intel, filters.demangle, false, false, filters)
- : fs.readFile(outputFilename, {encoding: 'utf8'})
+ : (async () => {
+ if (result.asmSize === undefined) {
+ result.asm = '<No output file>';
+ return result;
+ }
+ if (result.asmSize >= maxSize) {
+ result.asm =
+ '<No output: generated assembly was too large' +
+ ` (${result.asmSize} > ${maxSize} bytes)>`;
+ return result;
+ }
+ if (postProcess.length > 0) {
+ return await this.execPostProcess(result, postProcess, outputFilename, maxSize);
+ } else {
+ const contents = await fs.readFile(outputFilename, {encoding: 'utf8'});
+ result.asm = contents.toString();
+ return result;
+ }
+ })()
).then(asm => {
result.asm = typeof asm === 'string' ? asm : asm.asm;
return result;
});
- return Promise.all([asmPromise, optPromise]);
+ return Promise.all([asmPromise, optPromise, '']);
}
override async extractDeviceCode(result, filters, compilationInfo: CompilationInfo) {
diff --git a/lib/compilers/nvcpp.ts b/lib/compilers/nvcpp.ts
new file mode 100644
index 000000000..b588c692b
--- /dev/null
+++ b/lib/compilers/nvcpp.ts
@@ -0,0 +1,129 @@
+// 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 * as fs from 'fs/promises';
+import path from 'path';
+
+import {CompilationInfo} from '../../types/compilation/compilation.interfaces.js';
+import {BaseCompiler} from '../base-compiler.js';
+import {SassAsmParser} from '../parsers/asm-parser-sass.js';
+import {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
+import {unwrap} from '../assert.js';
+
+export class NvcppCompiler extends BaseCompiler {
+ protected deviceAsmParser: SassAsmParser;
+ protected cuobjdump: string | undefined;
+
+ static get key() {
+ return 'nvcpp';
+ }
+
+ constructor(info: PreliminaryCompilerInfo, env) {
+ super(info, env);
+
+ this.cuobjdump = this.compilerProps<string | undefined>(
+ 'compiler.' + this.compiler.id + '.cuobjdump',
+ undefined,
+ );
+
+ this.deviceAsmParser = new SassAsmParser(this.compilerProps);
+
+ this.compiler.supportsDeviceAsmView = true;
+ }
+
+ async nvdisasm(result, outputFilename: string, maxOutput: number) {
+ const disasmResult = await this.exec(unwrap(this.compiler.nvdisasm), ['-c', '-g', '-hex', outputFilename], {
+ maxOutput,
+ customCwd: path.dirname(outputFilename),
+ });
+
+ const newResult = {asm: ''};
+
+ if (disasmResult.code === 0) {
+ newResult.asm = disasmResult.stdout;
+ } else {
+ newResult.asm = `<No output: ${path.basename(unwrap(this.compiler.nvdisasm))} returned ${
+ disasmResult.code
+ }>`;
+ }
+ return newResult;
+ }
+
+ async extractDeviceBinariesFromExecutable(result, compilationInfo: CompilationInfo) {
+ if (this.cuobjdump) {
+ const execOptions = this.getDefaultExecOptions();
+ execOptions.customCwd = result.dirPath;
+
+ if (!result.buildsteps) result.buildsteps = [];
+
+ await this.exec(this.cuobjdump, ['-xelf', 'all', compilationInfo.executableFilename], execOptions);
+
+ // couldn't test this, does this happen?
+ await this.exec(this.cuobjdump, ['-xptx', 'all', compilationInfo.executableFilename], execOptions);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ override async extractDeviceCode(result, filters, compilationInfo: CompilationInfo) {
+ const {dirPath} = result;
+ const {demangle} = filters;
+ const devices = {...result.devices};
+
+ if (filters.binary) {
+ await this.extractDeviceBinariesFromExecutable(result, compilationInfo);
+ }
+
+ if (dirPath) {
+ const files = await fs.readdir(dirPath);
+ const maxSize = this.env.ceProps('max-asm-size', 64 * 1024 * 1024);
+ await Promise.all(
+ files
+ .filter(f => f.endsWith('.ptx') || f.endsWith('.cubin'))
+ .map(async name => {
+ const type = name.endsWith('.ptx') ? 'PTX' : 'SASS';
+ const {asm} =
+ type === 'PTX'
+ ? {asm: await fs.readFile(path.join(dirPath, name), 'utf8')}
+ : await this.nvdisasm(result, path.join(dirPath, name), maxSize);
+ const archAndCode = name.split('.').slice(1, -1).join(', ') || '';
+ const nameAndArch = type + (archAndCode ? ` (${archAndCode.toLowerCase()})` : '');
+ Object.assign(devices, {
+ [nameAndArch]: await this.postProcessAsm(
+ {
+ okToCache: demangle,
+ ...this.deviceAsmParser.process(asm, {...filters, binary: type === 'SASS'}),
+ },
+ {...filters, binary: type === 'SASS'},
+ ),
+ });
+ }),
+ );
+ result.devices = devices;
+ }
+ return result;
+ }
+}
diff --git a/lib/compilers/osaca.ts b/lib/compilers/osaca.ts
index 0ecff9e92..f8df4982a 100644
--- a/lib/compilers/osaca.ts
+++ b/lib/compilers/osaca.ts
@@ -59,6 +59,7 @@ export class OSACATool extends AnalysisTool {
libraryCode: false,
trim: false,
binaryObject: false,
+ debugCalls: false,
};
}
diff --git a/lib/compilers/pascal-win.ts b/lib/compilers/pascal-win.ts
index 00b4bcba8..e73d0335b 100644
--- a/lib/compilers/pascal-win.ts
+++ b/lib/compilers/pascal-win.ts
@@ -99,7 +99,7 @@ export class PascalWinCompiler extends BaseCompiler {
outputFilename = this.getOutputFilename(path.dirname(outputFilename));
}
- let args = ['-d', outputFilename];
+ let args = [...this.compiler.objdumperArgs, '-d', outputFilename];
if (intelAsm) args = args.concat(['-M', 'intel']);
return this.exec(this.compiler.objdumper, args, {maxOutput: 1024 * 1024 * 1024}).then(objResult => {
if (objResult.code === 0) {
@@ -151,7 +151,7 @@ export class PascalWinCompiler extends BaseCompiler {
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
) {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
diff --git a/lib/compilers/pascal.ts b/lib/compilers/pascal.ts
index 01b04b607..c91ba6a8b 100644
--- a/lib/compilers/pascal.ts
+++ b/lib/compilers/pascal.ts
@@ -62,7 +62,7 @@ export class FPCCompiler extends BaseCompiler {
return [];
}
- override processAsm(result, filters) {
+ override async processAsm(result, filters) {
// TODO: Pascal doesn't have a demangler exe, it's the only compiler that's weird like this
this.demangler = new (unwrap(this.demanglerClass))(null as any, this);
return this.asm.process(result.asm, filters);
@@ -90,7 +90,7 @@ export class FPCCompiler extends BaseCompiler {
options = options.concat(this.compiler.intelAsm.split(' '));
}
- filters.preProcessLines = _.bind(this.preProcessLines, this);
+ filters.preProcessLines = this.preProcessLines.bind(this);
if (filters.binary) {
filters.dontMaskFilenames = true;
@@ -186,7 +186,7 @@ export class FPCCompiler extends BaseCompiler {
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
) {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
@@ -198,7 +198,7 @@ export class FPCCompiler extends BaseCompiler {
const projectFile = path.join(dirPath, this.dprFilename);
execOptions.customCwd = dirPath;
if (this.nasmPath) {
- execOptions.env = _.clone(process.env);
+ execOptions.env = _.clone(process.env) as Record<string, string>;
execOptions.env.PATH = execOptions.env.PATH + ':' + this.nasmPath;
}
diff --git a/lib/compilers/pony.ts b/lib/compilers/pony.ts
index 081f84ebb..6906f58e1 100644
--- a/lib/compilers/pony.ts
+++ b/lib/compilers/pony.ts
@@ -30,6 +30,7 @@ import type {CompilationResult, ExecutionOptions} from '../../types/compilation/
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
import {BaseCompiler} from '../base-compiler.js';
import {unwrap} from '../assert.js';
+import {LLVMIrBackendOptions} from '../../types/compilation/ir.interfaces.js';
export class PonyCompiler extends BaseCompiler {
static get key() {
@@ -62,7 +63,13 @@ export class PonyCompiler extends BaseCompiler {
return source;
}
- override async generateIR(inputFilename: string, options: string[], filters: ParseFiltersAndOutputOptions) {
+ override async generateIR(
+ inputFilename: string,
+ options: string[],
+ irOptions: LLVMIrBackendOptions,
+ produceCfg: boolean,
+ filters: ParseFiltersAndOutputOptions,
+ ) {
const newOptions = _.filter(options, option => !['--pass', 'asm'].includes(option)).concat(
unwrap(this.compiler.irArg),
);
@@ -73,17 +80,21 @@ export class PonyCompiler extends BaseCompiler {
const output = await this.runCompiler(this.compiler.exe, newOptions, this.filename(inputFilename), execOptions);
if (output.code !== 0) {
- return [{text: 'Failed to run compiler to get IR code'}];
+ return {
+ asm: [{text: 'Failed to run compiler to get IR code'}],
+ };
}
- const ir = await this.processIrOutput(output, filters);
- return ir.asm;
+ const ir = await this.processIrOutput(output, irOptions, filters);
+ return {
+ asm: ir.asm,
+ };
}
override async runCompiler(
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
): Promise<CompilationResult> {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
diff --git a/lib/compilers/ptxas.ts b/lib/compilers/ptxas.ts
index 4073a8139..40157ded0 100644
--- a/lib/compilers/ptxas.ts
+++ b/lib/compilers/ptxas.ts
@@ -93,7 +93,7 @@ export class PtxAssembler extends BaseCompiler {
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
) {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
@@ -121,7 +121,7 @@ export class PtxAssembler extends BaseCompiler {
override async objdump(outputFilename, result: any, maxSize: number) {
const dirPath = path.dirname(outputFilename);
- const args = ['-c', '-g', '-hex', outputFilename];
+ const args = [...this.compiler.objdumperArgs, '-c', '-g', '-hex', outputFilename];
const objResult = await this.exec(this.compiler.objdumper, args, {maxOutput: maxSize, customCwd: dirPath});
result.asm = objResult.stdout;
if (objResult.code === 0) {
diff --git a/lib/compilers/python.ts b/lib/compilers/python.ts
index 6bca3ce4f..0d9cc8dde 100644
--- a/lib/compilers/python.ts
+++ b/lib/compilers/python.ts
@@ -46,7 +46,7 @@ export class PythonCompiler extends BaseCompiler {
resolvePathFromAppRoot('etc', 'scripts', 'disasms', 'dis_all.py');
}
- override processAsm(result) {
+ override async processAsm(result) {
const lineRe = /^\s{0,4}(\d+)(.*)/;
const bytecodeLines = result.asm.split('\n');
diff --git a/lib/compilers/racket.ts b/lib/compilers/racket.ts
index 9c808dba7..0811058d1 100644
--- a/lib/compilers/racket.ts
+++ b/lib/compilers/racket.ts
@@ -41,7 +41,7 @@ export class RacketCompiler extends BaseCompiler {
super(
{
// Disable output filters, as they currently don't do anything
- disabledFilters: ['labels', 'directives', 'commentOnly', 'trim'],
+ disabledFilters: ['labels', 'directives', 'commentOnly', 'trim', 'debugCalls'],
...info,
},
env,
@@ -74,7 +74,7 @@ export class RacketCompiler extends BaseCompiler {
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
): Promise<CompilationResult> {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
@@ -123,7 +123,7 @@ export class RacketCompiler extends BaseCompiler {
return result;
}
- override processAsm(result: any, filters: any, options: any) {
+ override async processAsm(result: any, filters: any, options: any) {
// TODO: Process and highlight decompiled output
return {
asm: [{text: result.asm}],
diff --git a/lib/compilers/rga.ts b/lib/compilers/rga.ts
index 21d839ccd..645dfc4bb 100644
--- a/lib/compilers/rga.ts
+++ b/lib/compilers/rga.ts
@@ -105,7 +105,7 @@ Please supply an ASIC from the following options:`,
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
): Promise<CompilationResult> {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
diff --git a/lib/compilers/ruby.ts b/lib/compilers/ruby.ts
index f19cf1638..07886c3b8 100644
--- a/lib/compilers/ruby.ts
+++ b/lib/compilers/ruby.ts
@@ -48,7 +48,7 @@ export class RubyCompiler extends BaseCompiler {
return 'asmruby';
}
- override processAsm(result) {
+ override async processAsm(result) {
const lineRe = /\(\s*(\d+)\)(?:\[[^\]]+])?$/;
const fileRe = /ISeq:.*?@(.*?):(\d+) /;
const baseFile = path.basename(this.compileFilename);
diff --git a/lib/compilers/rust.ts b/lib/compilers/rust.ts
index 09fba6952..98683f6d9 100644
--- a/lib/compilers/rust.ts
+++ b/lib/compilers/rust.ts
@@ -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,19 +52,60 @@ 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;
this.compiler.supportsRustHirView = isNightly;
this.compiler.irArg = ['--emit', 'llvm-ir'];
+ this.compiler.minIrArgs = ['--emit=llvm-ir'];
this.compiler.llvmOptArg = ['-C', 'llvm-args=-print-after-all -print-before-all'];
this.compiler.llvmOptModuleScopeArg = ['-C', 'llvm-args=-print-module-scope'];
this.compiler.llvmOptNoDiscardValueNamesArg = isNightly ? ['-Z', 'fewer-names=no'] : [];
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 [];
}
diff --git a/lib/compilers/snowball.ts b/lib/compilers/snowball.ts
new file mode 100644
index 000000000..613e69276
--- /dev/null
+++ b/lib/compilers/snowball.ts
@@ -0,0 +1,95 @@
+// 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 'underscore';
+
+import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
+import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
+import {unwrap} from '../assert.js';
+import {BaseCompiler} from '../base-compiler.js';
+
+export class SnowballCompiler extends BaseCompiler {
+ linker: string;
+
+ static get key() {
+ return 'snowball';
+ }
+
+ constructor(info: PreliminaryCompilerInfo, env) {
+ super(info, env);
+ this.compiler.supportsIntel = false;
+ this.compiler.supportsIrView = true;
+ this.compiler.supportsLLVMOptPipelineView = true;
+ this.compiler.supportsCfg = true;
+
+ this.compiler.irArg = ['--emit', 'llvm-ir'];
+ this.linker = this.compilerProps<string>('linker');
+ }
+
+ override getSharedLibraryPathsAsArguments(libraries, libDownloadPath) {
+ return [];
+ }
+
+ override getSharedLibraryLinks(libraries: any[]): string[] {
+ return [];
+ }
+
+ override orderArguments(
+ options: string[],
+ inputFilename: string,
+ libIncludes: string[],
+ libOptions: string[],
+ libPaths: string[],
+ libLinks: string[],
+ userOptions: string[],
+ staticLibLinks: string[],
+ ) {
+ return options.concat(userOptions, libIncludes, libOptions, libPaths, libLinks, staticLibLinks, [
+ '-f',
+ this.filename(inputFilename),
+ ]);
+ }
+
+ override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: string, userOptions?: string[]) {
+ let options = ['build', '--silent', '-o', this.filename(outputFilename)];
+
+ const userRequestedEmit = _.any(unwrap(userOptions), opt => opt.includes('--emit'));
+ if (filters.binary) {
+ options = options.concat(['--emit', 'exec']);
+ } else if (filters.binaryObject) {
+ options = options.concat(['--emit', 'lib']);
+ } else {
+ if (!userRequestedEmit) {
+ options = options.concat('--emit', 'asm');
+ }
+ // TODO:
+ // if (filters.intel) options = options.concat('--llvm-args', '--x86-asm-syntax=intel');
+ }
+ return options;
+ }
+
+ override isCfgCompiler(/*compilerVersion*/) {
+ return true;
+ }
+}
diff --git a/lib/compilers/solidity.ts b/lib/compilers/solidity.ts
index fee0f4afe..13812b052 100644
--- a/lib/compilers/solidity.ts
+++ b/lib/compilers/solidity.ts
@@ -65,7 +65,7 @@ export class SolidityCompiler extends BaseCompiler {
return path.join(dirPath, 'contracts/combined.json');
}
- override processAsm(result) {
+ override async processAsm(result) {
// Handle "error" documents.
if (!result.asm.includes('\n') && result.asm[0] === '<') {
return {asm: [{text: result.asm}]};
@@ -235,7 +235,7 @@ export class SolidityCompiler extends BaseCompiler {
processPossibleTagOpcode(opcode, contractFunctions);
} else {
- processPossibleTagOpcode(opcode, generatedSources[opcode.source]);
+ processPossibleTagOpcode(opcode, generatedSources[opcode.source] || []);
}
}
diff --git a/lib/compilers/spirv.ts b/lib/compilers/spirv.ts
index 60ce5d338..a709a43f8 100644
--- a/lib/compilers/spirv.ts
+++ b/lib/compilers/spirv.ts
@@ -34,6 +34,8 @@ 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';
+import {LLVMIrBackendOptions} from '../../types/compilation/ir.interfaces.js';
export class SPIRVCompiler extends BaseCompiler {
protected translatorPath: string;
@@ -59,6 +61,7 @@ export class SPIRVCompiler extends BaseCompiler {
inputFilename: string,
outputFilename: string,
libraries,
+ overrides: ConfiguredOverrides,
) {
let options = this.optionsForFilter(filters, outputFilename);
backendOptions = backendOptions || {};
@@ -118,7 +121,7 @@ export class SPIRVCompiler extends BaseCompiler {
compiler: string,
options: string[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
) {
const sourceDir = path.dirname(inputFilename);
const bitcodeFilename = path.join(sourceDir, this.outputFilebase + '.bc');
@@ -166,7 +169,7 @@ export class SPIRVCompiler extends BaseCompiler {
compiler: string,
options: any[],
inputFilename: string,
- execOptions: ExecutionOptions,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
) {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
@@ -199,7 +202,13 @@ export class SPIRVCompiler extends BaseCompiler {
);
}
- override async generateIR(inputFilename: string, options: string[], filters: ParseFiltersAndOutputOptions) {
+ override async generateIR(
+ inputFilename: string,
+ options: string[],
+ irOptions: LLVMIrBackendOptions,
+ produceCfg: boolean,
+ filters: ParseFiltersAndOutputOptions,
+ ) {
const newOptions = _.filter(options, option => option !== '-fcolor-diagnostics').concat('-emit-llvm');
const execOptions = this.getDefaultExecOptions();
@@ -213,9 +222,13 @@ export class SPIRVCompiler extends BaseCompiler {
);
if (output.code !== 0) {
logger.error('Failed to run compiler to get IR code');
- return output.stderr;
+ return {
+ asm: output.stderr,
+ };
}
- const ir = await this.processIrOutput(output, filters);
- return ir.asm;
+ const ir = await this.processIrOutput(output, irOptions, filters);
+ return {
+ asm: ir.asm,
+ };
}
}
diff --git a/lib/compilers/swift.ts b/lib/compilers/swift.ts
index caa07237e..6b4406aeb 100644
--- a/lib/compilers/swift.ts
+++ b/lib/compilers/swift.ts
@@ -24,19 +24,29 @@
import {BaseCompiler} from '../base-compiler.js';
-import {ClangParser} from './argument-parsers.js';
+import {SwiftParser} from './argument-parsers.js';
+
+import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
export class SwiftCompiler extends BaseCompiler {
static get key() {
return 'swift';
}
+ constructor(info: PreliminaryCompilerInfo, env) {
+ super(info, env);
+ this.compiler.supportsLLVMOptPipelineView = true;
+ this.compiler.llvmOptArg = ['-Xllvm', '-print-after-all', '-Xllvm', '-print-before-all'];
+ this.compiler.llvmOptModuleScopeArg = ['-Xllvm', '-print-module-scope'];
+ this.compiler.llvmOptNoDiscardValueNamesArg = [];
+ }
+
override getSharedLibraryPathsAsArguments() {
return [];
}
override getArgumentParser() {
- return ClangParser;
+ return SwiftParser;
}
override isCfgCompiler(/*compilerVersion*/) {
diff --git a/lib/compilers/tendra.ts b/lib/compilers/tendra.ts
index 47323d3f2..3bfad871d 100644
--- a/lib/compilers/tendra.ts
+++ b/lib/compilers/tendra.ts
@@ -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;
+ }
}
diff --git a/lib/compilers/tic2000.ts b/lib/compilers/tic2000.ts
new file mode 100644
index 000000000..864881511
--- /dev/null
+++ b/lib/compilers/tic2000.ts
@@ -0,0 +1,70 @@
+// 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 path from 'path';
+
+import {BaseCompiler} from '../base-compiler.js';
+import {TiC2000AsmParser} from '../parsers/asm-parser-tic2000.js';
+
+export class TIC2000 extends BaseCompiler {
+ static get key() {
+ return 'tic2000';
+ }
+
+ constructor(info, env) {
+ super(info, env);
+ this.outputFilebase = this.compileFilename.split('.')[0];
+ this.asm = new TiC2000AsmParser(this.compilerProps);
+ }
+
+ override optionsForFilter(filters, outputFilename) {
+ const options = ['-g', '-c', '-n', '--output_file=' + outputFilename];
+
+ filters.preProcessLines = this.preProcessLines.bind(this);
+
+ return options;
+ }
+
+ override getOutputFilename(dirPath, outputFilebase) {
+ return path.join(dirPath, `${outputFilebase}.asm`);
+ }
+
+ preProcessLines(asmLines) {
+ let i = 0;
+
+ while (i < asmLines.length) {
+ // Regex for determining the file line and column of the following source lines
+ const match = asmLines[i].match(/^\s*\.dwpsn\s+file\s+(".*"),line\s+(\d+),column\s+(\d+)/);
+ i++;
+ if (match) {
+ // Add two lines stating the file and location to allow parsing the source location by the standard
+ // parser
+ asmLines.splice(i, 0, ' .file 1 ' + match[1], ' .loc 1 ' + match[2] + ' ' + match[3]);
+ i += 2;
+ }
+ }
+
+ return asmLines;
+ }
+}
diff --git a/lib/compilers/turboc.ts b/lib/compilers/turboc.ts
index 93df469f3..e09fed67b 100644
--- a/lib/compilers/turboc.ts
+++ b/lib/compilers/turboc.ts
@@ -53,12 +53,12 @@ export class TurboCCompiler extends DosboxCompiler {
return {stdout: [this.compiler.explicitVersion], stderr: [], code: 0};
}
const execOptions = this.getDefaultExecOptions();
- const versionFlag = '';
+ const versionFlag = [];
execOptions.timeoutMs = 0;
execOptions.ldPath = this.getSharedLibraryPathsAsLdLibraryPaths([]);
try {
- return this.execCompilerCached(this.compiler.exe, [versionFlag], execOptions);
+ return this.execCompilerCached(this.compiler.exe, versionFlag, execOptions);
} catch (err) {
logger.error(`Unable to get version for compiler '${this.compiler.exe}' - ${err}`);
return null;
diff --git a/lib/compilers/typescript-native.ts b/lib/compilers/typescript-native.ts
index 32017f66b..11790ce50 100644
--- a/lib/compilers/typescript-native.ts
+++ b/lib/compilers/typescript-native.ts
@@ -22,10 +22,14 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
-import type {CompilationResult, ExecutionOptions} from '../../types/compilation/compilation.interfaces.js';
+import Semver from 'semver';
+import path from 'path';
+
import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
+import {LLVMIrBackendOptions} from '../../types/compilation/ir.interfaces.js';
import {BaseCompiler} from '../base-compiler.js';
+import {asSafeVer} from '../utils.js';
import {TypeScriptNativeParser} from './argument-parsers.js';
@@ -36,98 +40,90 @@ export class TypeScriptNativeCompiler extends BaseCompiler {
tscJit: string;
tscSharedLib: string;
+ tscNewOutput: boolean;
+ tscAsmOutput: boolean;
constructor(compilerInfo: PreliminaryCompilerInfo, env) {
super(compilerInfo, env);
- this.compiler.supportsIntel = false;
- this.compiler.supportsIrView = true;
-
- this.tscJit = this.compilerProps<string>(`compiler.${this.compiler.id}.exe`);
+ this.tscJit = this.compiler.exe;
this.tscSharedLib = this.compilerProps<string>(`compiler.${this.compiler.id}.sharedlibs`);
+ this.tscNewOutput = Semver.gt(asSafeVer(this.compiler.semver || '0.0.0'), '0.0.32', true);
+ this.tscAsmOutput = Semver.gt(asSafeVer(this.compiler.semver || '0.0.0'), '0.0.34', true);
+
+ this.compiler.irArg = ['--emit=llvm'];
+ this.compiler.supportsIntel = this.tscAsmOutput;
+ this.compiler.supportsIrView = true;
}
override getSharedLibraryPathsAsArguments() {
return [];
}
- override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: string) {
- return [this.filename(outputFilename)];
+ override optionsForFilter(
+ filters: ParseFiltersAndOutputOptions,
+ outputFilename: string,
+ userOptions?: string[],
+ ): string[] {
+ return [];
}
- override async handleInterpreting(key, executeParameters) {
- executeParameters.args = [
- '--emit=jit',
- this.tscSharedLib ? '--shared-libs=' + this.tscSharedLib : '-nogc',
- ...executeParameters.args,
- ];
-
- return await super.handleInterpreting(key, executeParameters);
- }
+ override optionsForBackend(backendOptions: Record<string, any>, outputFilename: string): string[] {
+ const addOpts: string[] = [];
- override async runCompiler(
- compiler: string,
- options: string[],
- inputFilename: string,
- execOptions: ExecutionOptions,
- ): Promise<CompilationResult> {
- // These options make Clang produce an IR
- const newOptions = ['--emit=mlir-llvm', inputFilename];
+ addOpts.push(this.tscAsmOutput ? '--emit=asm' : '--emit=mlir');
if (!this.tscSharedLib) {
- newOptions.push('-nogc');
+ addOpts.push('-nogc');
}
- const output = await this.runCompilerRawOutput(
- this.tscJit,
- newOptions,
- this.filename(inputFilename),
- execOptions,
- );
- if (output.code !== 0) {
- return {
- code: output.code,
- timedOut: false,
- stdout: [],
- stderr: [
- {
- text: 'Failed to run compiler to get MLIR code',
- },
- ],
- };
+ if (this.tscNewOutput) {
+ addOpts.push('-o=' + this.filename(outputFilename));
}
- return {code: 0, timedOut: false, stdout: [], stderr: []};
+ return addOpts;
}
- override async generateIR(inputFilename: string, options: string[], filters: ParseFiltersAndOutputOptions) {
- // These options make Clang produce an IR
- const newOptions = ['--emit=llvm', inputFilename];
+ override getIrOutputFilename(inputFilename: string, filters: ParseFiltersAndOutputOptions): string {
+ const outputFilename = this.getOutputFilename(path.dirname(inputFilename), this.outputFilebase);
+ // As per #4054, if we are asked for binary mode, the output will be in the .s file, no .ll will be emited
+ if (!filters.binary) {
+ return outputFilename.replace('.s', '.ll');
+ }
+ return outputFilename;
+ }
- if (!this.tscSharedLib) {
- newOptions.push('-nogc');
+ override async generateIR(
+ inputFilename: string,
+ options: string[],
+ irOptions: LLVMIrBackendOptions,
+ produceCfg: boolean,
+ filters: ParseFiltersAndOutputOptions,
+ ) {
+ const newOptions = [...options.filter(e => !e.startsWith('--emit=') && !e.startsWith('-o='))];
+ if (this.tscNewOutput) {
+ newOptions.push('-o=' + this.getIrOutputFilename(inputFilename, filters));
}
- const execOptions = this.getDefaultExecOptions();
- // TODO: maybe this isn't needed?
- execOptions.maxOutput = 1024 * 1024 * 1024;
-
- const output = await this.runCompilerRawOutput(
- this.tscJit,
- newOptions,
- this.filename(inputFilename),
- execOptions,
- );
- if (output.code !== 0) {
- return [{text: 'Failed to run compiler to get IR code'}];
+ return await super.generateIR(inputFilename, newOptions, irOptions, produceCfg, filters);
+ }
+
+ override async processIrOutput(output, irOptions: LLVMIrBackendOptions, filters: ParseFiltersAndOutputOptions) {
+ if (this.tscNewOutput) {
+ return await super.processIrOutput(output, irOptions, filters);
}
- filters.commentOnly = false;
- filters.libraryCode = true;
- filters.directives = true;
+ return this.llvmIr.process(output.stderr.map(l => l.text).join('\n'), irOptions);
+ }
+
+ override async handleInterpreting(key, executeParameters) {
+ executeParameters.args = [
+ '--emit=jit',
+ this.tscSharedLib ? '--shared-libs=' + this.tscSharedLib : '-nogc',
+ ...executeParameters.args,
+ ];
- const ir = await this.llvmIr.process(output.stderr, filters);
- return ir.asm;
+ return await super.handleInterpreting(key, executeParameters);
}
override isCfgCompiler() {
diff --git a/lib/compilers/v.ts b/lib/compilers/v.ts
new file mode 100644
index 000000000..d5b5abf10
--- /dev/null
+++ b/lib/compilers/v.ts
@@ -0,0 +1,230 @@
+// 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 path from 'path';
+
+import {unwrap} from '../assert.js';
+import {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
+import {BaseCompiler} from '../base-compiler.js';
+import {CompilationResult, ExecutionOptions} from '../../types/compilation/compilation.interfaces.js';
+
+const V_DEFAULT_BACKEND = 'c';
+
+export class VCompiler extends BaseCompiler {
+ outputFileExt = `.${V_DEFAULT_BACKEND}`;
+
+ static get key() {
+ return 'v';
+ }
+
+ override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: string, userOptions?: string[]) {
+ const options = unwrap(userOptions);
+ if (options) {
+ if (options.includes('-h') || options.includes('--help')) {
+ return [];
+ }
+
+ const backend = this.getBackendFromOptions(options);
+ const outputFileExt = this.getFileExtForBackend(backend);
+ if (outputFileExt !== undefined) {
+ this.outputFileExt = outputFileExt;
+ }
+ }
+
+ const compilerOptions: string[] = [];
+ if (!filters.binary) {
+ compilerOptions.push('-o');
+ compilerOptions.push(this.filename(this.patchOutputFilename(outputFilename)));
+ }
+
+ if (!filters.labels) {
+ compilerOptions.push('-skip-unused');
+ }
+
+ return compilerOptions;
+ }
+
+ override async processAsm(result: any, filters, options: string[]): Promise<any> {
+ const backend = this.getBackendFromOptions(options);
+ switch (backend) {
+ case 'c':
+ case 'js':
+ case 'js_node':
+ case 'js_browser':
+ case 'js_freestanding':
+ case 'go':
+ return this.processCLike(result, filters);
+ default:
+ return this.asm.process(result.asm, filters);
+ }
+ }
+
+ override getSharedLibraryPathsAsArguments(libraries, libDownloadPath) {
+ return [];
+ }
+
+ override getSharedLibraryLinks(libraries: any[]): string[] {
+ return [];
+ }
+
+ override getOutputFilename(dirPath: string, outputFilebase: string, key?: any): string {
+ return path.join(dirPath, 'output' + this.outputFileExt);
+ }
+
+ override async runCompiler(
+ compiler: string,
+ options: string[],
+ inputFilename: string,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
+ ): Promise<CompilationResult> {
+ if (!execOptions) {
+ execOptions = super.getDefaultExecOptions();
+ }
+
+ const tmpDir = path.dirname(inputFilename);
+ execOptions.env['VMODULES'] = path.join(tmpDir, '.vmodules');
+ execOptions.env['VTMP'] = tmpDir;
+
+ if (!execOptions.customCwd) {
+ execOptions.customCwd = tmpDir;
+ }
+
+ const result = await this.exec(compiler, options, execOptions);
+ return {
+ ...this.transformToCompilationResult(result, inputFilename),
+ languageId: this.getCompilerResultLanguageId(),
+ };
+ }
+
+ getBackendFromOptions(options: string[]): string {
+ const backendOpt = options.indexOf('-b');
+ if (backendOpt >= 0 && options[backendOpt + 1]) return options[backendOpt + 1].toLowerCase();
+ if (options.includes('-native')) return 'native';
+ if (options.includes('-interpret')) return 'interpret';
+
+ return V_DEFAULT_BACKEND; // default V backend
+ }
+
+ getFileExtForBackend(backend: string): string | undefined {
+ switch (backend) {
+ case 'c':
+ case 'go':
+ case 'wasm':
+ return '.' + backend;
+ case 'js':
+ case 'js_node':
+ case 'js_browser':
+ case 'js_freestanding':
+ return '.js';
+ case 'native':
+ return '';
+ default:
+ return undefined;
+ }
+ }
+
+ patchOutputFilename(outputFilename: string): string {
+ const parts = outputFilename.split('.');
+
+ if (this.outputFileExt === '') {
+ parts.pop();
+ return parts.join('.');
+ }
+
+ parts[parts.length - 1] = this.outputFileExt.split('.')[1];
+ return parts.join('.');
+ }
+
+ removeUnusedLabels(input: string[]): string[] {
+ const output: string[] = [];
+
+ const lineRe = /^.*main__.*$/;
+ const mainFunctionCall = '\tmain__main();';
+
+ let scopeDepth = 0;
+ let insertNewLine = false;
+
+ for (const lineNo in input) {
+ const line = input[lineNo];
+ if (!line) continue;
+
+ if (insertNewLine) {
+ output.push('');
+ insertNewLine = false;
+ }
+
+ if ((scopeDepth === 0 && line.match(lineRe) && line !== mainFunctionCall) || scopeDepth > 0) {
+ const opening = (line.match(/{/g) || []).length - 1;
+ const closing = (line.match(/}/g) || []).length - 1;
+ scopeDepth += opening - closing;
+
+ output.push(line);
+
+ insertNewLine = scopeDepth === 0;
+ }
+ }
+
+ return output;
+ }
+
+ removeWhitespaceLines = (input: string[]) => input.map(line => line.trimStart()).filter(line => line !== '');
+ removeComments = (input: string[]) =>
+ input
+ .filter(line => !line.trimStart().startsWith('//'))
+ .map(line => line.split('//')[0].replaceAll(/(\/\*).*?(\*\/)/g, ''));
+ removeDirectives = (input: string[]) => input.filter(line => !line.trimStart().startsWith('#'));
+
+ async processCLike(result, filters): Promise<any> {
+ let lines = result.asm.split('\n');
+
+ // remove non-user defined code
+ if (!filters.labels) lines = this.removeUnusedLabels(lines);
+
+ // remove comments
+ if (!filters.commentOnly) lines = this.removeComments(lines);
+
+ // remove whitespace
+ if (filters.trim) lines = this.removeWhitespaceLines(lines);
+
+ // remove preprocessor directives
+ if (!filters.directives) lines = this.removeDirectives(lines);
+
+ // finally, remove unnecessary newlines to make the output nicer
+ const finalLines: string[] = [];
+ let emptyLineEncountered = false;
+
+ for (const lineNo in lines) {
+ const line = lines[lineNo];
+
+ if (line.trimStart() === '') {
+ if (emptyLineEncountered) continue;
+ emptyLineEncountered = true;
+ } else emptyLineEncountered = false;
+
+ finalLines.push(line);
+ }
+
+ return {asm: finalLines.map(line => ({text: line}))};
+ }
+}
diff --git a/lib/compilers/v8.ts b/lib/compilers/v8.ts
new file mode 100644
index 000000000..c5b1a832c
--- /dev/null
+++ b/lib/compilers/v8.ts
@@ -0,0 +1,63 @@
+// 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 path from 'path';
+import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
+import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
+import {BaseCompiler} from '../base-compiler.js';
+
+export class V8Compiler extends BaseCompiler {
+ static get key() {
+ return 'v8';
+ }
+
+ constructor(compilerInfo: PreliminaryCompilerInfo, env) {
+ super(compilerInfo, env);
+ this.compiler.demangler = '';
+ this.demanglerClass = null;
+ }
+
+ override getIrOutputFilename(inputFilename: string): string {
+ return this.filename(path.dirname(inputFilename) + '/code.asm');
+ }
+
+ public override getOutputFilename(dirPath: string, outputFilebase: string, key?: any) {
+ let filename;
+ if (key && key.backendOptions && key.backendOptions.customOutputFilename) {
+ filename = key.backendOptions.customOutputFilename;
+ } else {
+ filename = 'code.asm';
+ }
+
+ if (dirPath) {
+ return path.join(dirPath, filename);
+ } else {
+ return filename;
+ }
+ }
+
+ override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: string) {
+ return [];
+ }
+}
diff --git a/lib/compilers/vala.ts b/lib/compilers/vala.ts
new file mode 100644
index 000000000..d36975dec
--- /dev/null
+++ b/lib/compilers/vala.ts
@@ -0,0 +1,109 @@
+// 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 path from 'path';
+
+import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
+import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
+import {BaseCompiler} from '../base-compiler.js';
+
+export class ValaCompiler extends BaseCompiler {
+ static get key() {
+ return 'vala';
+ }
+
+ ccPath: string;
+ pkgconfigPath: string;
+
+ constructor(compiler: PreliminaryCompilerInfo, env) {
+ super(compiler, env);
+ this.ccPath = this.compilerProps<string>(`compiler.${this.compiler.id}.cc`);
+ this.pkgconfigPath = this.compilerProps<string>(`compiler.${this.compiler.id}.pkgconfigpath`);
+ }
+
+ override getCompilerResultLanguageId() {
+ return 'c';
+ }
+
+ override getDefaultExecOptions() {
+ const execOptions = super.getDefaultExecOptions();
+ if (this.ccPath) {
+ execOptions.env.CC = this.ccPath;
+ }
+
+ if (this.pkgconfigPath) {
+ execOptions.env.PKG_CONFIG_PATH = this.pkgconfigPath;
+ }
+
+ return execOptions;
+ }
+
+ override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: any) {
+ const options = ['-g'];
+ if (!filters.binary) {
+ options.push('-C'); // Save transpiled C code
+ } else {
+ options.push('-o', this.filename(outputFilename));
+ }
+
+ return options;
+ }
+
+ override async objdump(
+ outputFilename,
+ result: any,
+ maxSize: number,
+ intelAsm,
+ demangle,
+ staticReloc: boolean,
+ dynamicReloc: boolean,
+ filters: ParseFiltersAndOutputOptions,
+ ) {
+ const objdumpResult = await super.objdump(
+ outputFilename,
+ result,
+ maxSize,
+ intelAsm,
+ demangle,
+ staticReloc,
+ dynamicReloc,
+ filters,
+ );
+
+ objdumpResult.languageId = 'asm';
+ return objdumpResult;
+ }
+
+ override getSharedLibraryPathsAsArguments(libraries, libDownloadPath) {
+ return [];
+ }
+
+ override getSharedLibraryLinks(libraries: any[]): string[] {
+ return [];
+ }
+
+ override getOutputFilename(dirPath: string, outputFilebase: string, key?: any): string {
+ return path.join(dirPath, 'example.c');
+ }
+}
diff --git a/lib/compilers/win32-mingw-clang.ts b/lib/compilers/win32-mingw-clang.ts
new file mode 100644
index 000000000..6a1990a12
--- /dev/null
+++ b/lib/compilers/win32-mingw-clang.ts
@@ -0,0 +1,114 @@
+// 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 path from 'path';
+
+import {
+ BuildResult,
+ BypassCache,
+ CompilationResult,
+ ExecutionOptions,
+} from '../../types/compilation/compilation.interfaces.js';
+import {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
+
+import {copyNeededDlls} from '../win-utils.js';
+
+import {ClangCompiler} from './clang.js';
+
+export class Win32MingWClang extends ClangCompiler {
+ static override get key() {
+ return 'win32-mingw-clang';
+ }
+
+ getExtraPaths(): string[] {
+ return [path.normalize(path.dirname(this.compiler.exe))];
+ }
+
+ override optionsForFilter(
+ filters: ParseFiltersAndOutputOptions,
+ outputFilename: string,
+ userOptions?: string[],
+ ): string[] {
+ if (filters.binary) {
+ filters.dontMaskFilenames = true;
+ }
+
+ return super.optionsForFilter(filters, outputFilename, userOptions);
+ }
+
+ override orderArguments(
+ options: string[],
+ inputFilename: string,
+ libIncludes: string[],
+ libOptions: string[],
+ libPaths: string[],
+ libLinks: string[],
+ userOptions: string[],
+ staticLibLinks: string[],
+ ) {
+ const newUserOptions = userOptions.filter(opt => !opt.startsWith('-l'));
+ const newLinkOptions = userOptions.filter(opt => opt.startsWith('-l'));
+
+ return options.concat(
+ newUserOptions,
+ [this.filename(inputFilename)],
+ libIncludes,
+ libOptions,
+ libPaths,
+ newLinkOptions,
+ libLinks,
+ staticLibLinks,
+ );
+ }
+
+ override getDefaultExecOptions(): ExecutionOptions & {env: Record<string, string>} {
+ const options = super.getDefaultExecOptions();
+ if (!options.env) options.env = {};
+ if (!options.env.PATH) options.env.PATH = '';
+ options.env.PATH = this.getExtraPaths().join(path.delimiter);
+
+ return options;
+ }
+
+ override async buildExecutableInFolder(key, dirPath: string): Promise<BuildResult> {
+ const result = await super.buildExecutableInFolder(key, dirPath);
+
+ if (result.code === 0) {
+ await copyNeededDlls(
+ dirPath,
+ result.executableFilename,
+ this.exec,
+ this.compiler.objdumper,
+ this.getDefaultExecOptions(),
+ );
+ }
+
+ return result;
+ }
+
+ override async handleExecution(key, executeParameters, bypassCache: BypassCache): Promise<CompilationResult> {
+ const execOptions = this.getDefaultExecOptions();
+ return super.handleExecution(key, {...executeParameters, env: execOptions.env}, bypassCache);
+ }
+}
diff --git a/lib/compilers/win32-mingw-gcc.ts b/lib/compilers/win32-mingw-gcc.ts
new file mode 100644
index 000000000..715b1e0c1
--- /dev/null
+++ b/lib/compilers/win32-mingw-gcc.ts
@@ -0,0 +1,114 @@
+// 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 path from 'path';
+
+import {
+ BuildResult,
+ BypassCache,
+ CompilationResult,
+ ExecutionOptions,
+} from '../../types/compilation/compilation.interfaces.js';
+import {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
+
+import {copyNeededDlls} from '../win-utils.js';
+
+import {GCCCompiler} from './gcc.js';
+
+export class Win32MingWGcc extends GCCCompiler {
+ static override get key() {
+ return 'win32-mingw-gcc';
+ }
+
+ getExtraPaths(): string[] {
+ return [path.normalize(path.dirname(this.compiler.exe))];
+ }
+
+ override optionsForFilter(
+ filters: ParseFiltersAndOutputOptions,
+ outputFilename: string,
+ userOptions?: string[],
+ ): string[] {
+ if (filters.binary) {
+ filters.dontMaskFilenames = true;
+ }
+
+ return super.optionsForFilter(filters, outputFilename, userOptions);
+ }
+
+ override orderArguments(
+ options: string[],
+ inputFilename: string,
+ libIncludes: string[],
+ libOptions: string[],
+ libPaths: string[],
+ libLinks: string[],
+ userOptions: string[],
+ staticLibLinks: string[],
+ ) {
+ const newUserOptions = userOptions.filter(opt => !opt.startsWith('-l'));
+ const newLinkOptions = userOptions.filter(opt => opt.startsWith('-l'));
+
+ return options.concat(
+ newUserOptions,
+ [this.filename(inputFilename)],
+ libIncludes,
+ libOptions,
+ libPaths,
+ newLinkOptions,
+ libLinks,
+ staticLibLinks,
+ );
+ }
+
+ override getDefaultExecOptions(): ExecutionOptions & {env: Record<string, string>} {
+ const options = super.getDefaultExecOptions();
+ if (!options.env) options.env = {};
+ if (!options.env.PATH) options.env.PATH = '';
+ options.env.PATH = this.getExtraPaths().join(path.delimiter);
+
+ return options;
+ }
+
+ override async buildExecutableInFolder(key, dirPath: string): Promise<BuildResult> {
+ const result = await super.buildExecutableInFolder(key, dirPath);
+
+ if (result.code === 0) {
+ await copyNeededDlls(
+ dirPath,
+ result.executableFilename,
+ this.exec,
+ this.compiler.objdumper,
+ this.getDefaultExecOptions(),
+ );
+ }
+
+ return result;
+ }
+
+ override async handleExecution(key, executeParameters, bypassCache: BypassCache): Promise<CompilationResult> {
+ const execOptions = this.getDefaultExecOptions();
+ return super.handleExecution(key, {...executeParameters, env: execOptions.env}, bypassCache);
+ }
+}
diff --git a/lib/compilers/win32.ts b/lib/compilers/win32.ts
index 3466ff392..8f2cff314 100644
--- a/lib/compilers/win32.ts
+++ b/lib/compilers/win32.ts
@@ -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) => {
@@ -59,8 +64,8 @@ export class Win32Compiler extends BaseCompiler {
});
}
- override getExecutableFilename(dirPath: string, outputFilebase: string) {
- return this.getOutputFilename(dirPath, outputFilebase) + '.exe';
+ override getExecutableFilename(dirPath: string, outputFilebase: string, key?) {
+ return this.getOutputFilename(dirPath, outputFilebase, key) + '.exe';
}
override getObjdumpOutputFilename(defaultOutputFilename: string) {
@@ -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 || {};
@@ -168,7 +174,7 @@ export class Win32Compiler extends BaseCompiler {
}
}
- override processAsm(result, filters /*, options*/) {
+ override async processAsm(result, filters /*, options*/) {
if (filters.binary) {
filters.dontMaskFilenames = true;
return this.binaryAsmParser.process(result.asm, filters);
diff --git a/lib/compilers/wine-vc.ts b/lib/compilers/wine-vc.ts
index 14eec9b40..461085092 100644
--- a/lib/compilers/wine-vc.ts
+++ b/lib/compilers/wine-vc.ts
@@ -49,7 +49,12 @@ export class WineVcCompiler extends BaseCompiler {
return 'Z:' + fn;
}
- override runCompiler(compiler: string, options: string[], inputFilename: string, execOptions: ExecutionOptions) {
+ override async runCompiler(
+ compiler: string,
+ options: string[],
+ inputFilename: string,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
+ ) {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
}
@@ -59,7 +64,7 @@ export class WineVcCompiler extends BaseCompiler {
execOptions.customCwd = execOptions.customCwd.substr(2);
}
- return super.runCompiler(compiler, options, inputFilename, execOptions);
+ return await super.runCompiler(compiler, options, inputFilename, execOptions);
}
override getArgumentParser() {
diff --git a/lib/compilers/wsl-vc.ts b/lib/compilers/wsl-vc.ts
index 5195341af..1908cb05f 100644
--- a/lib/compilers/wsl-vc.ts
+++ b/lib/compilers/wsl-vc.ts
@@ -60,7 +60,7 @@ export class WslVcCompiler extends Win32VcCompiler {
// NPM temp package: https://www.npmjs.com/package/temp, see Affixes
override newTempDir() {
return new Promise<string>((resolve, reject) => {
- temp.mkdir({prefix: 'compiler-explorer-compiler', dir: process.env.winTmp}, (err, dirPath) => {
+ temp.mkdir({prefix: 'compiler-explorer-compiler', dir: unwrap(process.env.winTmp)}, (err, dirPath) => {
if (err) reject(`Unable to open temp file: ${err}`);
else resolve(dirPath);
});
@@ -82,7 +82,12 @@ export class WslVcCompiler extends Win32VcCompiler {
return super.exec(compiler, args, options);
}
- override runCompiler(compiler: string, options: string[], inputFilename: string, execOptions: ExecutionOptions) {
+ override async runCompiler(
+ compiler: string,
+ options: string[],
+ inputFilename: string,
+ execOptions: ExecutionOptions & {env: Record<string, string>},
+ ) {
if (!execOptions) {
execOptions = this.getDefaultExecOptions();
}
@@ -94,6 +99,6 @@ export class WslVcCompiler extends Win32VcCompiler {
const directoryPath = inputDirectory.substring(2).trim();
execOptions.customCwd = path.join('/mnt', driveLetter, directoryPath);
- return super.runCompiler(compiler, options, inputFilename, execOptions);
+ return await super.runCompiler(compiler, options, inputFilename, execOptions);
}
}
diff --git a/lib/compilers/z88dk.ts b/lib/compilers/z88dk.ts
index 85d234336..ff16d07e3 100644
--- a/lib/compilers/z88dk.ts
+++ b/lib/compilers/z88dk.ts
@@ -32,6 +32,7 @@ import {BaseCompiler} 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,
@@ -90,7 +108,7 @@ export class z88dkCompiler extends BaseCompiler {
}
}
- override getDefaultExecOptions(): ExecutionOptions {
+ override getDefaultExecOptions(): ExecutionOptions & {env: Record<string, string>} {
const opts = super.getDefaultExecOptions();
opts.env.ZCCCFG = path.join(path.dirname(this.compiler.exe), '../share/z88dk/lib/config');
opts.env.PATH = process.env.PATH + path.delimiter + path.dirname(this.compiler.exe);
@@ -134,7 +152,7 @@ export class z88dkCompiler extends BaseCompiler {
}
}
- const args = [outputFilename];
+ const args = [...this.compiler.objdumperArgs, outputFilename];
if (this.externalparser) {
const objResult = await this.externalparser.objdumpAndParseAssembly(result.dirPath, args, filters);
diff --git a/lib/compilers/zig.ts b/lib/compilers/zig.ts
index df2f3575f..b0d55432b 100644
--- a/lib/compilers/zig.ts
+++ b/lib/compilers/zig.ts
@@ -54,6 +54,7 @@ export class ZigCompiler extends BaseCompiler {
} else {
this.compiler.irArg = ['--emit', 'llvm-ir'];
}
+ this.compiler.minIrArgs = ['--emit llvm-ir', '-femit-llvm-ir'];
}
override getSharedLibraryPathsAsArguments(): string[] {
diff --git a/lib/compilers/zigcxx.ts b/lib/compilers/zigcxx.ts
index 2d9b8ff3e..39a2e1621 100644
--- a/lib/compilers/zigcxx.ts
+++ b/lib/compilers/zigcxx.ts
@@ -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