mirror of https://github.com/aminya/setup-cpp.git
Merge pull request #367 from aminya/macos-llvm-installer
feat: install LLVM via brew on Mac if possible
This commit is contained in:
commit
65cf4fec22
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
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "setup-brew",
|
||||
"version": "1.0.2",
|
||||
"version": "1.1.0",
|
||||
"description": "Setup brew and brew packages",
|
||||
"repository": "https://github.com/aminya/setup-cpp",
|
||||
"homepage": "https://github.com/aminya/setup-cpp/tree/master/packages/setup-brew",
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import { join } from "path"
|
||||
import { info } from "ci-log"
|
||||
import { info, warning } from "ci-log"
|
||||
import { execaSync } from "execa"
|
||||
import which from "which"
|
||||
import type { InstallationInfo } from "./InstallationInfo.js"
|
||||
import type { BrewPackOptions } from "./install-pack-options.js"
|
||||
import { getBrewBinDir, setupBrew } from "./install.js"
|
||||
import { getBrewBinDir, getBrewBinPath, setupBrew } from "./install.js"
|
||||
import { brewPackInstallDir, brewPackNameAndVersion } from "./pack-install-dir.js"
|
||||
|
||||
/* eslint-disable require-atomic-updates */
|
||||
let hasBrew = false
|
||||
|
|
@ -36,14 +37,13 @@ export async function installBrewPack(
|
|||
hasBrew = true
|
||||
}
|
||||
|
||||
const binDir = getBrewBinDir()
|
||||
const brewPath = join(binDir, "brew")
|
||||
const brewPath = getBrewBinPath()
|
||||
|
||||
// Args
|
||||
const args = [
|
||||
"install",
|
||||
(version !== undefined && version !== "") ? `${name}@${version}` : name,
|
||||
brewPackNameAndVersion(name, version),
|
||||
]
|
||||
|
||||
// Add options to args
|
||||
for (const [key, value] of Object.entries(options)) {
|
||||
if (typeof value === "boolean" && value) {
|
||||
|
|
@ -56,5 +56,12 @@ export async function installBrewPack(
|
|||
// brew is not thread-safe
|
||||
execaSync(brewPath, args, { stdio: "inherit" })
|
||||
|
||||
return { binDir }
|
||||
const installDir = await brewPackInstallDir(name, version)
|
||||
|
||||
if (installDir === undefined) {
|
||||
warning(`Failed to find installation directory for ${name} ${version}`)
|
||||
return { binDir: getBrewBinDir(), installDir: undefined }
|
||||
}
|
||||
|
||||
return { installDir, binDir: join(installDir, "bin") }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,10 @@ export function getBrewBinDir() {
|
|||
return join(getBrewDir(), "bin")
|
||||
}
|
||||
|
||||
export function getBrewBinPath() {
|
||||
return join(getBrewBinDir(), "brew")
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path where brew is installed
|
||||
* @returns {string} The path where brew is installed
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
import { existsSync } from "fs"
|
||||
import { join } from "path"
|
||||
import { execa } from "execa"
|
||||
import { getBrewBinPath, getBrewDir } from "./install.js"
|
||||
|
||||
export function brewPackNameAndVersion(name: string, version: string | undefined) {
|
||||
return (version !== undefined && version !== "") ? `${name}@${version}` : name
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the installation directory of a package
|
||||
* @param name The name of the package
|
||||
* @param nameAndVersion The name and version of the package
|
||||
* @returns The installation directory of the package
|
||||
*/
|
||||
|
||||
export async function brewPackInstallDir(name: string, version: string | undefined) {
|
||||
const nameAndVersion = brewPackNameAndVersion(name, version)
|
||||
|
||||
// first try with --prefix
|
||||
const nameAndVersionPrefix = await getBrewPackPrefix(nameAndVersion)
|
||||
if (nameAndVersionPrefix !== undefined) {
|
||||
return nameAndVersionPrefix
|
||||
}
|
||||
|
||||
// try with --prefix name
|
||||
const namePrefix = await getBrewPackPrefix(name)
|
||||
if (namePrefix !== undefined) {
|
||||
return namePrefix
|
||||
}
|
||||
|
||||
// if that fails, try with searchInstallDir
|
||||
return searchInstallDir(name, nameAndVersion)
|
||||
}
|
||||
|
||||
async function getBrewPackPrefix(packArg: string) {
|
||||
try {
|
||||
const brewPath = getBrewBinPath()
|
||||
return (await execa(brewPath, ["--prefix", packArg], { stdio: "pipe" })).stdout
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Searches for the installation directory of a package
|
||||
* @param name The name of the package
|
||||
* @param nameAndVersion The name and version of the package
|
||||
* @returns The installation directory of the package
|
||||
*/
|
||||
function searchInstallDir(name: string, nameAndVersion: string) {
|
||||
const brewDir = getBrewDir()
|
||||
|
||||
// Check in opt directory (most common location)
|
||||
const nameAndVersionOptDir = join(brewDir, "opt", nameAndVersion)
|
||||
if (existsSync(nameAndVersionOptDir)) {
|
||||
return nameAndVersionOptDir
|
||||
}
|
||||
const nameOptDir = join(brewDir, "opt", name)
|
||||
if (existsSync(nameOptDir)) {
|
||||
return nameOptDir
|
||||
}
|
||||
|
||||
// Check in Cellar (where casks and some formulae are installed)
|
||||
const nameAndVersionCellarDir = join(brewDir, "Cellar", nameAndVersion)
|
||||
if (existsSync(nameAndVersionCellarDir)) {
|
||||
return nameAndVersionCellarDir
|
||||
}
|
||||
const nameCellarDir = join(brewDir, "Cellar", name)
|
||||
if (existsSync(nameCellarDir)) {
|
||||
return nameCellarDir
|
||||
}
|
||||
|
||||
// Check in lib directory
|
||||
const nameAndVersionLibDir = join(brewDir, "lib", nameAndVersion)
|
||||
if (existsSync(nameAndVersionLibDir)) {
|
||||
return nameAndVersionLibDir
|
||||
}
|
||||
const nameLibDir = join(brewDir, "lib", name)
|
||||
if (existsSync(nameLibDir)) {
|
||||
return nameLibDir
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
|
@ -18,29 +18,26 @@ import { quoteIfHasSpace } from "../utils/std/index.js"
|
|||
import { getVersion } from "../versions/versions.js"
|
||||
import { LLVMPackages, trySetupLLVMApt } from "./llvm_apt_installer.js"
|
||||
import { setupLLVMBin } from "./llvm_bin.js"
|
||||
import { trySetupLLVMBrew } from "./llvm_brew_installer.js"
|
||||
import { majorLLVMVersion } from "./utils.js"
|
||||
|
||||
const dirname = typeof __dirname === "string" ? __dirname : path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
export async function setupLLVM(version: string, setupDir: string, arch: string): Promise<InstallationInfo> {
|
||||
const installationInfo = await setupLLVMWithoutActivation(version, setupDir, arch)
|
||||
await activateLLVM(installationInfo.installDir ?? setupDir, version)
|
||||
return installationInfo
|
||||
}
|
||||
const installationInfo = await setupLLVMOnly(version, setupDir, arch)
|
||||
|
||||
async function setupLLVMWithoutActivation_(version: string, setupDir: string, arch: string) {
|
||||
// install LLVM
|
||||
const [installationInfo, _1] = await Promise.all([
|
||||
setupLLVMOnly(version, setupDir, arch),
|
||||
addLLVMLoggingMatcher(),
|
||||
])
|
||||
|
||||
// install LLVM dependencies
|
||||
// install gcc for LLVM (for ld, libstdc++, etc.)
|
||||
await setupGccForLLVM(arch)
|
||||
|
||||
// add the logging matcher
|
||||
await addLLVMLoggingMatcher()
|
||||
|
||||
// activate LLVM in the end
|
||||
if (installationInfo.installDir !== undefined) {
|
||||
await activateLLVM(installationInfo.installDir, version)
|
||||
}
|
||||
return installationInfo
|
||||
}
|
||||
const setupLLVMWithoutActivation = memoize(setupLLVMWithoutActivation_, { promise: true })
|
||||
|
||||
async function setupLLVMOnly(
|
||||
version: string,
|
||||
|
|
@ -53,6 +50,11 @@ async function setupLLVMOnly(
|
|||
return aptInstallInfo
|
||||
}
|
||||
|
||||
const brewInstallInfo = await trySetupLLVMBrew(version, setupDir, arch)
|
||||
if (brewInstallInfo !== undefined) {
|
||||
return brewInstallInfo
|
||||
}
|
||||
|
||||
return setupLLVMBin(version, setupDir, arch)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
import { warning } from "ci-log"
|
||||
import { addPath } from "envosman"
|
||||
import { installBrewPack } from "setup-brew"
|
||||
import { rcOptions } from "../cli-options.ts"
|
||||
import { majorLLVMVersion } from "./utils.ts"
|
||||
|
||||
export async function trySetupLLVMBrew(version: string, _setupDir: string, _arch: string) {
|
||||
if (process.platform !== "darwin") {
|
||||
return Promise.resolve(undefined)
|
||||
}
|
||||
|
||||
try {
|
||||
return await setupLLVMBrew(version, _setupDir, _arch)
|
||||
} catch (err) {
|
||||
warning(`Failed to install llvm via brew: ${err}`)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
export async function setupLLVMBrew(version: string, _setupDir: string, _arch: string) {
|
||||
const majorVersion = majorLLVMVersion(version)
|
||||
|
||||
// install llvm via brew if a bottle is available for it
|
||||
const installInfo = await installBrewPack("llvm", `${majorVersion}`, { "force-bottle": true })
|
||||
|
||||
// add the bin directory to the PATH
|
||||
await addPath(installInfo.binDir, rcOptions)
|
||||
|
||||
return installInfo
|
||||
}
|
||||
Loading…
Reference in New Issue