Merge pull request #306 from aminya/versions [skip ci]

This commit is contained in:
Amin Yahyaabadi 2024-09-22 23:11:24 -07:00 committed by GitHub
commit 9560b8d586
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 340 additions and 145 deletions

View File

@ -1,5 +1,11 @@
import { buildTerserOptions } from "terser-config-atomic/dist/builder.js" import { buildTerserOptions } from "terser-config-atomic/dist/builder.js"
const config = buildTerserOptions(process.env.NODE_ENV, undefined, true) const config = buildTerserOptions(process.env.NODE_ENV, undefined, true)
config.compress.unsafe_math = false
if (
typeof config.compress === "object"
&& "unsafe_math" in config.compress
) {
config.compress.unsafe_math = false
}
export default config export default config

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,8 @@ import { endGroup, startGroup } from "@actions/core"
import { error, info } from "ci-log" import { error, info } from "ci-log"
import semverValid from "semver/functions/valid" import semverValid from "semver/functions/valid"
import { getSuccessMessage } from "./cli-options.js" import { getSuccessMessage } from "./cli-options.js"
import { setupGcc, setupMingw } from "./gcc/gcc.js" import { setupGcc } from "./gcc/gcc.js"
import { setupMingw } from "./gcc/mingw.js"
import { activateGcovGCC, activateGcovLLVM } from "./gcovr/gcovr.js" import { activateGcovGCC, activateGcovLLVM } from "./gcovr/gcovr.js"
import { setupAppleClang } from "./llvm/apple-clang.js" import { setupAppleClang } from "./llvm/apple-clang.js"
import { setupLLVM } from "./llvm/llvm.js" import { setupLLVM } from "./llvm/llvm.js"

View File

