mirror of https://github.com/aminya/setup-cpp.git
refactor: refactor llvm install into modules
This commit is contained in:
parent
57e4acf400
commit
935a8bc14f
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
135
src/llvm/llvm.ts
135
src/llvm/llvm.ts
|
|
@ -1,32 +1,24 @@
|
|||
import { tmpdir } from "os"
|
||||
import path, { delimiter, join } from "path"
|
||||
import { fileURLToPath } from "url"
|
||||
import { execRootSync } from "admina"
|
||||
import ciInfo from "ci-info"
|
||||
const { GITHUB_ACTIONS } = ciInfo
|
||||
import { info, warning } from "ci-log"
|
||||
import { addEnv } from "envosman"
|
||||
import memoize from "memoizee"
|
||||
import { DownloaderHelper } from "node-downloader-helper"
|
||||
import { pathExists } from "path-exists"
|
||||
import { addExeExt } from "patha"
|
||||
import { addUpdateAlternativesToRc, installAptPack } from "setup-apt"
|
||||
import { addUpdateAlternativesToRc } from "setup-apt"
|
||||
import { rcOptions } from "../cli-options.js"
|
||||
import { setupGcc } from "../gcc/gcc.js"
|
||||
import { setupMacOSSDK } from "../macos-sdk/macos-sdk.js"
|
||||
import { arm64, x86_64 } from "../utils/env/arch.js"
|
||||
import { hasDnf } from "../utils/env/hasDnf.js"
|
||||
import { isArch } from "../utils/env/isArch.js"
|
||||
import { isUbuntu } from "../utils/env/isUbuntu.js"
|
||||
import { ubuntuVersion } from "../utils/env/ubuntu_version.js"
|
||||
import { type InstallationInfo, setupBin } from "../utils/setup/setupBin.js"
|
||||
import { setupDnfPack } from "../utils/setup/setupDnfPack.js"
|
||||
import { setupPacmanPack } from "../utils/setup/setupPacmanPack.js"
|
||||
import { semverCoerceIfInvalid } from "../utils/setup/version.js"
|
||||
import type { InstallationInfo } from "../utils/setup/setupBin.js"
|
||||
import { quoteIfHasSpace } from "../utils/std/index.js"
|
||||
import { getVersion } from "../versions/versions.js"
|
||||
import { LLVMPackages, setupLLVMApt } from "./llvm_installer.js"
|
||||
import { getLLVMPackageInfo } from "./llvm_url.js"
|
||||
import { LLVMPackages, trySetupLLVMApt } from "./llvm_apt_installer.js"
|
||||
import { setupLLVMBin } from "./llvm_bin.js"
|
||||
import { majorLLVMVersion } from "./utils.js"
|
||||
|
||||
const dirname = typeof __dirname === "string" ? __dirname : path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
|
|
@ -44,110 +36,34 @@ async function setupLLVMWithoutActivation_(version: string, setupDir: string, ar
|
|||
])
|
||||
|
||||
// install LLVM dependencies
|
||||
await setupLLVMDeps(arch)
|
||||
await setupGccForLLVM(arch)
|
||||
|
||||
return installationInfo
|
||||
}
|
||||
const setupLLVMWithoutActivation = memoize(setupLLVMWithoutActivation_, { promise: true })
|
||||
|
||||
/**
|
||||
* Setup clang-format
|
||||
*
|
||||
* This uses the LLVM installer on Ubuntu, and the LLVM binaries on other platforms
|
||||
*/
|
||||
export function setupClangFormat(version: string, setupDir: string, arch: string) {
|
||||
return setupLLVMOnly(version, setupDir, arch, LLVMPackages.ClangFormat)
|
||||
}
|
||||
|
||||
/** Setup llvm tools (clang tidy, etc.) without activating llvm and using it as the compiler */
|
||||
export function setupClangTools(version: string, setupDir: string, arch: string) {
|
||||
return setupLLVMOnly(version, setupDir, arch)
|
||||
}
|
||||
|
||||
async function setupLLVMOnly(
|
||||
version: string,
|
||||
setupDir: string,
|
||||
arch: string,
|
||||
packages: LLVMPackages = LLVMPackages.All,
|
||||
) {
|
||||
const majorVersion = majorLLVMVersion(version)
|
||||
if (isUbuntu()) {
|
||||
try {
|
||||
return await setupLLVMApt(majorVersion, packages)
|
||||
} catch (err) {
|
||||
info(`Failed to install llvm via system package manager ${err}. Trying to remove the repository`)
|
||||
try {
|
||||
execRootSync(join(dirname, "llvm_repo_remove.bash"), [`${majorVersion}`])
|
||||
} catch (removeErr) {
|
||||
info(`Failed to remove llvm repository ${removeErr}`)
|
||||
}
|
||||
}
|
||||
const aptInstallInfo = await trySetupLLVMApt(version, packages)
|
||||
if (aptInstallInfo !== undefined) {
|
||||
return aptInstallInfo
|
||||
}
|
||||
|
||||
const installationInfo = await setupBin("llvm", version, getLLVMPackageInfo, setupDir, arch)
|
||||
await llvmBinaryDeps(majorVersion)
|
||||
return installationInfo
|
||||
return setupLLVMBin(version, setupDir, arch)
|
||||
}
|
||||
|
||||
function majorLLVMVersion(version: string) {
|
||||
const coeredVersion = semverCoerceIfInvalid(version)
|
||||
return Number.parseInt(coeredVersion.split(".")[0], 10)
|
||||
}
|
||||
|
||||
async function llvmBinaryDeps_(_majorVersion: number) {
|
||||
if (isUbuntu()) {
|
||||
for (const dep of ["libtinfo5", "libtinfo6"]) {
|
||||
/* eslint-disable no-await-in-loop */
|
||||
try {
|
||||
await installAptPack([{ name: dep }])
|
||||
} catch (_err) {
|
||||
try {
|
||||
if (dep === "libtinfo5") {
|
||||
// Manually install libtinfo5 if the package is not available
|
||||
info(`Failed to install ${dep}\nManually installing the package`)
|
||||
const arch = x86_64.includes(process.arch)
|
||||
? "amd64"
|
||||
: arm64.includes(process.arch)
|
||||
? "arm64"
|
||||
: process.arch
|
||||
|
||||
const fileName = `libtinfo5_6.3-2ubuntu0.1_${arch}.deb`
|
||||
const url = `http://launchpadlibrarian.net/666971015/${fileName}`
|
||||
const dl = new DownloaderHelper(url, tmpdir(), { fileName })
|
||||
dl.on("error", async (dlErr) => {
|
||||
info(`Failed to download ${url}: ${dlErr}`)
|
||||
await dl.stop()
|
||||
})
|
||||
await dl.start()
|
||||
// Install the downloaded package via dpkg
|
||||
execRootSync("dpkg", ["-i", join(tmpdir(), fileName)])
|
||||
}
|
||||
} catch (_errFallback) {
|
||||
info(`Failed to install ${dep}. Ignoring`)
|
||||
}
|
||||
}
|
||||
/* eslint-enable no-await-in-loop */
|
||||
}
|
||||
} else if (isArch()) {
|
||||
// https://aur.archlinux.org/packages/ncurses5-compat-libs
|
||||
await setupPacmanPack("ncurses5-compat-libs", undefined, "yay")
|
||||
} else if (hasDnf()) {
|
||||
// https://packages.fedoraproject.org/pkgs/ncurses/ncurses-compat-libs/index.html
|
||||
await setupDnfPack([
|
||||
{ name: "ncurses-compat-libs" },
|
||||
])
|
||||
}
|
||||
}
|
||||
const llvmBinaryDeps = memoize(llvmBinaryDeps_, { promise: true })
|
||||
|
||||
async function setupLLVMDeps_(arch: string) {
|
||||
async function setupGccForLLVM_(arch: string) {
|
||||
if (process.platform === "linux") {
|
||||
// using llvm requires ld, an up to date libstdc++, etc. So, install gcc first,
|
||||
// but with a lower priority than the one used by activateLLVM()
|
||||
await setupGcc(getVersion("gcc", undefined, await ubuntuVersion()), "", arch, 40)
|
||||
}
|
||||
}
|
||||
const setupLLVMDeps = memoize(setupLLVMDeps_, { promise: true })
|
||||
const setupGccForLLVM = memoize(setupGccForLLVM_, { promise: true })
|
||||
|
||||
export async function activateLLVM(directory: string, version: string) {
|
||||
const ld = process.env.LD_LIBRARY_PATH ?? ""
|
||||
|
|
@ -201,11 +117,26 @@ export async function activateLLVM(directory: string, version: string) {
|
|||
}
|
||||
|
||||
async function addLLVMLoggingMatcher() {
|
||||
if (GITHUB_ACTIONS) {
|
||||
const matcherPath = join(dirname, "llvm_matcher.json")
|
||||
if (!(await pathExists(matcherPath))) {
|
||||
return warning("the llvm_matcher.json file does not exist in the same folder as setup-cpp.js")
|
||||
}
|
||||
info(`::add-matcher::${matcherPath}`)
|
||||
if (!GITHUB_ACTIONS) {
|
||||
return
|
||||
}
|
||||
const matcherPath = join(dirname, "llvm_matcher.json")
|
||||
if (!(await pathExists(matcherPath))) {
|
||||
return warning("the llvm_matcher.json file does not exist in the same folder as setup-cpp.js")
|
||||
}
|
||||
info(`::add-matcher::${matcherPath}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup clang-format
|
||||
*
|
||||
* This uses the LLVM installer on Ubuntu, and the LLVM binaries on other platforms
|
||||
*/
|
||||
export function setupClangFormat(version: string, setupDir: string, arch: string) {
|
||||
return setupLLVMOnly(version, setupDir, arch, LLVMPackages.ClangFormat)
|
||||
}
|
||||
|
||||
/** Setup llvm tools (clang tidy, etc.) without activating llvm and using it as the compiler */
|
||||
export function setupClangTools(version: string, setupDir: string, arch: string) {
|
||||
return setupLLVMOnly(version, setupDir, arch)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
import { info } from "console"
|
||||
import { tmpdir } from "os"
|
||||
import { join } from "path"
|
||||
import { execRoot } from "admina"
|
||||
import path, { join } from "path"
|
||||
import { fileURLToPath } from "url"
|
||||
import { execRoot, execRootSync } from "admina"
|
||||
import { addPath } from "envosman"
|
||||
import { chmod, readFile, writeFile } from "fs/promises"
|
||||
import { DownloaderHelper } from "node-downloader-helper"
|
||||
import { aptTimeout, hasNala, installAddAptRepo, installAptPack, isAptPackRegexInstalled } from "setup-apt"
|
||||
import { rcOptions } from "../cli-options.js"
|
||||
import { DEFAULT_TIMEOUT } from "../installTool.js"
|
||||
import { isUbuntu } from "../utils/env/isUbuntu.js"
|
||||
import type { InstallationInfo } from "../utils/setup/setupBin.js"
|
||||
import { majorLLVMVersion } from "./utils.js"
|
||||
const dirname = typeof __dirname === "string" ? __dirname : path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
export enum LLVMPackages {
|
||||
All = 0,
|
||||
|
|
@ -16,10 +20,52 @@ export enum LLVMPackages {
|
|||
Core = 2,
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to setup LLVM via the apt package manager
|
||||
*
|
||||
* @param {string} version - The version of LLVM to install
|
||||
* @param {LLVMPackages} packages - The packages to install
|
||||
*
|
||||
* @returns {InstallationInfo} The installation info if the installation was successful
|
||||
* @returns {undefined} If the installation fails, it will try to remove the repository and will return undefined
|
||||
*/
|
||||
export async function trySetupLLVMApt(
|
||||
version: string,
|
||||
packages: LLVMPackages = LLVMPackages.All,
|
||||
): Promise<InstallationInfo | undefined> {
|
||||
if (!isUbuntu()) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
try {
|
||||
return await setupLLVMApt(version, packages)
|
||||
} catch (err) {
|
||||
info(`Failed to install llvm via system package manager ${err}. Trying to remove the repository`)
|
||||
try {
|
||||
execRootSync(join(dirname, "llvm_repo_remove.bash"), [`${majorLLVMVersion(version)}`])
|
||||
} catch (removeErr) {
|
||||
info(`Failed to remove llvm repository ${removeErr}`)
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup LLVM via the apt package manager
|
||||
*
|
||||
* @note assumes this is running on an Ubuntu/Debian system
|
||||
*
|
||||
* @param {string} version - The version of LLVM to install
|
||||
* @param {LLVMPackages} packages - The packages to install
|
||||
*
|
||||
* @returns {InstallationInfo} The installation info if the installation was successful
|
||||
*/
|
||||
export async function setupLLVMApt(
|
||||
majorVersion: number,
|
||||
version: string,
|
||||
packages: LLVMPackages = LLVMPackages.All,
|
||||
): Promise<InstallationInfo> {
|
||||
const majorVersion = majorLLVMVersion(version)
|
||||
|
||||
// TODO for older versions, this also includes the minor version
|
||||
const installationFolder = `/usr/lib/llvm-${majorVersion}`
|
||||
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
import { tmpdir } from "os"
|
||||
import { join } from "path"
|
||||
import { execRootSync } from "admina"
|
||||
import { info } from "ci-log"
|
||||
import memoize from "memoizee"
|
||||
import { DownloaderHelper } from "node-downloader-helper"
|
||||
import { installAptPack } from "setup-apt"
|
||||
import { arm64, x86_64 } from "../utils/env/arch.js"
|
||||
import { hasDnf } from "../utils/env/hasDnf.js"
|
||||
import { isArch } from "../utils/env/isArch.js"
|
||||
import { isUbuntu } from "../utils/env/isUbuntu.js"
|
||||
import { setupBin } from "../utils/setup/setupBin.js"
|
||||
import { setupDnfPack } from "../utils/setup/setupDnfPack.js"
|
||||
import { setupPacmanPack } from "../utils/setup/setupPacmanPack.js"
|
||||
import { getLLVMPackageInfo } from "./llvm_url.js"
|
||||
import { majorLLVMVersion } from "./utils.js"
|
||||
|
||||
export async function setupLLVMBin(version: string, setupDir: string, arch: string) {
|
||||
const installInfo = await setupBin("llvm", version, getLLVMPackageInfo, setupDir, arch)
|
||||
await llvmBinaryDeps(majorLLVMVersion(version))
|
||||
return installInfo
|
||||
}
|
||||
|
||||
async function llvmBinaryDeps_(_majorVersion: number) {
|
||||
if (isUbuntu()) {
|
||||
for (const dep of ["libtinfo5", "libtinfo6"]) {
|
||||
/* eslint-disable no-await-in-loop */
|
||||
try {
|
||||
await installAptPack([{ name: dep }])
|
||||
} catch (_err) {
|
||||
try {
|
||||
if (dep === "libtinfo5") {
|
||||
// Manually install libtinfo5 if the package is not available
|
||||
info(`Failed to install ${dep}\nManually installing the package`)
|
||||
const arch = x86_64.includes(process.arch)
|
||||
? "amd64"
|
||||
: arm64.includes(process.arch)
|
||||
? "arm64"
|
||||
: process.arch
|
||||
|
||||
const fileName = `libtinfo5_6.3-2ubuntu0.1_${arch}.deb`
|
||||
const url = `http://launchpadlibrarian.net/666971015/${fileName}`
|
||||
const dl = new DownloaderHelper(url, tmpdir(), { fileName })
|
||||
dl.on("error", async (dlErr) => {
|
||||
info(`Failed to download ${url}: ${dlErr}`)
|
||||
await dl.stop()
|
||||
})
|
||||
await dl.start()
|
||||
// Install the downloaded package via dpkg
|
||||
execRootSync("dpkg", ["-i", join(tmpdir(), fileName)])
|
||||
}
|
||||
} catch (_errFallback) {
|
||||
info(`Failed to install ${dep}. Ignoring`)
|
||||
}
|
||||
}
|
||||
/* eslint-enable no-await-in-loop */
|
||||
}
|
||||
} else if (isArch()) {
|
||||
// https://aur.archlinux.org/packages/ncurses5-compat-libs
|
||||
await setupPacmanPack("ncurses5-compat-libs", undefined, "yay")
|
||||
} else if (hasDnf()) {
|
||||
// https://packages.fedoraproject.org/pkgs/ncurses/ncurses-compat-libs/index.html
|
||||
await setupDnfPack([
|
||||
{ name: "ncurses-compat-libs" },
|
||||
])
|
||||
}
|
||||
}
|
||||
const llvmBinaryDeps = memoize(llvmBinaryDeps_, { promise: true })
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import memoize from "memoizee"
|
||||
import { semverCoerceIfInvalid } from "../utils/setup/version.ts"
|
||||
function majorLLVMVersion_(version: string) {
|
||||
const coeredVersion = semverCoerceIfInvalid(version)
|
||||
return Number.parseInt(coeredVersion.split(".")[0], 10)
|
||||
}
|
||||
|
||||
export const majorLLVMVersion = memoize(majorLLVMVersion_)
|
||||
Loading…
Reference in New Issue