aboutsummaryrefslogtreecommitdiff
path: root/lib/base-compiler.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/base-compiler.js')
-rw-r--r--lib/base-compiler.js108
1 files changed, 108 insertions, 0 deletions
diff --git a/lib/base-compiler.js b/lib/base-compiler.js
index 5235d4975..cdac46dd0 100644
--- a/lib/base-compiler.js
+++ b/lib/base-compiler.js
@@ -36,6 +36,7 @@ import { CompilerArguments } from './compiler-arguments';
import { ClangParser, GCCParser } from './compilers/argument-parsers';
import { getDemanglerTypeByKey } from './demangler';
import * as exec from './exec';
+import { FormattingHandler } from './handlers/formatting';
import { InstructionSets } from './instructionsets';
import { languages } from './languages';
import { LlvmAstParser } from './llvm-ast';
@@ -79,6 +80,8 @@ export class BaseCompiler {
this.llvmIr = new LlvmIrParser(this.compilerProps);
this.llvmAst = new LlvmAstParser(this.compilerProps);
+ this.formatHandler = new FormattingHandler(this.env.ceProps);
+
this.toolchainPath = getToolchainPath(this.compiler.exe, this.compiler.options);
this.possibleArguments = new CompilerArguments(this.compiler.id);
@@ -287,6 +290,20 @@ export class BaseCompiler {
return result;
}
+ async runCompilerRawOutput(compiler, options, inputFilename, execOptions) {
+ if (!execOptions) {
+ execOptions = this.getDefaultExecOptions();
+ }
+
+ if (!execOptions.customCwd) {
+ execOptions.customCwd = path.dirname(inputFilename);
+ }
+
+ const result = await this.exec(compiler, options, execOptions);
+ result.inputFilename = inputFilename;
+ return result;
+ }
+
parseCompilationOutput(result, inputFilename) {
result.stdout = utils.parseOutput(result.stdout, inputFilename);
result.stderr = utils.parseOutput(result.stderr, inputFilename);
@@ -695,6 +712,88 @@ export class BaseCompiler {
await this.runCompiler(this.compiler.exe, newOptions, this.filename(inputFilename), execOptions));
}
+ async generatePP(inputFilename, compilerOptions, rawPpOptions) {
+ // -E to dump preprocessor output, remove -o so it is dumped to stdout
+ compilerOptions = compilerOptions.concat(['-E']);
+ if (compilerOptions.includes('-o')) {
+ compilerOptions.splice(compilerOptions.indexOf('-o'), 2);
+ }
+
+ let ppOptions = _.extend({
+ 'filter-headers': false,
+ 'clang-format': false,
+ }, rawPpOptions);
+
+ const execOptions = this.getDefaultExecOptions();
+ // A higher max output is needed for when the user includes headers
+ execOptions.maxOutput = 1024 * 1024 * 1024;
+ let result = await this.runCompilerRawOutput(this.compiler.exe, compilerOptions,
+ this.filename(inputFilename), execOptions);
+ let output = result.stdout;
+
+ let numberOfLinesFiltered = 0;
+ if (ppOptions['filter-headers']) {
+ [numberOfLinesFiltered, output] = this.filterPP(output);
+ }
+ if (ppOptions['clang-format']) {
+ output = await this.applyClangFormat(output);
+ }
+
+ return {
+ numberOfLinesFiltered,
+ output: output,
+ };
+ }
+
+ filterPP(stdout) {
+ // Every compiler except Chibicc, as far as I've tested, outputs these line annotations
+ // Compiler test: https://godbolt.org/z/K7Pncjs4o
+ // Matching things like:
+ // # 4 "/app/example.cpp"
+ // # 11 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 2 3 4
+ // #line 1816 "C:/WinSdk/Include/10.0.18362.0/ucrt\\corecrt.h"
+ // # 13 "" 3
+ // regex test cases: https://regex101.com/r/9dOsUI/1
+ let lines = stdout.split('\n');
+ const ppLineRe = /^\s*#\s*(?:line)?\s*\d+\s*"((?:\\"|[^"])*)"/i;
+ let isInSourceRegion = true;
+ let numberOfLinesFiltered = 0;
+ let filteredLines = [];
+ for (const line of lines) {
+ let match = line.match(ppLineRe);
+ if (match === null) {
+ if (isInSourceRegion) {
+ filteredLines.push(line);
+ } else {
+ numberOfLinesFiltered++;
+ }
+ } else {
+ let path = match[1];
+ if (path.trim() === '' || path === '<source>' || path.endsWith('.c') || path.endsWith('.cpp')) {
+ isInSourceRegion = true;
+ } else {
+ isInSourceRegion = false;
+ }
+ numberOfLinesFiltered++;
+ }
+ }
+ return [numberOfLinesFiltered, filteredLines.join('\n')];
+ }
+
+ async applyClangFormat(output) {
+ // Currently hard-coding llvm style
+ try {
+ let [stdout, stderr] = await this.formatHandler.internalFormat('clangformat', 'LLVM', output);
+ if (stderr) {
+ stdout += '\n/* clang-format stderr:\n' + stderr.trim() + '\n*/';
+ }
+ return stdout;
+ } catch (err) {
+ logger.error('Internal formatter error', {err});
+ return '/* <Error while running clang-format> */\n\n' + output;
+ }
+ }
+
async generateIR(inputFilename, options, filters) {
// These options make Clang produce an IR
const newOptions = _.filter(options, option => option !== '-fcolor-diagnostics')
@@ -1249,6 +1348,7 @@ export class BaseCompiler {
execOptions.ldPath = this.getSharedLibraryPathsAsLdLibraryPaths([]);
const makeAst = backendOptions.produceAst && this.compiler.supportsAstView;
+ const makePp = typeof backendOptions.producePp === 'object' && this.compiler.supportsPpView;
const makeGnatDebug = backendOptions.produceGnatDebug && this.compiler.supportsGnatDebugViews;
const makeGnatDebugTree = backendOptions.produceGnatDebugTree && this.compiler.supportsGnatDebugViews;
const makeIr = backendOptions.produceIr && this.compiler.supportsIrView;
@@ -1262,6 +1362,7 @@ export class BaseCompiler {
const [
asmResult,
astResult,
+ ppResult,
irResult,
rustHirResult,
rustMacroExpResult,
@@ -1269,6 +1370,7 @@ export class BaseCompiler {
] = await Promise.all([
this.runCompiler(this.compiler.exe, options, inputFilenameSafe, execOptions),
(makeAst ? this.generateAST(inputFilename, options) : ''),
+ (makePp ? this.generatePP(inputFilename, options, backendOptions.producePp) : ''),
(makeIr ? this.generateIR(inputFilename, options, filters) : ''),
(makeRustHir ? this.generateRustHir(inputFilename, options) : ''),
(makeRustMacroExp ? this.generateRustMacroExpansion(inputFilename, options) : ''),
@@ -1332,6 +1434,10 @@ export class BaseCompiler {
asmResult.hasAstOutput = true;
asmResult.astOutput = astResult;
}
+ if (ppResult) {
+ asmResult.hasPpOutput = true;
+ asmResult.ppOutput = ppResult;
+ }
if (irResult) {
asmResult.hasIrOutput = true;
asmResult.irOutput = irResult;
@@ -2031,6 +2137,8 @@ but nothing was dumped. Possible causes are:
this.compiler.version = version;
this.compiler.fullVersion = fullVersion;
this.compiler.supportsCfg = this.isCfgCompiler(version);
+ // all C/C++ compilers support -E
+ this.compiler.supportsPpView = (this.compiler.lang === 'c' || this.compiler.lang === 'c++');
this.compiler.supportsAstView = this.couldSupportASTDump(version);
}