@ -1,83 +1,34 @@
import path, { join } from "path" import path from "path"
import { fileURLToPath } from "url" import { fileURLToPath } from "url"
import { GITHUB_ACTIONS } from "ci-info" import { GITHUB_ACTIONS } from "ci-info"
import { error, info, warning } from "ci-log" import { error, info, warning } from "ci-log"
import { addEnv, addPath } from "envosman" import { addEnv } from "envosman"
import { execa } from "execa" import { execa } from "execa"
import { readdir } from "fs/promises" import { readdir } from "fs/promises"
import { pathExists } from "path-exists" import { pathExists } from "path-exists"
import { addExeExt } from "patha"
import semverCoerce from "semver/functions/coerce" import semverCoerce from "semver/functions/coerce"
import semverMajor from "semver/functions/major" import semverMajor from "semver/functions/major"
import { addUpdateAlternativesToRc, installAptPack } from "setup-apt" import { addUpdateAlternativesToRc, installAptPack } from "setup-apt"
import { installBrewPack } from "setup-brew" import { installBrewPack } from "setup-brew"
import { rcOptions } from "../cli-options.js" import { rcOptions } from "../cli-options.js"
import { setupMacOSSDK } from "../macos-sdk/macos-sdk.js" import { setupMacOSSDK } from "../macos-sdk/macos-sdk.js"
import { loadAssetList, matchAsset } from "../utils/asset/load-assets.js"
import { hasDnf } from "../utils/env/hasDnf.js" import { hasDnf } from "../utils/env/hasDnf.js"
import { isArch } from "../utils/env/isArch.js" import { isArch } from "../utils/env/isArch.js"
import { isUbuntu } from "../utils/env/isUbuntu.js" import { isUbuntu } from "../utils/env/isUbuntu.js"
import { extract7Zip } from "../utils/setup/extract.js" import type { InstallationInfo } from "../utils/setup/setupBin.js"
import { type InstallationInfo, type PackageInfo, setupBin } from "../utils/setup/setupBin.js"
import { setupChocoPack } from "../utils/setup/setupChocoPack.js"
import { setupDnfPack } from "../utils/setup/setupDnfPack.js" import { setupDnfPack } from "../utils/setup/setupDnfPack.js"
import { setupPacmanPack } from "../utils/setup/setupPacmanPack.js" import { setupPacmanPack } from "../utils/setup/setupPacmanPack.js"
import { compareVersion } from "../utils/setup/version.js" import { compareVersion } from "../utils/setup/version.js"
import { addGccLoggingMatcher } from "./gccMatcher.js"
import { setupMingw } from "./mingw.js"
const dirname = typeof __dirname === "string" ? __dirname : path.dirname(fileURLToPath(import.meta.url)) export const dirname = typeof __dirname === "string" ? __dirname : path.dirname(fileURLToPath(import.meta.url))
async function getGccPackageInfo(version: string, platform: NodeJS.Platform, arch: string): Promise<PackageInfo> {
switch (platform) {
case "win32": {
const mingwAssets = await loadAssetList(
join(dirname, "github_brechtsanders_winlibs_mingw.json"),
)
const mingwArchMap = {
x64: "x86_64",
ia32: "i386",
} as Record<string, string | undefined>
const asset = matchAsset(
mingwAssets,
{
version,
keywords: [
mingwArchMap[arch] ?? arch,
],
},
)
if (asset === undefined) {
throw new Error(`No asset found for version ${version} and arch ${arch}`)
}
return {
binRelativeDir: "bin/",
binFileName: addExeExt("g++"),
extractedFolderName: "mingw64",
extractFunction: extract7Zip,
url: `https://github.com/brechtsanders/winlibs_mingw/releases/download/${asset.tag}/${asset.name}`,
}
}
default:
throw new Error(`Unsupported platform '${platform}'`)
}
}
export async function setupGcc(version: string, setupDir: string, arch: string, priority: number = 40) { export async function setupGcc(version: string, setupDir: string, arch: string, priority: number = 40) {
let installationInfo: InstallationInfo | undefined let installationInfo: InstallationInfo | undefined
switch (process.platform) { switch (process.platform) {
case "win32": { case "win32": {
if (arch === "arm" || arch === "arm64") { installationInfo = await setupMingw(version, setupDir, arch)
await setupChocoPack("gcc-arm-embedded", version)
}
try {
installationInfo = await setupBin("g++", version, getGccPackageInfo, setupDir, arch)
} catch (err) {
info(`Failed to download g++ binary. ${err}. Falling back to chocolatey.`)
installationInfo = await setupChocoMingw(version, arch)
}
break break
} }
case "darwin": { case "darwin": {
@ -159,75 +110,18 @@ export async function setupGcc(version: string, setupDir: string, arch: string,
return undefined return undefined
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars /**
export async function setupMingw(version: string, setupDir: string, arch: string) { * Setup gcc as the compiler on Linux and macOS
let installationInfo: InstallationInfo | undefined */
switch (process.platform) {
case "win32":
case "darwin": {
return setupGcc(version, setupDir, arch)
}
case "linux": {
if (isArch()) {
installationInfo = await setupPacmanPack("mingw-w64-gcc", version)
} else if (hasDnf()) {
installationInfo = await setupDnfPack([{ name: "mingw64-gcc", version }])
} else if (isUbuntu()) {
installationInfo = await installAptPack([
{
name: "mingw-w64",
version,
repository: "ppa:ubuntu-toolchain-r/test",
key: { key: "1E9377A2BA9EF27F", fileName: "ubuntu-toolchain-r-test.gpg" },
},
])
}
break
}
default: {
throw new Error(`Unsupported platform for ${arch}`)
}
}
if (installationInfo !== undefined) {
// TODO: setup alternatives and update CC/CXX env. ?
// Setting up g++-mingw-w64-i686-win32 (10.3.0-14ubuntu1+24.3) ...
// update-alternatives: using /usr/bin/i686-w64-mingw32-g++-win32 to provide /usr/bin/i686-w64-mingw32-g++ (i686-w64-mingw32-g++) in auto mode
// Setting up g++-mingw-w64-x86-64-win32 (10.3.0-14ubuntu1+24.3) ...
// update-alternatives: using /usr/bin/x86_64-w64-mingw32-g++-win32 to provide /usr/bin/x86_64-w64-mingw32-g++ (x86_64-w64-mingw32-g++) in auto mode
// await activateGcc(version, installationInfo.binDir)
return installationInfo
}
return undefined
}
async function setupChocoMingw(version: string, arch: string): Promise<InstallationInfo | undefined> {
await setupChocoPack("mingw", version)
let binDir: string | undefined
if (arch === "x64" && (await pathExists("C:/tools/mingw64/bin"))) {
binDir = "C:/tools/mingw64/bin"
await addPath(binDir, rcOptions)
} else if (arch === "ia32" && (await pathExists("C:/tools/mingw32/bin"))) {
binDir = "C:/tools/mingw32/bin"
await addPath(binDir, rcOptions)
} else if (await pathExists(`${process.env.ChocolateyInstall ?? "C:/ProgramData/chocolatey"}/bin/g++.exe`)) {
binDir = `${process.env.ChocolateyInstall ?? "C:/ProgramData/chocolatey"}/bin`
}
if (binDir !== undefined) {
return { binDir }
}
return undefined
}
/** Setup gcc as the compiler */
async function activateGcc(givenVersion: string, binDir: string, priority: number = 40) { async function activateGcc(givenVersion: string, binDir: string, priority: number = 40) {
if (process.platform === "win32") {
// already done in setupMingw
return
}
const promises: Promise<void>[] = [] const promises: Promise<void>[] = []
if (process.platform === "win32") { {
promises.push(
addEnv("CC", addExeExt(`${binDir}/gcc`), rcOptions),
addEnv("CXX", addExeExt(`${binDir}/g++`), rcOptions),
)
} else {
// if version is empty, get the version from the gcc command // if version is empty, get the version from the gcc command
let version = givenVersion let version = givenVersion
if (givenVersion === "") { if (givenVersion === "") {
@ -329,11 +223,3 @@ async function getGccCmdVersion(binDir: string, givenVersion: string) {
return givenVersion return givenVersion
} }
} }
async function addGccLoggingMatcher() {
const matcherPath = join(dirname, "gcc_matcher.json")
if (!(await pathExists(matcherPath))) {
return warning("the gcc_matcher.json file does not exist in the same folder as setup-cpp.js")
}
info(`::add-matcher::${matcherPath}`)
}

12
src/gcc/gccMatcher.ts Normal file
View File

@ -0,0 +1,12 @@
import { join } from "path"
import { info, warning } from "ci-log"
import { pathExists } from "path-exists"
import { dirname } from "./gcc.ts"
export async function addGccLoggingMatcher() {
const matcherPath = join(dirname, "gcc_matcher.json")
if (!(await pathExists(matcherPath))) {
return warning("the gcc_matcher.json file does not exist in the same folder as setup-cpp.js")
}
info(`::add-matcher::${matcherPath}`)
}

217
src/gcc/mingw.ts Normal file
View File

@ -0,0 +1,217 @@
import path, { join } from "path"
import { fileURLToPath } from "url"
import { GITHUB_ACTIONS } from "ci-info"
import { info } from "ci-log"
import { addEnv, addPath } from "envosman"
import { pathExists } from "path-exists"
import { addExeExt } from "patha"
import semverCoerce from "semver/functions/coerce.js"
import semverSatisfies from "semver/functions/satisfies.js"
import { installAptPack } from "setup-apt"
import { rcOptions } from "../cli-options.js"
import { loadAssetList, matchAsset } from "../utils/asset/load-assets.js"
import { hasDnf } from "../utils/env/hasDnf.js"
import { isArch } from "../utils/env/isArch.js"
import { isUbuntu } from "../utils/env/isUbuntu.js"
import { extract7Zip } from "../utils/setup/extract.js"
import { type InstallationInfo, type PackageInfo, setupBin } from "../utils/setup/setupBin.js"
import { setupChocoPack } from "../utils/setup/setupChocoPack.js"
import { setupDnfPack } from "../utils/setup/setupDnfPack.js"
import { setupPacmanPack } from "../utils/setup/setupPacmanPack.js"
import { addGccLoggingMatcher } from "./gccMatcher.js"
const dirname = typeof __dirname === "string" ? __dirname : path.dirname(fileURLToPath(import.meta.url))
export async function setupMingw(version: string, setupDir: string, arch: string) {
let installationInfo: InstallationInfo | undefined
switch (process.platform) {
case "win32": {
if (arch === "arm" || arch === "arm64") {
installationInfo = await setupChocoPack("gcc-arm-embedded", version)
}
try {
installationInfo = await setupBin("g++", version, getMinGWPackageInfo, setupDir, arch)
} catch (err) {
info(`Failed to download g++ binary. ${err}. Falling back to chocolatey.`)
installationInfo = await setupChocoMingw(version, arch)
}
break
}
case "linux": {
if (isArch()) {
installationInfo = await setupPacmanPack("mingw-w64-gcc", version)
} else if (hasDnf()) {
installationInfo = await setupDnfPack([{ name: "mingw64-gcc", version }])
} else if (isUbuntu()) {
installationInfo = await installAptPack([
{
name: "mingw-w64",
version,
repository: "ppa:ubuntu-toolchain-r/test",
key: { key: "1E9377A2BA9EF27F", fileName: "ubuntu-toolchain-r-test.gpg" },
},
])
} else {
throw new Error(`Unsupported Linux distro for ${arch}`)
}
break
}
default: {
throw new Error(`Unsupported platform for ${arch}`)
}
}
if (installationInfo !== undefined) {
await activateMinGW(installationInfo.binDir)
}
return installationInfo
}
async function setupChocoMingw(version: string, arch: string): Promise<InstallationInfo | undefined> {
await setupChocoPack("mingw", version)
let binDir: string | undefined
if (arch === "x64" && (await pathExists("C:/tools/mingw64/bin"))) {
binDir = "C:/tools/mingw64/bin"
await addPath(binDir, rcOptions)
} else if (arch === "ia32" && (await pathExists("C:/tools/mingw32/bin"))) {
binDir = "C:/tools/mingw32/bin"
await addPath(binDir, rcOptions)
} else if (await pathExists(`${process.env.ChocolateyInstall ?? "C:/ProgramData/chocolatey"}/bin/g++.exe`)) {
binDir = `${process.env.ChocolateyInstall ?? "C:/ProgramData/chocolatey"}/bin`
}
if (binDir !== undefined) {
return { binDir }
}
return undefined
}
export async function getMinGWPackageInfo(
version: string,
platform: NodeJS.Platform,
arch: string,
): Promise<PackageInfo> {
if (platform !== "win32") {
throw new Error(`Unsupported platform '${platform}'`)
}
const mingwAssets = await loadAssetList(
join(dirname, "github_brechtsanders_winlibs_mingw.json"),
)
const mingwArchMap = {
x64: "x86_64",
ia32: "i386",
} as Record<string, string | undefined>
const runtime = extractMinGWRuntime(version)
const threadModel = extractMinGWThreadModel(version)
const exceptionModel = extractMingwExceptionModel(version)
const asset = matchAsset(
mingwAssets,
{
version,
keywords: [
mingwArchMap[arch] ?? arch,
],
filterName: (assetName) => {
return (runtime === undefined || runtime === extractMinGWRuntime(assetName))
&& (threadModel === undefined || threadModel === extractMinGWThreadModel(assetName))
&& (exceptionModel === undefined || exceptionModel === extractMingwExceptionModel(assetName))
},
versionSatisfies: (assetVersion, versionRange) => {
// extract the base version by coercing the version
const assetCoerce = semverCoerce(assetVersion)
if (assetCoerce === null) {
throw new Error(`Invalid MinGW asset version: '${assetVersion}'`)
}
// if the asset version is satisfied by the version
// and the runtime and thread model match or not specified
return semverSatisfies(assetCoerce, versionRange)
&& (runtime === undefined || runtime === extractMinGWRuntime(assetVersion))
&& (threadModel === undefined || threadModel === extractMinGWThreadModel(assetVersion))
},
},
)
if (asset === undefined) {
throw new Error(`No asset found for version ${version} and arch ${arch}`)
}
return {
binRelativeDir: "bin/",
binFileName: addExeExt("g++"),
extractedFolderName: "mingw64",
extractFunction: extract7Zip,
url: `https://github.com/brechtsanders/winlibs_mingw/releases/download/${asset.tag}/${asset.name}`,
}
}
/**
* Extract the runtime used by the MinGW asset/version
* @param input The input to extract the runtime from
*
* @example
* extractMinGWRuntime("14.2.0posix-18.1.8-12.0.0-ucrt-r1") // "ucrt"
* extractMinGWRuntime("10.5.0-11.0.1-msvcrt-r2") // "msvcrt"
* extractMinGWRuntime("11.1.0-12.0.0-9.0.0-r1") // undefined
*/
function extractMinGWRuntime(input: string) {
const match = input.match(/(ucrt|msvcrt)/)
return match !== null ? match[1] : undefined
}
/**
* Extract the thread model used by the MinGW asset/version
* @param input The input to extract the thread model from
*
* @example
* extractMinGWThreadModel("14.2.0posix-18.1.8-12.0.0-ucrt-r1") // "posix"
* extractMinGWThreadModel("14.2.0mcf-12.0.0-ucrt-r1") // "mcf"
* extractMinGWThreadModel("10.5.0-11.0.1-msvcrt-r2") // undefined
* extractMinGWThreadModel("11.1.0-12.0.0-9.0.0-r1") // undefined
*/
function extractMinGWThreadModel(input: string) {
const match = input.match(/(posix|mcf)/)
return match !== null ? match[1] : undefined
}
/**
* Extract the exception model used by the MinGW asset/version
*
* @param input The input to extract the exception model from
*
* @example
* extractMingwExceptionModel("14.2.0posix-18.1.8-12.0.0-ucrt-r1") // "seh"
* extractMingwExceptionModel("14.2.0mcf-12.0.0-ucrt-r1") // undefined
* extractMingwExceptionModel("10.5.0-11.0.1-msvcrt-r2") // "dwarf"
*/
function extractMingwExceptionModel(input: string) {
const match = input.match(/(seh|dwarf)/)
return match !== null ? match[1] : undefined
}
async function activateMinGW(binDir: string) {
const promises: Promise<void>[] = []
if (process.platform === "win32") {
promises.push(
addEnv("CC", addExeExt(`${binDir}/gcc`), rcOptions),
addEnv("CXX", addExeExt(`${binDir}/g++`), rcOptions),
)
}
// TODO add update-alternatives for Ubuntu
// Setting up g++-mingw-w64-i686-win32 (10.3.0-14ubuntu1+24.3) ...
// update-alternatives: using /usr/bin/i686-w64-mingw32-g++-win32 to provide /usr/bin/i686-w64-mingw32-g++ (i686-w64-mingw32-g++) in auto mode
// Setting up g++-mingw-w64-x86-64-win32 (10.3.0-14ubuntu1+24.3) ...
// update-alternatives: using /usr/bin/x86_64-w64-mingw32-g++-win32 to provide /usr/bin/x86_64-w64-mingw32-g++ (x86_64-w64-mingw32-g++) in auto mode
if (GITHUB_ACTIONS) {
await addGccLoggingMatcher()
}
await Promise.all(promises)
}

View File

@ -9,7 +9,8 @@ import { setupCppcheck } from "./cppcheck/cppcheck.js"
import { setupCpplint } from "./cpplint/cpplint.js" import { setupCpplint } from "./cpplint/cpplint.js"
import { setupDoxygen } from "./doxygen/doxygen.js" import { setupDoxygen } from "./doxygen/doxygen.js"
import { setupFlawfinder } from "./flawfinder/flawfinder.js" import { setupFlawfinder } from "./flawfinder/flawfinder.js"
import { setupGcc, setupMingw } from "./gcc/gcc.js" import { setupGcc } from "./gcc/gcc.js"
import { setupMingw } from "./gcc/mingw.js"
import { setupGcovr } from "./gcovr/gcovr.js" import { setupGcovr } from "./gcovr/gcovr.js"
import { setupGraphviz } from "./graphviz/graphviz.js" import { setupGraphviz } from "./graphviz/graphviz.js"
import { setupInfer } from "./infer/infer.js" import { setupInfer } from "./infer/infer.js"

View File

@ -1,4 +1,6 @@
import { readFile } from "fs/promises" import { readFile } from "fs/promises"
import semverSatisfies from "semver/functions/satisfies.js"
import { semverCoercedRangeIfInvalid } from "../setup/version.ts"
/** /**
* The list of assets * The list of assets
@ -15,16 +17,56 @@ export async function loadAssetList(path: string): Promise<Assets> {
return JSON.parse(data) return JSON.parse(data)
} }
type MatchAssetOpts = { /**
* The options to match the asset
*/
export type MatchAssetOpts = {
/**
* The version to match
*/
version: string version: string
/**
* The keywords that must be in the asset name
* @default []
*/
keywords?: string[] keywords?: string[]
/**
* Optional keywords that are not required to be in the asset name
* but increase the score of the asset if they are present
* @default []
*/
optionalKeywords?: string[] optionalKeywords?: string[]
/**
* Custom version compare function
* @param candidate The candidate version
* @param coeredVersion The coerced version to compare against
* @returns true if the candidate version satisfies the version
*
* @default semverSatisfies
*/
versionSatisfies?: (candidate: string, coeredVersion: string) => boolean
/**
* Custom tag filter and map function
* @param tag The tag to filter and map
* @returns The mapped tag or undefined if the tag should be
* excluded from the search
* @default undefined
*/
filterMapTag?: (tag: string) => string | undefined filterMapTag?: (tag: string) => string | undefined
/**
* Custom asset name filter function
* @param asset The asset name to filter
* @returns true if the asset should be included in the search
* @default undefined
*/
filterName?: (asset: string) => boolean filterName?: (asset: string) => boolean
} }
/** /**
* Match the asset that matches the version and given keywords * Match the asset that matches the version and given keywords
* @param assets The list of assets
* @param opts The options to match the asset
* @returns The tag and name of the asset that matches the version and keywords
*/ */
export function matchAsset( export function matchAsset(
assets: Assets, assets: Assets,
@ -52,11 +94,17 @@ export function matchAsset(
return undefined return undefined
} }
// Assume the version is a semver version if a custom version compare function is not given
const versionSatisfies: (c: string, v: string) => boolean = opts.versionSatisfies ?? semverSatisfies
// If not a valid semver version, coerce it to a semver version range
const versionRange = semverCoercedRangeIfInvalid(opts.version)
// find the first tag that starts with the version // find the first tag that starts with the version
// loop over the versions starting with the latest // loop over the versions starting with the latest
const candidateTags: string[] = [] const candidateTags: string[] = []
for (const [version, origTag] of versionMap.entries()) { for (const [version, origTag] of versionMap.entries()) {
if (version.startsWith(opts.version)) { if (versionSatisfies(version, versionRange)) {
candidateTags.push(origTag) candidateTags.push(origTag)
} }
} }

View File

@ -137,6 +137,31 @@ export function semverCoerceIfInvalid(version: string) {
return version return version
} }
/**
* Coerce the given version to a semver range if it is invalid
*/
export function semverCoercedRangeIfInvalid(version: string) {
if (semverValid(version) === null) {
// version coercion
try {
// find the semver version of an integer
const coercedVersion = semverCoerce(version)
if (coercedVersion !== null) {
// if the versions doesn't specify a range specifier (e.g. ^, ~, >, <, etc.), add a ^ to the version
const versionRange = /^[<=>^~]/.test(coercedVersion.version)
? coercedVersion.version
: `^${coercedVersion.version}`
info(`Coerced version '${version}' to '${versionRange}'`)
return versionRange
}
} catch (err) {
// handled below
}
}
return version
}
export function removeVPrefix(version: string) { export function removeVPrefix(version: string) {
return Number.parseInt(version.replace(/^v/, ""), 10) return Number.parseInt(version.replace(/^v/, ""), 10)
} }

View File

@ -18,13 +18,12 @@ export const DefaultVersions: Record<string, string | undefined> = {
"clang-format": defaultLLVM, "clang-format": defaultLLVM,
clangformat: defaultLLVM, clangformat: defaultLLVM,
ninja: "1.12.1", // https://github.com/ninja-build/ninja/releases ninja: "1.12.1", // https://github.com/ninja-build/ninja/releases
cmake: "3.30.2", // https://github.com/Kitware/CMake/releases cmake: "3.30.3", // https://github.com/Kitware/CMake/releases
gcovr: "5.2", // "6.0", // https://pypi.org/project/gcovr/ conan: "1.65.0", // 2.7.1 // https://github.com/conan-io/conan/releases
conan: "1.64.1", // 2.0.17 // https://github.com/conan-io/conan/releases meson: "1.5.2", // https://github.com/mesonbuild/meson/releases
meson: "1.5.1", // https://github.com/mesonbuild/meson/releases
kcov: "42", // https://github.com/SimonKagstrom/kcov/releases kcov: "42", // https://github.com/SimonKagstrom/kcov/releases
task: "3.38.0", // https://github.com/go-task/task/releases task: "3.39.2", // https://github.com/go-task/task/releases
doxygen: isArch() ? "1.11.0-4" : "1.11.0", // https://www.doxygen.nl/download.html // https://packages.ubuntu.com/search?suite=all&arch=any&searchon=names&keywords=doxygen // https://formulae.brew.sh/formula/doxygen // https://archlinux.org/packages/extra/x86_64/doxygen/ doxygen: isArch() ? "1.12.0-2" : "1.12.0", // https://www.doxygen.nl/download.html // https://packages.ubuntu.com/search?suite=all&arch=any&searchon=names&keywords=doxygen // https://formulae.brew.sh/formula/doxygen // https://archlinux.org/packages/extra/x86_64/doxygen/
gcc: process.platform === "win32" gcc: process.platform === "win32"
? "14.2.0posix-18.1.8-12.0.0-ucrt-r1" ? "14.2.0posix-18.1.8-12.0.0-ucrt-r1"
: "", // use the default version on Ubuntu, Fedora, Arch, macOS, etc. : "", // use the default version on Ubuntu, Fedora, Arch, macOS, etc.