Skip to content

Commit

Permalink
Merge pull request #298 from aminya/compiler-sync [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya authored Sep 19, 2024
2 parents 5d12f41 + e4f89db commit 037f22b
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 33 deletions.
2 changes: 1 addition & 1 deletion dist/legacy/setup-cpp.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/legacy/setup-cpp.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/modern/setup-cpp.mjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/modern/setup-cpp.mjs.map

Large diffs are not rendered by default.

40 changes: 38 additions & 2 deletions src/__tests__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,39 @@ describe("getCompilerInfo", () => {
})
})

describe("getCompilerInfo", () => {
it("getCompilerInfo with semver", () => {
const { compiler, version } = getCompilerInfo("llvm-12.0.0")
expect(compiler).toBe("llvm")
expect(version).toBe("12.0.0")
})

it("getCompilerInfo with major version", () => {
const { compiler, version } = getCompilerInfo("llvm-12")
expect(compiler).toBe("llvm")
expect(version).toBe("12")
})

it("getCompilerInfo without version", () => {
const { compiler, version } = getCompilerInfo("llvm")
expect(compiler).toBe("llvm")
expect(version).toBeUndefined()
})
})

describe("syncVersion", () => {
it("Syncs llvm tools versions", () => {
expect(syncVersions(parseArgs(["--llvm", "14.0.0", "--clangtidy", "true"]), llvmTools as Inputs[])).toBe(true)
expect(syncVersions(parseArgs(["--llvm", "13.0.0", "--clangtidy", "true"]), llvmTools as Inputs[])).toBe(true)
expect(syncVersions(parseArgs(["--compiler", "llvm-13.0.0", "--clangtidy", "true"]), llvmTools as Inputs[])).toBe(
true,
)
expect(syncVersions(parseArgs(["--llvm", "13.0.0", "--clangtidy", "12.0.0"]), llvmTools as Inputs[])).toBe(false)

const opts1 = parseArgs(["--llvm", "14.0.0", "--clangtidy", "true"])
expect(syncVersions(opts1, llvmTools as Inputs[])).toBe(true)
expect(opts1.llvm).toBe(opts1.clangtidy)
expect(opts1.llvm).toBe("14.0.0")
expect(opts1.clangtidy).toBe("14.0.0")
expect(opts1.clangformat).toBe(undefined)

const opts2 = parseArgs(["--clangtidy", "15.0.0", "--clangformat", "true"])
Expand All @@ -45,8 +69,20 @@ describe("syncVersion", () => {
const opts3 = parseArgs(["--llvm", "true", "--clangformat", "true"])
expect(syncVersions(opts3, llvmTools as Inputs[])).toBe(true)
expect(opts3.llvm).toBe("true")
expect(opts3.clangtidy).toBe(undefined)
expect(opts3.clangformat).toBe("true")
expect(opts3.clangtidy).toBe(undefined)

const opts4 = parseArgs(["--compiler", "llvm-13.0.0", "--clangtidy", "true"])
expect(syncVersions(opts4, [...llvmTools, "compiler"] as Inputs[], getCompilerInfo("llvm-13.0.0"))).toBe(true)
expect(opts4.compiler).toBe("llvm-13.0.0")
expect(opts4.clangtidy).toBe("13.0.0")
expect(opts4.clangformat).toBe(undefined)

const opts5 = parseArgs(["--compiler", "gcc-13", "--clangtidy", "true"])
expect(syncVersions(opts5, [...llvmTools, "compiler"] as Inputs[], getCompilerInfo("gcc-13"))).toBe(true)
expect(opts5.compiler).toBe("gcc-13")
expect(opts5.clangtidy).toBe("true")
expect(opts5.clangformat).toBe(undefined)
})
})

Expand Down
14 changes: 9 additions & 5 deletions src/compilers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import { appleClangSetups, gccSetups, llvmSetups, mingwSetups, msvcSetups } from
import type { InstallationInfo } from "./utils/setup/setupBin.js"
import { getVersion } from "./versions/versions.js"

export type CompilerInfo = {
compiler: string
version: string | undefined
}

/**
* Detecting the compiler version. Divide the given string by `-` and use the second element as the version
*
Expand All @@ -20,7 +25,7 @@ import { getVersion } from "./versions/versions.js"
*
* @nothrow It doesn't throw any error, but it logs the error if it fails to parse the compiler info
*/
export function getCompilerInfo(compilerAndVersion: string) {
export function getCompilerInfo(compilerAndVersion: string): CompilerInfo {
try {
const compilerAndMaybeVersion = compilerAndVersion.split("-")
const compiler = compilerAndMaybeVersion[0]
Expand All @@ -40,15 +45,14 @@ export function getCompilerInfo(compilerAndVersion: string) {

/** Installing the specified compiler */
export async function installCompiler(
compilerAndVersion: string,
compiler: string,
version: string | undefined,
osVersion: number[] | null,
setupCppDir: string,
arch: string,
successMessages: string[],
errorMessages: string[],
) {
const { compiler, version } = getCompilerInfo(compilerAndVersion)

let installationInfo: InstallationInfo | undefined | void | null // null means the compiler is not supported
try {
// install the compiler. We allow some aliases for the compiler name
Expand Down Expand Up @@ -82,7 +86,7 @@ export async function installCompiler(
}
} catch (err) {
error(err as string | Error)
errorMessages.push(`Failed to install the ${compilerAndVersion}`)
errorMessages.push(`Failed to install the ${compiler} ${version}`)
}

if (installationInfo !== null) {
Expand Down
37 changes: 21 additions & 16 deletions src/setup-cpp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import timeDeltaLocale from "time-delta/locales/en.js"
import { untildifyUser } from "untildify-user"
import { checkUpdates } from "./check-updates.js"
import { parseArgs, printHelp, rcOptions } from "./cli-options.js"
import { installCompiler } from "./compilers.js"
import { getCompilerInfo, installCompiler } from "./compilers.js"
import { installTool } from "./installTool.js"
import { type Inputs, llvmTools, tools } from "./tool.js"
import { isArch } from "./utils/env/isArch.js"
Expand Down Expand Up @@ -55,8 +55,10 @@ async function main(args: string[]): Promise<number> {

const osVersion = await ubuntuVersion()

const compilerInfo = opts.compiler !== undefined ? getCompilerInfo(opts.compiler) : undefined

// sync the version for the llvm tools
if (!syncVersions(opts, llvmTools as Inputs[])) {
if (!syncVersions(opts, [...llvmTools, "compiler"] as Inputs[], compilerInfo)) {
error("The same version must be used for llvm, clang-format and clang-tidy")
return 1
}
Expand All @@ -71,11 +73,9 @@ async function main(args: string[]): Promise<number> {
let failedFast = false
for (const tool of tools) {
// fail fast inside CI when any tool fails
if (isCI) {
if (errorMessages.length !== 0) {
failedFast = true
break
}
if (isCI && errorMessages.length !== 0) {
failedFast = true
break
}

// get the version or "true" or undefined for this tool from the options
Expand All @@ -101,15 +101,20 @@ async function main(args: string[]): Promise<number> {
}
}

if (!failedFast) {
// installing the specified compiler
const maybeCompiler = opts.compiler
if (maybeCompiler !== undefined) {
const time1Compiler = Date.now()
await installCompiler(maybeCompiler, osVersion, setupCppDir, arch, successMessages, errorMessages)
const time2Compiler = Date.now()
info(`took ${timeFormatter.format(time1Compiler, time2Compiler) || "0 seconds"}`)
}
if (!failedFast && compilerInfo !== undefined) {
// install the specified compiler
const time1Compiler = Date.now()
await installCompiler(
compilerInfo.compiler,
compilerInfo.version,
osVersion,
setupCppDir,
arch,
successMessages,
errorMessages,
)
const time2Compiler = Date.now()
info(`took ${timeFormatter.format(time1Compiler, time2Compiler) || "0 seconds"}`)
}

await finalizeRC(rcOptions)
Expand Down
51 changes: 45 additions & 6 deletions src/versions/versions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Opts } from "../cli-options.js"
import type { CompilerInfo } from "../compilers.js"
import type { Inputs } from "../tool.js"
import { DefaultUbuntuVersion, DefaultVersions } from "./default_versions.js"

Expand Down Expand Up @@ -34,21 +35,59 @@ function getDefaultLinuxVersion(osVersion: number[], toolLinuxVersions: Record<n
/**
* Sync the versions for the given inputs
*
* It modifies the opts object to have the same version for all the tools
* If the return is false, it means that versions don't match the target version
* @param opts - The options object (modified in place)
* @param tools - The tools to sync the versions for (it can include `compiler`)
* @param compilerInfo - The compiler info to sync the versions for (if any)
*/
export function syncVersions(opts: Opts, tools: Inputs[]): boolean {
export function syncVersions(
opts: Opts,
toolsGiven: Inputs[],
compilerInfo: CompilerInfo | undefined = undefined,
): boolean {
// check if compiler version should be synced
const syncCompiler = compilerInfo === undefined ? false : toolsGiven.includes(compilerInfo.compiler as Inputs)

// remove the compiler from the tools if it should not be synced
const tools = syncCompiler ? toolsGiven : toolsGiven.filter((tool) => tool !== "compiler")

// filter out the tools that are in use in the options
const toolsInUse = tools.filter((tool) => opts[tool] !== undefined)
const toolsNonDefaultVersion = toolsInUse.filter((tool) => !isVersionDefault(opts[tool]))

const targetVersion = toolsNonDefaultVersion.length >= 1 ? opts[toolsNonDefaultVersion[0]] : "true"
// filter out the tools that are not default
const toolsNonDefaultVersion = toolsInUse.filter((tool) => {
const version = (syncCompiler && tool === "compiler" && compilerInfo !== undefined)
? compilerInfo.version
: opts[tool]
return !isVersionDefault(version)
})

// find the target version to sync to
const targetVersion: string = (toolsNonDefaultVersion.length !== 0)
? (syncCompiler && toolsNonDefaultVersion[0] === "compiler" && compilerInfo !== undefined)
? compilerInfo.version ?? "true"
: opts[toolsNonDefaultVersion[0]] ?? "true"
: "true"

// error if any explicit versions don't match the target version
if (
toolsNonDefaultVersion.some((tool) => {
if (syncCompiler && tool === "compiler" && compilerInfo !== undefined) {
return opts.compiler !== `${compilerInfo.compiler}-${targetVersion}`
}

if (toolsNonDefaultVersion.some((tool) => opts[tool] !== targetVersion)) {
// error if any explicit versions don't match the target version
return opts[tool] !== targetVersion
})
) {
return false
}

// update the version of all the tools to the target version
for (const tool of toolsInUse) {
opts[tool] = targetVersion
opts[tool] = (syncCompiler && tool === "compiler" && compilerInfo !== undefined)
? `${compilerInfo.compiler}-${targetVersion}`
: targetVersion
}

return true
Expand Down

0 comments on commit 037f22b

Please sign in to comment.