mirror of https://github.com/aminya/setup-cpp.git
340 lines
10 KiB
TypeScript
340 lines
10 KiB
TypeScript
import * as path from "path"
|
|
import semverLte from "semver/functions/lte"
|
|
import semverMajor from "semver/functions/major"
|
|
import { isValidUrl } from "../utils/http/validate_url"
|
|
import { InstallationInfo, PackageInfo, setupBin } from "../utils/setup/setupBin"
|
|
import { extractExe, extractTarByExe } from "../utils/setup/extract"
|
|
import { getSpecificVersionAndUrl, getVersions, semverCoerceIfInvalid } from "../utils/setup/version"
|
|
import { setupMacOSSDK } from "../macos-sdk/macos-sdk"
|
|
import { addBinExtension } from "../utils/extension/extension"
|
|
import { addEnv } from "../utils/env/addEnv"
|
|
import { setOutput } from "@actions/core"
|
|
import { setupAptPack, updateAptAlternatives } from "../utils/setup/setupAptPack"
|
|
import { info, warning } from "../utils/io/io"
|
|
import { existsSync } from "fs"
|
|
import { isGitHubCI } from "../utils/env/isci"
|
|
import { setupGcc } from "../gcc/gcc"
|
|
import { getVersion } from "../default_versions"
|
|
|
|
//================================================
|
|
// Version
|
|
//================================================
|
|
|
|
/** The specific and minimum LLVM versions supported by this action. */
|
|
export const VERSIONS: Set<string> = getVersions([
|
|
"3.5.0",
|
|
"3.5.1",
|
|
"3.5.2",
|
|
"3.6.0",
|
|
"3.6.1",
|
|
"3.6.2",
|
|
"3.7.0",
|
|
"3.7.1",
|
|
"3.8.0",
|
|
"3.8.1",
|
|
"3.9.0",
|
|
"3.9.1",
|
|
"4.0.0",
|
|
"4.0.1",
|
|
"5.0.0",
|
|
"5.0.1",
|
|
"5.0.2",
|
|
"6.0.0",
|
|
"6.0.1",
|
|
"7.0.0",
|
|
"7.0.1",
|
|
"7.1.0",
|
|
"8.0.0",
|
|
"8.0.1",
|
|
"9.0.0",
|
|
"9.0.1",
|
|
"10.0.0",
|
|
"10.0.1",
|
|
"11.0.0",
|
|
"11.0.1",
|
|
"11.1.0",
|
|
"12.0.0",
|
|
"12.0.1",
|
|
"13.0.0",
|
|
"13.0.1",
|
|
"14.0.0",
|
|
"14.0.1",
|
|
])
|
|
|
|
//================================================
|
|
// URL
|
|
//================================================
|
|
|
|
/** Gets a LLVM download URL for GitHub. */
|
|
function getGitHubUrl(version: string, prefix: string, suffix: string): string {
|
|
const file = `${prefix}${version}${suffix}`
|
|
return `https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/${file}`
|
|
}
|
|
|
|
/** Gets a LLVM download URL for https://releases.llvm.org. */
|
|
function getReleaseUrl(version: string, prefix: string, suffix: string): string {
|
|
const file = `${prefix}${version}${suffix}`
|
|
return `https://releases.llvm.org/${version}/${file}`
|
|
}
|
|
|
|
/** The LLVM versions that were never released for the Darwin platform. */
|
|
const DARWIN_MISSING: Set<string> = new Set([
|
|
"3.5.1",
|
|
"3.6.1",
|
|
"3.6.2",
|
|
"3.7.1",
|
|
"3.8.1",
|
|
"3.9.1",
|
|
"6.0.1",
|
|
"7.0.1",
|
|
"7.1.0",
|
|
"8.0.1",
|
|
"11.0.1",
|
|
"11.1.0",
|
|
"12.0.1",
|
|
])
|
|
|
|
/** Gets an LLVM download URL for the Darwin platform. */
|
|
function getDarwinUrl(version: string): string | null {
|
|
if (DARWIN_MISSING.has(version)) {
|
|
return null
|
|
}
|
|
|
|
const darwin = version === "9.0.0" ? "-darwin-apple" : "-apple-darwin"
|
|
const prefix = "clang+llvm-"
|
|
const suffix = `-x86_64${darwin}.tar.xz`
|
|
if (semverLte(version, "9.0.1")) {
|
|
return getReleaseUrl(version, prefix, suffix)
|
|
} else {
|
|
return getGitHubUrl(version, prefix, suffix)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The LLVM versions that should use the last RC version instead of the release version for the Linux (Ubuntu) platform.
|
|
* This is useful when there were binaries released for the Linux (Ubuntu) platform for the last RC version but not for
|
|
* the actual release version.
|
|
*/
|
|
const UBUNTU_RC: Map<string, string> = new Map()
|
|
|
|
/**
|
|
* The (latest) Ubuntu versions for each LLVM version.
|
|
*
|
|
* https://github.com/llvm/llvm-project/releases/tag/llvmorg-14.0.1 or https://releases.llvm.org/14.0.1
|
|
*/
|
|
const UBUNTU_SUFFIX_MAP: { [key: string]: string } = {
|
|
"3.5.0": "-ubuntu-14.04",
|
|
"3.5.1": "",
|
|
"3.5.2": "-ubuntu-14.04",
|
|
"3.6.0": "-ubuntu-14.04",
|
|
"3.6.1": "-ubuntu-14.04",
|
|
"3.6.2": "-ubuntu-14.04",
|
|
"3.7.0": "-ubuntu-14.04",
|
|
"3.7.1": "-ubuntu-14.04",
|
|
"3.8.0": "-ubuntu-16.04",
|
|
"3.8.1": "-ubuntu-16.04",
|
|
"3.9.0": "-ubuntu-16.04",
|
|
"3.9.1": "-ubuntu-16.04",
|
|
"4.0.0": "-ubuntu-16.04",
|
|
"5.0.0": "-ubuntu16.04",
|
|
"5.0.1": "-ubuntu-16.04",
|
|
"5.0.2": "-ubuntu-16.04",
|
|
"6.0.0": "-ubuntu-16.04",
|
|
"6.0.1": "-ubuntu-16.04",
|
|
"7.0.0": "-ubuntu-16.04",
|
|
"7.0.1": "-ubuntu-18.04",
|
|
"7.1.0": "-ubuntu-14.04",
|
|
"8.0.0": "-ubuntu-18.04",
|
|
"9.0.0": "-ubuntu-18.04",
|
|
"9.0.1": "-ubuntu-16.04",
|
|
"10.0.0": "-ubuntu-18.04",
|
|
"10.0.1": "-ubuntu-16.04",
|
|
"11.0.0": "-ubuntu-20.04",
|
|
"11.0.1": "-ubuntu-16.04",
|
|
"11.1.0": "-ubuntu-16.04",
|
|
"12.0.0": "-ubuntu-20.04",
|
|
"12.0.1": "-ubuntu-16.04",
|
|
"13.0.0": "-ubuntu-20.04",
|
|
"13.0.1": "-ubuntu-18.04",
|
|
"14.0.0": "-ubuntu-18.04",
|
|
// "14.0.1": "-ubuntu-18.04", // only available for powerpc64le
|
|
}
|
|
|
|
/** The latest supported LLVM version for the Linux (Ubuntu) platform. */
|
|
const MAX_UBUNTU: string = "14.0.0"
|
|
|
|
/** Gets an LLVM download URL for the Linux (Ubuntu) platform. */
|
|
function getLinuxUrl(versionGiven: string): string {
|
|
let version = versionGiven
|
|
|
|
const rc = UBUNTU_RC.get(version)
|
|
if (rc !== undefined) {
|
|
version = rc
|
|
}
|
|
|
|
let ubuntu: string
|
|
// ubuntu-version is specified
|
|
if (version.includes("ubuntu")) {
|
|
ubuntu = version
|
|
} else if (version !== "" && version in UBUNTU_SUFFIX_MAP) {
|
|
ubuntu = UBUNTU_SUFFIX_MAP[version]
|
|
} else {
|
|
// default to the maximum version
|
|
ubuntu = UBUNTU_SUFFIX_MAP[MAX_UBUNTU]
|
|
}
|
|
|
|
const prefix = "clang+llvm-"
|
|
const suffix = version === "5.0.0" ? `-linux-x86_64${ubuntu}.tar.xz` : `-x86_64-linux-gnu${ubuntu}.tar.xz`
|
|
if (semverLte(version, "9.0.1")) {
|
|
return getReleaseUrl(version, prefix, suffix)
|
|
} else {
|
|
return getGitHubUrl(version, prefix, suffix)
|
|
}
|
|
}
|
|
|
|
/** The LLVM versions that were never released for the Windows platform. */
|
|
const WIN32_MISSING: Set<string> = new Set(["10.0.1"])
|
|
|
|
/** Gets an LLVM download URL for the Windows platform. */
|
|
async function getWin32Url(version: string): Promise<string | null> {
|
|
if (WIN32_MISSING.has(version)) {
|
|
return null
|
|
}
|
|
|
|
const prefix = "LLVM-"
|
|
const suffix = semverLte(version, "3.7.0") ? "-win32.exe" : "-win64.exe"
|
|
|
|
const olderThan9_1 = semverLte(version, "9.0.1")
|
|
let url: string
|
|
let fallback = false
|
|
if (olderThan9_1) {
|
|
url = getReleaseUrl(version, prefix, suffix)
|
|
if (!(await isValidUrl(url))) {
|
|
fallback = true // fallback to github
|
|
}
|
|
}
|
|
if (fallback || !olderThan9_1) {
|
|
url = getGitHubUrl(version, prefix, suffix)
|
|
}
|
|
|
|
return url!
|
|
}
|
|
|
|
/** Gets an LLVM download URL. */
|
|
export function getUrl(platform: string, version: string): string | null | Promise<string | null> {
|
|
switch (platform) {
|
|
case "darwin":
|
|
return getDarwinUrl(version)
|
|
case "linux":
|
|
return getLinuxUrl(version)
|
|
case "win32":
|
|
return getWin32Url(version)
|
|
default:
|
|
return null
|
|
}
|
|
}
|
|
|
|
//================================================
|
|
// Exports
|
|
//================================================
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
async function getLLVMPackageInfo(version: string, platform: NodeJS.Platform, _arch: string): Promise<PackageInfo> {
|
|
const [specificVersion, url] = await getSpecificVersionAndUrl(VERSIONS, platform, version, getUrl)
|
|
setOutput("version", specificVersion)
|
|
return {
|
|
url,
|
|
extractedFolderName: "",
|
|
binRelativeDir: "bin",
|
|
binFileName: addBinExtension("clang"),
|
|
extractFunction:
|
|
platform === "win32"
|
|
? extractExe
|
|
: (file: string, dest: string) => {
|
|
return extractTarByExe(file, dest, ["--strip-components=1"])
|
|
},
|
|
}
|
|
}
|
|
|
|
export async function setupLLVM(version: string, setupDir: string, arch: string): Promise<InstallationInfo> {
|
|
const installationInfo = await _setupLLVM(version, setupDir, arch)
|
|
await activateLLVM(installationInfo.installDir ?? setupDir, version)
|
|
return installationInfo
|
|
}
|
|
|
|
let didInit = false
|
|
async function _setupLLVM(version: string, setupDir: string, arch: string) {
|
|
const installationInfo = await setupBin("llvm", version, getLLVMPackageInfo, setupDir, arch)
|
|
if (!didInit) {
|
|
if (process.platform === "linux") {
|
|
// install llvm build dependencies
|
|
await setupGcc(getVersion("gcc", undefined), "", arch) // using llvm requires ld, an up to date libstdc++, etc. So, install gcc first
|
|
setupAptPack("libtinfo-dev")
|
|
}
|
|
// eslint-disable-next-line require-atomic-updates
|
|
didInit = true
|
|
}
|
|
return installationInfo
|
|
}
|
|
|
|
export async function activateLLVM(directory: string, versionGiven: string) {
|
|
const version = semverCoerceIfInvalid(versionGiven)
|
|
|
|
const lib = path.join(directory, "lib")
|
|
|
|
const ld = process.env.LD_LIBRARY_PATH ?? ""
|
|
const dyld = process.env.DYLD_LIBRARY_PATH ?? ""
|
|
|
|
addEnv("LLVM_PATH", directory) // the output of this action
|
|
|
|
// Setup LLVM as the compiler
|
|
addEnv("LD_LIBRARY_PATH", `${lib}${path.delimiter}${ld}`)
|
|
addEnv("DYLD_LIBRARY_PATH", `${lib}${path.delimiter}${dyld}`)
|
|
|
|
const llvmMajor = semverMajor(version)
|
|
if (existsSync(`${directory}/lib/clang/${version}/include`)) {
|
|
addEnv("CPATH", `${directory}/lib/clang/${version}/include`)
|
|
} else if (existsSync(`${directory}/lib/clang/${llvmMajor}/include`)) {
|
|
addEnv("CPATH", `${directory}/lib/clang/${llvmMajor}/include`)
|
|
}
|
|
|
|
addEnv("LDFLAGS", `-L${directory}/lib`)
|
|
addEnv("CPPFLAGS", `-I${directory}/include`)
|
|
|
|
addEnv("CC", `${directory}/bin/clang`)
|
|
addEnv("CXX", `${directory}/bin/clang++`)
|
|
|
|
addEnv("LIBRARY_PATH", `${directory}/lib`)
|
|
|
|
await setupMacOSSDK()
|
|
|
|
if (process.platform === "linux") {
|
|
await updateAptAlternatives("cc", `${directory}/bin/clang`)
|
|
await updateAptAlternatives("cxx", `${directory}/bin/clang++`)
|
|
await updateAptAlternatives("clang", `${directory}/bin/clang`)
|
|
await updateAptAlternatives("clang++", `${directory}/bin/clang++`)
|
|
await updateAptAlternatives("lld", `${directory}/bin/lld`)
|
|
await updateAptAlternatives("ld.lld", `${directory}/bin/ld.lld`)
|
|
await updateAptAlternatives("llvm-ar", `${directory}/bin/llvm-ar`)
|
|
}
|
|
|
|
if (isGitHubCI()) {
|
|
addLLVMLoggingMatcher()
|
|
}
|
|
}
|
|
|
|
/** Setup llvm tools (clang tidy, clang format, etc) without activating llvm and using it as the compiler */
|
|
export function setupClangTools(version: string, setupDir: string, arch: string): Promise<InstallationInfo> {
|
|
if (isGitHubCI()) {
|
|
addLLVMLoggingMatcher()
|
|
}
|
|
return _setupLLVM(version, setupDir, arch)
|
|
}
|
|
|
|
function addLLVMLoggingMatcher() {
|
|
const matcherPath = path.join(__dirname, "llvm_matcher.json")
|
|
if (!existsSync(matcherPath)) {
|
|
return warning("the llvm_matcher.json file does not exist in the same folder as setup_cpp.js")
|
|
}
|
|
info(`::add-matcher::${matcherPath}`)
|
|
}
|