Remove global handler_config variable (#7675)

The global handler_config was being used to allow compilers to find
other compilers. This change replaces that global with a proper method
on the CompilationEnvironment class, allowing compilers to find other
compilers through the environment instead of using a global variable.

🤖 PR description generated with [Claude Code](https://claude.ai/code) -
code by @mattgodbolt though :)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Matt Godbolt
2025-05-11 19:47:58 -05:00
committed by GitHub
parent ad5bec7626
commit 2f892583ba
7 changed files with 25 additions and 57 deletions

8
app.ts
View File

@@ -548,6 +548,7 @@ async function main() {
defArgs.doCache,
);
const compileHandler = new CompileHandler(compilationEnvironment, awsProps);
compilationEnvironment.setCompilerFinder(compileHandler.findCompiler.bind(compileHandler));
const storageType = getStorageTypeByKey(storageSolution);
const storageHandler = new storageType(httpRoot, compilerProps, awsProps);
const compilerFinder = new CompilerFinder(compileHandler, compilerProps, defArgs, clientOptionsHandler);
@@ -614,8 +615,7 @@ async function main() {
process.exit(0);
}
// Exported to allow compilers to refer to other existing compilers.
global.handler_config = {
const handler_config = {
compileHandler,
clientOptionsHandler,
storageHandler,
@@ -627,8 +627,8 @@ async function main() {
renderGoldenLayout,
};
const noscriptHandler = new NoScriptHandler(router, global.handler_config);
const routeApi = new RouteAPI(router, global.handler_config);
const noscriptHandler = new NoScriptHandler(router, handler_config);
const routeApi = new RouteAPI(router, handler_config);
async function onCompilerChange(compilers: CompilerInfo[]) {
if (JSON.stringify(prevCompilers) === JSON.stringify(compilers)) {

View File

@@ -30,7 +30,9 @@ import _ from 'underscore';
import type {CacheableValue} from '../types/cache.interfaces.js';
import {CompilerOverrideOptions} from '../types/compilation/compiler-overrides.interfaces.js';
import {LanguageKey} from '../types/languages.interfaces.js';
import {unwrap} from './assert.js';
import {BaseCompiler} from './base-compiler.js';
import type {Cache} from './cache/base.interfaces.js';
import {BaseCache} from './cache/base.js';
import {createCacheFromConfig} from './cache/from-config.js';
@@ -41,6 +43,8 @@ import type {PropertyGetter} from './properties.interfaces.js';
import {CompilerProps, PropFunc} from './properties.js';
import {IStatsNoter, createStatsNoter} from './stats.js';
type FindCompiler = (langId: LanguageKey, compilerId: string) => BaseCompiler | undefined;
export class CompilationEnvironment {
ceProps: PropertyGetter;
awsProps: PropFunc;
@@ -58,6 +62,7 @@ export class CompilationEnvironment {
statsNoter: IStatsNoter;
private logCompilerCacheAccesses: boolean;
private cachingInProgress: Record<string, boolean>;
private findCompilerFunc?: FindCompiler;
constructor(
compilerProps: CompilerProps,
@@ -202,4 +207,13 @@ export class CompilationEnvironment {
getCompilerPropsForLanguage(languageId: string): PropFunc {
return _.partial(this.compilerProps as any, languageId);
}
setCompilerFinder(compilerFinder: FindCompiler) {
this.findCompilerFunc = compilerFinder;
}
findCompiler(langId: LanguageKey, compilerId: string): BaseCompiler | undefined {
if (!this.findCompilerFunc) throw new Error('Compiler finder not set');
return this.findCompilerFunc(langId, compilerId);
}
}

View File

@@ -36,7 +36,6 @@ import {unwrap} from '../assert.js';
import {BaseCompiler, SimpleOutputFilenameCompiler} from '../base-compiler.js';
import {CompilationEnvironment} from '../compilation-env.js';
import {logger} from '../logger.js';
import '../global.js';
import * as utils from '../utils.js';
import {JavaCompiler} from './java.js';
@@ -103,9 +102,7 @@ export class D8Compiler extends BaseCompiler implements SimpleOutputFilenameComp
let outputFilename = '';
let initialResult: CompilationResult | null = null;
const javaCompiler = global.handler_config.compileHandler.findCompiler('java', this.javaId) as
| JavaCompiler
| undefined;
const javaCompiler = this.env.findCompiler('java', this.javaId) as JavaCompiler | undefined;
if (!javaCompiler) {
return {
...this.handleUserError(
@@ -137,9 +134,7 @@ export class D8Compiler extends BaseCompiler implements SimpleOutputFilenameComp
javaCompiler.getDefaultExecOptions(),
);
} else if (this.lang.id === 'android-kotlin') {
const kotlinCompiler = unwrap(
global.handler_config.compileHandler.findCompiler('kotlin', this.kotlinId),
) as KotlinCompiler;
const kotlinCompiler = unwrap(this.env.findCompiler('kotlin', this.kotlinId)) as KotlinCompiler;
outputFilename = kotlinCompiler.getOutputFilename(preliminaryCompilePath);
const kotlinOptions = _.compact(
kotlinCompiler.prepareArguments(
@@ -217,9 +212,7 @@ export class D8Compiler extends BaseCompiler implements SimpleOutputFilenameComp
async generateSmali(outputFilename: string, maxSize: number) {
const dirPath = path.dirname(outputFilename);
const javaCompiler = unwrap(
global.handler_config.compileHandler.findCompiler('java', this.javaId),
) as JavaCompiler;
const javaCompiler = unwrap(this.env.findCompiler('java', this.javaId)) as JavaCompiler;
// There is only one dex file for all classes.
let files = await fs.readdir(dirPath);

View File

@@ -161,9 +161,7 @@ export class Dex2OatCompiler extends BaseCompiler {
// Instantiate D8 compiler, which will in turn instantiate a Java or
// Kotlin compiler based on the current language.
const d8Compiler = global.handler_config.compileHandler.findCompiler(this.lang.id, this.d8Id) as
| D8Compiler
| undefined;
const d8Compiler = this.env.findCompiler(this.lang.id, this.d8Id) as D8Compiler | undefined;
if (!d8Compiler) {
return {
...this.handleUserError(

View File

@@ -36,7 +36,6 @@ import {SimpleOutputFilenameCompiler} from '../base-compiler.js';
import {CompilationEnvironment} from '../compilation-env.js';
import {logger} from '../logger.js';
import '../global.js';
import {D8Compiler} from './d8.js';
import {JavaCompiler} from './java.js';
import {KotlinCompiler} from './kotlin.js';
@@ -64,9 +63,7 @@ export class R8Compiler extends D8Compiler implements SimpleOutputFilenameCompil
let outputFilename = '';
let initialResult: CompilationResult | null = null;
const javaCompiler = unwrap(
global.handler_config.compileHandler.findCompiler('java', this.javaId),
) as JavaCompiler;
const javaCompiler = unwrap(this.env.findCompiler('java', this.javaId)) as JavaCompiler;
// Instantiate Java or Kotlin compiler based on the current language.
if (this.lang.id === 'android-java') {
@@ -89,9 +86,7 @@ export class R8Compiler extends D8Compiler implements SimpleOutputFilenameCompil
javaCompiler.getDefaultExecOptions(),
);
} else if (this.lang.id === 'android-kotlin') {
const kotlinCompiler = unwrap(
global.handler_config.compileHandler.findCompiler('kotlin', this.kotlinId),
) as KotlinCompiler;
const kotlinCompiler = unwrap(this.env.findCompiler('kotlin', this.kotlinId)) as KotlinCompiler;
outputFilename = kotlinCompiler.getOutputFilename(preliminaryCompilePath);
const kotlinOptions = _.compact(
kotlinCompiler.prepareArguments(

View File

@@ -47,7 +47,7 @@ export class WyrmCompiler extends BaseCompiler {
getGcc(): BaseCompiler {
if (!this.gcc) {
this.gcc = unwrap(global.handler_config.compileHandler.findCompiler('c', this.gccId));
this.gcc = unwrap(this.env.findCompiler('c', this.gccId));
}
return unwrap(this.gcc);
}

View File

@@ -1,32 +0,0 @@
// 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 {HandlerConfig} from './handlers/route-api.js';
declare global {
// var is required
var handler_config: HandlerConfig;
/* eslint-enable no-var */
}