mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2026-05-17 08:24:24 -04:00
## Summary - Fixed `delayCleanupTemp: any` → `boolean` - Fixed `toolchainPath: any` → `string | undefined` - Changed `getToolchainPath()` to return `string | undefined` instead of `string | false` (more idiomatic TypeScript) - Fixed a latent bug in `changeOptionsBasedOnOverrides` ### Bug fix details The bug was introduced in commit079d49575("Compiler overrides #5001") on May 16, 2023. The original **correct** code (from commit86a84f7f6) was: ```typescript let sysrootPath: string | undefined; const overriddenToolchainPath = this.getOverridenToolchainPath(overrides); if (overriddenToolchainPath) { sysrootPath = getSysrootByToolchainPath(overriddenToolchainPath); } ``` The buggy refactor changed it to: ```typescript const sysrootPath = overriddenToolchainPath ?? getSysrootByToolchainPath(overriddenToolchainPath); ``` This had two issues: 1. **The fallback was never reached**: `false ?? x` returns `false` because `false` is not nullish (only `null`/`undefined` trigger `??`) 2. **The fallback passed the wrong variable**: It passed `overriddenToolchainPath` to the fallback, but when the fallback is needed, that variable would be `false`/`undefined` Fixed to match the original correct behaviour: ```typescript const sysrootPath = overriddenToolchainPath ? getSysrootByToolchainPath(overriddenToolchainPath) : this.toolchainPath ? getSysrootByToolchainPath(this.toolchainPath) : undefined; ``` The sysroot is now always computed via `getSysrootByToolchainPath()`, since toolchain paths (e.g. `/opt/compiler-explorer/gcc-7.2.0`) differ from sysroot paths (e.g. `/opt/compiler-explorer/gcc-7.2.0/x86_64-pc-linux-gnu/sysroot`). ## Test plan - [x] `npm run ts-check` passes - [x] `npm run test-min` passes - [x] Pre-commit hooks pass 🤖 Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
159 lines
6.1 KiB
TypeScript
159 lines
6.1 KiB
TypeScript
// Copyright (c) 2020, 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 fs from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
import {splitArguments} from '../shared/common-utils.js';
|
|
import {CompilerOverrideOptions} from '../types/compilation/compiler-overrides.interfaces.js';
|
|
import {PreliminaryCompilerInfo} from '../types/compiler.interfaces.js';
|
|
|
|
export const clang_style_toolchain_flag = '--gcc-toolchain=';
|
|
export const icc_style_toolchain_flag = '--gxx-name=';
|
|
export const clang_style_sysroot_flag = '--sysroot=';
|
|
|
|
export function getToolchainPathWithOptionsArr(compilerExe: string | null, options: string[]): string | undefined {
|
|
const existingChain = options.find(elem => elem.includes(clang_style_toolchain_flag));
|
|
if (existingChain) return existingChain.substring(16);
|
|
|
|
const gxxname = options.find(elem => elem.includes(icc_style_toolchain_flag));
|
|
if (gxxname) {
|
|
return path.resolve(path.dirname(gxxname.substring(11)), '..');
|
|
}
|
|
if (typeof compilerExe === 'string' && (compilerExe.includes('/g++') || compilerExe.endsWith('-g++'))) {
|
|
return path.resolve(path.dirname(compilerExe), '..');
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
export function getToolchainPath(compilerExe: string | null, compilerOptions?: string): string | undefined {
|
|
const options = compilerOptions ? splitArguments(compilerOptions) : [];
|
|
return getToolchainPathWithOptionsArr(compilerExe, options);
|
|
}
|
|
|
|
export function removeToolchainArg(compilerOptions: string[]): string[] {
|
|
return compilerOptions.filter(
|
|
elem => !elem.includes(clang_style_toolchain_flag) && !elem.includes(icc_style_toolchain_flag),
|
|
);
|
|
}
|
|
|
|
export function removeSysrootArg(compilerOptions: string[]): string[] {
|
|
return compilerOptions.filter(elem => !elem.includes(clang_style_sysroot_flag));
|
|
}
|
|
|
|
export function replaceToolchainArg(compilerOptions: string[], newPath: string): string[] {
|
|
return compilerOptions.map(elem => {
|
|
if (elem.includes(clang_style_toolchain_flag)) {
|
|
return clang_style_toolchain_flag + path.normalize(newPath);
|
|
}
|
|
if (elem.includes(icc_style_toolchain_flag)) {
|
|
return icc_style_toolchain_flag + path.normalize(newPath);
|
|
}
|
|
|
|
return elem;
|
|
});
|
|
}
|
|
|
|
export function replaceSysrootArg(compilerOptions: string[], newPath: string): string[] {
|
|
return compilerOptions.map(elem => {
|
|
if (elem.includes(clang_style_sysroot_flag)) {
|
|
return clang_style_sysroot_flag + path.normalize(newPath);
|
|
}
|
|
|
|
return elem;
|
|
});
|
|
}
|
|
|
|
export function getToolchainFlagFromOptions(options: string[]): string | false {
|
|
for (const elem of options) {
|
|
if (elem.includes(clang_style_toolchain_flag)) return clang_style_toolchain_flag;
|
|
if (elem.includes(icc_style_toolchain_flag)) return icc_style_toolchain_flag;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
export function hasToolchainArg(options: string[]): boolean {
|
|
return !!getToolchainFlagFromOptions(options);
|
|
}
|
|
|
|
export function getSysrootFlagFromOptions(options: string[]): string | false {
|
|
for (const elem of options) {
|
|
if (elem.includes(clang_style_sysroot_flag)) return clang_style_sysroot_flag;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
export function hasSysrootArg(options: string[]): boolean {
|
|
return !!getSysrootFlagFromOptions(options);
|
|
}
|
|
|
|
export async function getPossibleGccToolchainsFromCompilerInfo(
|
|
compilers: PreliminaryCompilerInfo[],
|
|
): Promise<CompilerOverrideOptions> {
|
|
const overrideOptions: CompilerOverrideOptions = [];
|
|
for (const compiler of compilers) {
|
|
if (
|
|
compiler.compilerCategories?.includes('gcc') &&
|
|
!compiler.compilerCategories?.includes('mingw') &&
|
|
!compiler.hidden &&
|
|
compiler.exe &&
|
|
path.isAbsolute(compiler.exe)
|
|
) {
|
|
try {
|
|
await fs.promises.stat(compiler.exe);
|
|
} catch {
|
|
continue;
|
|
}
|
|
|
|
const toolchainPath = path.resolve(path.dirname(compiler.exe), '..');
|
|
if (!overrideOptions.find(opt => opt.value === toolchainPath)) {
|
|
overrideOptions.push({
|
|
name: compiler.name,
|
|
value: toolchainPath,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return overrideOptions;
|
|
}
|
|
|
|
export function getSpecificTargetBasedOnToolchainPath(target: string, toolchainPath: string) {
|
|
const lastPathBit = path.basename(toolchainPath);
|
|
if (lastPathBit.startsWith(target)) {
|
|
return lastPathBit;
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
export function getSysrootByToolchainPath(toolchainPath: string): string | undefined {
|
|
const lastPathBit = path.basename(toolchainPath);
|
|
const possibleSysrootPath = path.join(toolchainPath, lastPathBit, 'sysroot');
|
|
if (fs.existsSync(possibleSysrootPath)) {
|
|
return possibleSysrootPath;
|
|
}
|
|
}
|