setup-cpp/src/gcc/gcc.ts

273 lines
12 KiB
TypeScript
Raw Normal View History

import { addEnv, addPath } from "os-env"
2024-04-03 15:15:43 +08:00
import { GITHUB_ACTIONS } from "ci-info"
import { info, warning } from "ci-log"
2024-08-07 14:44:32 +08:00
import type { ExecaReturnValue } from "execa"
2024-04-03 15:15:43 +08:00
import { pathExists } from "path-exists"
import { addExeExt, join } from "patha"
import semverCoerce from "semver/functions/coerce"
2024-04-03 15:15:43 +08:00
import semverMajor from "semver/functions/major"
import { rcOptions } from "../cli-options.js"
import { setupMacOSSDK } from "../macos-sdk/macos-sdk.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 { setupAptPack, updateAptAlternatives } from "../utils/setup/setupAptPack.js"
import { type InstallationInfo, type PackageInfo, setupBin } from "../utils/setup/setupBin.js"
import { setupBrewPack } from "../utils/setup/setupBrewPack.js"
import { setupChocoPack } from "../utils/setup/setupChocoPack.js"
import { setupDnfPack } from "../utils/setup/setupDnfPack.js"
import { setupPacmanPack } from "../utils/setup/setupPacmanPack.js"
interface MingwInfo {
releaseName: string
fileSuffix: string
}
// https://github.com/brechtsanders/winlibs_mingw/releases
const GccToMingwInfo = {
"13": { releaseName: "13.2.0-16.0.6-11.0.0-ucrt-r1", fileSuffix: "13.2.0-mingw-w64ucrt-11.0.0-r1" },
"13.2-ucrt": { releaseName: "13.2.0-16.0.6-11.0.0-ucrt-r1", fileSuffix: "13.2.0-mingw-w64ucrt-11.0.0-r1" },
"13.2-ucrt-mcf": { releaseName: "13.2.0mcf-16.0.6-11.0.1-ucrt-r2", fileSuffix: "13.2.0-mingw-w64ucrt-11.0.1-r2" },
"13.2-msvcrt": { releaseName: "13.2.0-16.0.6-11.0.1-msvcrt-r1", fileSuffix: "13.2.0-mingw-w64msvcrt-11.0.1-r1" },
2023-05-24 12:10:03 +08:00
"13.1-ucrt": { releaseName: "13.1.0posix-16.0.3-11.0.0-ucrt-r1", fileSuffix: "13.1.0-mingw-w64ucrt-11.0.0-r1" },
"13.1-msvcrt": { releaseName: "13.1.0posix-16.0.3-11.0.0-msvcrt-r1", fileSuffix: "13.1.0-mingw-w64msvcrt-11.0.0-r1" },
"12": { releaseName: "12.3.0-16.0.4-11.0.0-ucrt-r1", fileSuffix: "12.3.0-mingw-w64ucrt-11.0.0-r1" },
"12.3.0-ucrt": { releaseName: "12.3.0-16.0.4-11.0.0-ucrt-r1", fileSuffix: "12.3.0-mingw-w64ucrt-11.0.0-r1" },
"12.3.0-msvcrt": { releaseName: "12.3.0-16.0.4-11.0.0-msvcrt-r1", fileSuffix: "12.3.0-mingw-w64msvcrt-11.0.0-r1" },
2022-11-21 08:25:37 +08:00
"12.2.0-ucrt": { releaseName: "12.2.0-14.0.6-10.0.0-ucrt-r2", fileSuffix: "12.2.0-mingw-w64ucrt-10.0.0-r2" },
"12.2.0-msvcrt": { releaseName: "12.2.0-14.0.6-10.0.0-msvcrt-r2", fileSuffix: "12.2.0-mingw-w64msvcrt-10.0.0-r2" },
2022-06-10 03:02:41 +08:00
"12.1.0-ucrt": { releaseName: "12.1.0-14.0.4-10.0.0-ucrt-r2", fileSuffix: "12.1.0-mingw-w64ucrt-10.0.0-r2" },
"12.1.0-msvcrt": {
releaseName: "12.1.0-14.0.6-10.0.0-msvcrt-r3",
fileSuffix: "12.1.0-llvm-14.0.6-mingw-w64msvcrt-10.0.0-r3",
},
"11": { releaseName: "11.3.0-14.0.3-10.0.0-ucrt-r3", fileSuffix: "11.3.0-mingw-w64ucrt-10.0.0-r3" },
"11.3.0-ucrt": { releaseName: "11.3.0-14.0.3-10.0.0-ucrt-r3", fileSuffix: "11.3.0-mingw-w64ucrt-10.0.0-r3" },
"11.3.0-msvcrt": { releaseName: "11.3.0-14.0.3-10.0.0-msvcrt-r3", fileSuffix: "11.3.0-mingw-w64msvcrt-10.0.0-r3" },
"11.2.0-ucrt": { releaseName: "11.2.0-9.0.0-ucrt-r5", fileSuffix: "11.2.0-mingw-w64ucrt-9.0.0-r5" },
"11.2.0-msvcrt": { releaseName: "11.2.0-9.0.0-msvcrt-r5", fileSuffix: "11.2.0-mingw-w64msvcrt-9.0.0-r5" },
"10": { releaseName: "10.5.0-11.0.1-msvcrt-r1", fileSuffix: "10.5.0-mingw-w64msvcrt-11.0.1-r1" },
"10.5.0-msvcrt": { releaseName: "10.5.0-11.0.1-msvcrt-r1", fileSuffix: "10.5.0-mingw-w64msvcrt-11.0.1-r1" },
"10.3.0": { releaseName: "10.3.0-12.0.0-9.0.0-r2", fileSuffix: "10.3.0-llvm-12.0.0-mingw-w64-9.0.0-r2" },
"10.2.0": { releaseName: "10.2.0-7.0.0-r4", fileSuffix: "10.2.0-llvm-10.0.1-mingw-w64-7.0.0-r4" },
"9": { releaseName: "9.4.0-9.0.0-r1", fileSuffix: "9.4.0-mingw-w64-9.0.0-r1" },
"9.4.0": { releaseName: "9.4.0-9.0.0-r1", fileSuffix: "9.4.0-mingw-w64-9.0.0-r1" },
} as Record<string, MingwInfo | undefined>
function getGccPackageInfo(version: string, platform: NodeJS.Platform, arch: string): PackageInfo {
switch (platform) {
case "win32": {
const mingwInfo = GccToMingwInfo[version]
if (mingwInfo === undefined) {
throw new Error(`mingw version ${version} is not supported`)
}
const mingwArch = arch === "ia32" ? "i686" : "x86_64"
const exceptionModel: "seh" | "dwarf" = "seh" // SEH is native windows exception model https://github.com/brechtsanders/winlibs_mingw/issues/4#issuecomment-599296483
return {
2022-05-21 08:07:25 +08:00
binRelativeDir: "bin/",
binFileName: addExeExt("g++"),
extractedFolderName: "mingw64",
extractFunction: extract7Zip,
2024-04-03 15:15:43 +08:00
url:
`https://github.com/brechtsanders/winlibs_mingw/releases/download/${mingwInfo.releaseName}/winlibs-${mingwArch}-posix-${exceptionModel}-gcc-${mingwInfo.fileSuffix}.7z`,
}
}
default:
throw new Error(`Unsupported platform '${platform}'`)
}
}
2021-09-16 22:03:54 +08:00
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export async function setupGcc(version: string, setupDir: string, arch: string, priority: number = 40) {
let installationInfo: InstallationInfo | undefined
2021-09-16 22:03:54 +08:00
switch (process.platform) {
case "win32": {
if (arch === "arm" || arch === "arm64") {
await setupChocoPack("gcc-arm-embedded", version)
2021-09-16 22:03:54 +08:00
}
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
2021-09-16 22:03:54 +08:00
}
case "darwin": {
installationInfo = await setupBrewPack("gcc", version)
break
2021-09-16 22:03:54 +08:00
}
case "linux": {
if (arch === "x64") {
2022-06-30 10:06:33 +08:00
if (isArch()) {
installationInfo = await setupPacmanPack("gcc", version)
} else if (hasDnf()) {
installationInfo = await setupDnfPack([
{ name: "gcc", version },
{ name: "gcc-c++", version },
{ name: "libstdc++-devel" },
])
} else if (isUbuntu()) {
installationInfo = await setupAptPack([
{ name: "gcc", version, repositories: ["ppa:ubuntu-toolchain-r/test"] },
{ name: "g++", version, repositories: ["ppa:ubuntu-toolchain-r/test"] },
])
}
2021-09-17 06:00:14 +08:00
} else {
2021-09-17 06:17:32 +08:00
info(`Install g++-multilib because gcc for ${arch} was requested`)
2022-06-30 10:06:33 +08:00
if (isArch()) {
2023-05-25 05:57:08 +08:00
await setupPacmanPack("gcc-multilib", version)
} else if (isUbuntu()) {
await setupAptPack([{ name: "gcc-multilib", version, repositories: ["ppa:ubuntu-toolchain-r/test"] }])
}
2021-09-16 22:03:54 +08:00
}
break
2021-09-16 22:03:54 +08:00
}
// TODO support bare-metal (need to support passing it as the input)
2021-09-16 22:03:54 +08:00
// TODO support abi
// case "none": {
// if (arch === "arm" || arch === "arm64") {
// return setupAptPack("gcc-arm-none-eabi", version, [
2021-12-07 20:16:31 +08:00
// "ppa:ubuntu-toolchain-r/test",
// ])
2021-09-16 22:03:54 +08:00
// } else {
// throw new Error(`Unsupported platform for ${arch}`)
// }
// }
default: {
throw new Error(`Unsupported platform for ${arch}`)
}
}
if (installationInfo !== undefined) {
await activateGcc(version, installationInfo.binDir, priority)
return installationInfo
}
return undefined
2021-09-16 22:03:54 +08:00
}
2021-09-20 20:25:41 +08:00
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export async function setupMingw(version: string, setupDir: string, arch: string) {
let installationInfo: InstallationInfo | undefined
switch (process.platform) {
case "win32":
case "darwin": {
return setupGcc(version, setupDir, arch)
}
case "linux": {
if (isArch()) {
2023-07-20 06:26:55 +08:00
installationInfo = await setupPacmanPack("mingw-w64-gcc", version)
} else if (hasDnf()) {
2023-07-20 17:44:13 +08:00
installationInfo = await setupDnfPack([{ name: "mingw64-gcc", version }])
} else if (isUbuntu()) {
installationInfo = await setupAptPack([
{ name: "mingw-w64", version, repositories: ["ppa:ubuntu-toolchain-r/test"] },
])
}
break
}
default: {
throw new Error(`Unsupported platform for ${arch}`)
}
}
if (installationInfo !== undefined) {
// TODO: setup alternatives and update CC/CXX env. ?
2024-04-03 15:15:43 +08:00
// 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
2024-04-03 15:15:43 +08:00
// 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
2024-04-03 15:15:43 +08:00
// await activateGcc(version, installationInfo.binDir)
return installationInfo
}
return undefined
}
async function setupChocoMingw(version: string, arch: string): Promise<InstallationInfo | undefined> {
2022-05-21 06:19:19 +08:00
await setupChocoPack("mingw", version)
let binDir: string | undefined
if (arch === "x64" && (await pathExists("C:/tools/mingw64/bin"))) {
2022-05-21 06:19:19 +08:00
binDir = "C:/tools/mingw64/bin"
await addPath(binDir, rcOptions)
} else if (arch === "ia32" && (await pathExists("C:/tools/mingw32/bin"))) {
2022-05-21 06:19:19 +08:00
binDir = "C:/tools/mingw32/bin"
await addPath(binDir, rcOptions)
} else if (await pathExists(`${process.env.ChocolateyInstall ?? "C:/ProgramData/chocolatey"}/bin/g++.exe`)) {
2022-05-21 06:19:19 +08:00
binDir = `${process.env.ChocolateyInstall ?? "C:/ProgramData/chocolatey"}/bin`
}
if (binDir !== undefined) {
return { binDir }
}
return undefined
2022-05-21 06:19:19 +08:00
}
async function activateGcc(version: string, binDir: string, priority: number = 40) {
2023-05-25 05:57:08 +08:00
const promises: Promise<void | ExecaReturnValue<string>>[] = []
// Setup gcc as the compiler
2021-09-20 20:25:41 +08:00
// TODO
// const ld = process.env.LD_LIBRARY_PATH ?? ""
// const dyld = process.env.DYLD_LIBRARY_PATH ?? ""
// promises.push(
// addEnv("LD_LIBRARY_PATH", `${installDir}/lib${path.delimiter}${ld}`, rcOptions),
// addEnv("DYLD_LIBRARY_PATH", `${installDir}/lib${path.delimiter}${dyld}`, rcOptions),
// addEnv("CPATH", `${installDir}/lib/gcc/${majorVersion}/include`, rcOptions),
// addEnv("LDFLAGS", `-L${installDir}/lib`, rcOptions),
// addEnv("CPPFLAGS", `-I${installDir}/include`, rcOptions),
// )
2021-09-20 20:25:41 +08:00
if (process.platform === "win32") {
promises.push(
addEnv("CC", addExeExt(`${binDir}/gcc`), rcOptions),
addEnv("CXX", addExeExt(`${binDir}/g++`), rcOptions),
)
2021-09-20 20:25:41 +08:00
} else {
2021-12-07 20:16:31 +08:00
const majorVersion = semverMajor(semverCoerce(version) ?? version)
if (majorVersion >= 5) {
promises.push(
addEnv("CC", `${binDir}/gcc-${majorVersion}`, rcOptions),
addEnv("CXX", `${binDir}/g++-${majorVersion}`, rcOptions),
)
if (isUbuntu()) {
promises.push(
updateAptAlternatives("cc", `${binDir}/gcc-${majorVersion}`, rcOptions.rcPath, priority),
updateAptAlternatives("cxx", `${binDir}/g++-${majorVersion}`, rcOptions.rcPath, priority),
updateAptAlternatives("gcc", `${binDir}/gcc-${majorVersion}`, rcOptions.rcPath, priority),
updateAptAlternatives("g++", `${binDir}/g++-${majorVersion}`, rcOptions.rcPath, priority),
)
}
2021-12-07 20:16:31 +08:00
} else {
promises.push(
addEnv("CC", `${binDir}/gcc-${version}`, rcOptions),
addEnv("CXX", `${binDir}/g++-${version}`, rcOptions),
)
if (isUbuntu()) {
promises.push(
updateAptAlternatives("cc", `${binDir}/gcc-${version}`, rcOptions.rcPath, priority),
updateAptAlternatives("cxx", `${binDir}/g++-${version}`, rcOptions.rcPath, priority),
updateAptAlternatives("gcc", `${binDir}/gcc-${version}`, rcOptions.rcPath, priority),
updateAptAlternatives("g++", `${binDir}/g++-${version}`, rcOptions.rcPath, priority),
)
}
2021-12-07 20:16:31 +08:00
}
2021-09-20 20:25:41 +08:00
}
2021-11-22 01:06:16 +08:00
promises.push(setupMacOSSDK())
if (GITHUB_ACTIONS) {
await addGccLoggingMatcher()
}
await Promise.all(promises)
}
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}`)
2021-09-20 20:25:41 +08:00
}