Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support more compiler/tool aliases (e.g. clang, clang-tidy) #293

Merged
merged 1 commit into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"orta.vscode-jest",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"biomejs.biome"
"biomejs.biome",
"p42ai.refactor"
]
}
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ Setting up a **cross-platform** environment for building and testing C++/C proje

`setup-cpp` is **modular** and you can choose to install any of these tools:

| category | tools |
| --------------------- | ------------------------------------------------------------ |
| compiler and analyzer | llvm, gcc, msvc, vcvarsall, cppcheck, clangtidy, clangformat |
| build system | cmake, ninja, meson, make, task, bazel |
| package manager | vcpkg, conan, choco, brew, nala |
| cache | ccache, sccache |
| documentation | doxygen, graphviz |
| coverage | gcovr, opencppcoverage, kcov |
| other | python, powershell, sevenzip |
| category | tools |
| --------------------- | --------------------------------------------------------------------------- |
| compiler and analyzer | llvm, gcc, msvc, apple-clang, vcvarsall, cppcheck, clang-tidy, clang-format |
| build system | cmake, ninja, meson, make, task, bazel |
| package manager | vcpkg, conan, choco, brew, nala |
| cache | ccache, sccache |
| documentation | doxygen, graphviz |
| coverage | gcovr, opencppcoverage, kcov |
| other | python, powershell, sevenzip |

`setup-cpp` automatically handles the dependencies of the selected tool (e.g., `python` is required for `conan`).

Expand Down Expand Up @@ -149,7 +149,7 @@ jobs:
ninja: true
vcpkg: true
cppcheck: true
clangtidy: true # instead of `true`, which chooses the default version, you can pass a specific version.
clang-tidy: true # instead of `true`, which chooses the default version, you can pass a specific version.
# ...
```

Expand Down
33 changes: 33 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,51 @@ inputs:
llvm:
description: "Wether to install llvm (true/false) or the specific version to install"
required: false
clang:
description: "Wether to install clang (true/false) or the specific version to install"
required: false
gcc:
description: "Wether to install gcc (true/false) or the specific version to install"
required: false
msvc:
description: "Wether to install msvc (true/false) or the specific version to install"
required: false
cl:
description: "Wether to install cl (true/false) or the specific version to install"
required: false
msbuild:
description: "Wether to install msbuild (true/false) or the specific version to install"
required: false
visualstudio:
description: "Wether to install visualstudio (true/false) or the specific version to install"
required: false
apple-clang:
description: "Wether to install apple-clang (true/false) or the specific version to install"
required: false
apple-llvm:
description: "Wether to install apple-llvm (true/false) or the specific version to install"
required: false
appleclang:
description: "Wether to install apple-clang (true/false) or the specific version to install"
required: false
applellvm:
description: "Wether to install apple-llvm (true/false) or the specific version to install"
required: false
vcvarsall:
description: "If should run vcvarsall?"
required: false
cppcheck:
description: "Wether to install cppcheck (true/false) or the specific version to install."
required: false
clang-tidy:
description: "Wether to install clang-tidy (true/false) or the specific version to install."
required: false
clangtidy:
description: "The clangWether to install tidy (true/false) or the specific version to install."
required: false
clang-format:
description: "The clangWether to install format (true/false) or the specific version to install."
required: false
clangformat:
description: "The clangWether to install format (true/false) or the specific version to install."
required: false
Expand Down Expand Up @@ -94,6 +124,9 @@ inputs:
powershell:
description: "Wether to install powershell (true/false) or the specific version to install."
required: false
pwsh:
description: "Wether to install pwsh (true/false) or the specific version to install."
required: false
python:
description: "Wether to install python (true/false) or the specific version to install."
required: false
Expand Down
2 changes: 1 addition & 1 deletion dist/legacy/setup-cpp.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/legacy/setup-cpp.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/modern/setup-cpp.mjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/modern/setup-cpp.mjs.map

Large diffs are not rendered by default.

15 changes: 7 additions & 8 deletions src/__tests__/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { parseArgs } from "../cli-options.js"
import { getCompilerInfo } from "../compilers.js"
import type { Inputs } from "../tool.js"
import { type Inputs, llvmTools } from "../tool.js"
import { DefaultUbuntuVersion, DefaultVersions } from "../versions/default_versions.js"
import { getVersion, syncVersions } from "../versions/versions.js"

Expand All @@ -27,24 +27,23 @@ describe("getCompilerInfo", () => {

describe("syncVersion", () => {
it("Syncs llvm tools versions", () => {
const llvmTools = ["llvm", "clangtidy", "clangformat"] as Inputs[]
expect(syncVersions(parseArgs(["--llvm", "14.0.0", "--clangtidy", "true"]), llvmTools)).toBe(true)
expect(syncVersions(parseArgs(["--llvm", "13.0.0", "--clangtidy", "true"]), llvmTools)).toBe(true)
expect(syncVersions(parseArgs(["--llvm", "13.0.0", "--clangtidy", "12.0.0"]), llvmTools)).toBe(false)
expect(syncVersions(parseArgs(["--llvm", "14.0.0", "--clangtidy", "true"]), llvmTools as Inputs[])).toBe(true)
expect(syncVersions(parseArgs(["--llvm", "13.0.0", "--clangtidy", "true"]), llvmTools as Inputs[])).toBe(true)
expect(syncVersions(parseArgs(["--llvm", "13.0.0", "--clangtidy", "12.0.0"]), llvmTools as Inputs[])).toBe(false)

const opts1 = parseArgs(["--llvm", "14.0.0", "--clangtidy", "true"])
expect(syncVersions(opts1, llvmTools)).toBe(true)
expect(syncVersions(opts1, llvmTools as Inputs[])).toBe(true)
expect(opts1.llvm).toBe(opts1.clangtidy)
expect(opts1.clangformat).toBe(undefined)

const opts2 = parseArgs(["--clangtidy", "15.0.0", "--clangformat", "true"])
expect(syncVersions(opts2, llvmTools)).toBe(true)
expect(syncVersions(opts2, llvmTools as Inputs[])).toBe(true)
expect(opts2.llvm).toBe(undefined)
expect(opts2.clangtidy).toBe("15.0.0")
expect(opts2.clangformat).toBe("15.0.0")

const opts3 = parseArgs(["--llvm", "true", "--clangformat", "true"])
expect(syncVersions(opts3, llvmTools)).toBe(true)
expect(syncVersions(opts3, llvmTools as Inputs[])).toBe(true)
expect(opts3.llvm).toBe("true")
expect(opts3.clangtidy).toBe(undefined)
expect(opts3.clangformat).toBe("true")
Expand Down
4 changes: 3 additions & 1 deletion src/cli-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ All the available tools:

console.table(
{
"compiler and analyzer": { tools: "--llvm, --gcc, --msvc, --vcvarsall, --cppcheck, --clangtidy, --clangformat" },
"compiler and analyzer": {
tools: "--llvm, --gcc, --msvc, --apple-clang, --vcvarsall, --cppcheck, --clang-tidy, --clang-format",
},
"build system": { tools: "--cmake, --ninja, --meson, --make, --task, --bazel" },
"package manager": { tools: "--vcpkg, --conan, --choco, --brew, --nala" },
cache: { tools: "--ccache, --sccache" },
Expand Down
130 changes: 58 additions & 72 deletions src/compilers.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
import { join } from "path"
import { endGroup, notice, startGroup } from "@actions/core"
import { endGroup, startGroup } from "@actions/core"
import { error, info } from "ci-log"
import { addEnv } from "envosman"
import semverValid from "semver/functions/valid"
import { getSuccessMessage, rcOptions } from "./cli-options.js"
import { getSuccessMessage } from "./cli-options.js"
import { setupGcc, setupMingw } from "./gcc/gcc.js"
import { activateGcovGCC, activateGcovLLVM } from "./gcovr/gcovr.js"
import { setupAppleClang } from "./llvm/apple-clang.js"
import { setupLLVM } from "./llvm/llvm.js"
import { setupMSVC } from "./msvc/msvc.js"
import { appleClangSetups, gccSetups, llvmSetups, mingwSetups, msvcSetups } from "./tool.js"
import type { InstallationInfo } from "./utils/setup/setupBin.js"
import { getVersion } from "./versions/versions.js"

/** Detecting the compiler version. Divide the given string by `-` and use the second element as the version */
/**
* Detecting the compiler version. Divide the given string by `-` and use the second element as the version
*
* @param compilerAndVersion - The compiler and version string
* @returns The compiler and version
*
* @nothrow It doesn't throw any error, but it logs the error if it fails to parse the compiler info
*/
export function getCompilerInfo(compilerAndVersion: string) {
const compilerAndMaybeVersion = compilerAndVersion.split("-")
const compiler = compilerAndMaybeVersion[0]
if (1 in compilerAndMaybeVersion) {
const maybeVersion = compilerAndMaybeVersion[1]
if (semverValid(maybeVersion) !== null) {
return { compiler, version: maybeVersion }
} else {
info(`Invalid semver version ${maybeVersion} used for the compiler.`)
try {
const compilerAndMaybeVersion = compilerAndVersion.split("-")
const compiler = compilerAndMaybeVersion[0]
if (1 in compilerAndMaybeVersion) {
const maybeVersion = compilerAndMaybeVersion[1]
if (semverValid(maybeVersion) === null) {
info(`Invalid semver version ${maybeVersion} used for the compiler.`)
}
return { compiler, version: maybeVersion }
}
return { compiler, version: undefined }
} catch (err) {
error(`Failed to parse the compiler info ${compilerAndVersion}: ${err}`)
return { compiler: compilerAndVersion, version: undefined }
}
return { compiler, version: undefined }
}

/** Installing the specified compiler */
Expand All @@ -35,73 +47,47 @@ export async function installCompiler(
successMessages: string[],
errorMessages: string[],
) {
try {
const { compiler, version } = getCompilerInfo(compilerAndVersion)
const { compiler, version } = getCompilerInfo(compilerAndVersion)

let installationInfo: InstallationInfo | undefined | void | null // null means the compiler is not supported
try {
// install the compiler. We allow some aliases for the compiler name
startGroup(`Installing ${compiler} ${version ?? ""}`)
switch (compiler) {
case "llvm":
case "clang":
case "clang++": {
const installationInfo = await setupLLVM(
getVersion("llvm", version, osVersion),
join(setupCppDir, "llvm"),
arch,
)

await activateGcovLLVM()

successMessages.push(getSuccessMessage("llvm", installationInfo))
break
}
case "gcc":
case "mingw":
case "cygwin":
case "msys": {
const gccVersion = compiler === "mingw"
? getVersion("mingw", version, osVersion)
: getVersion("gcc", version, osVersion)
const installationInfo = compiler === "mingw"
? await setupMingw(gccVersion, join(setupCppDir, "gcc"), arch)
: await setupGcc(gccVersion, join(setupCppDir, "gcc"), arch)

await activateGcovGCC(gccVersion)

successMessages.push(getSuccessMessage("gcc", installationInfo))
break
}
case "cl":
case "msvc":
case "msbuild":
case "vs":
case "visualstudio":
case "visualcpp":
case "visualc++": {
const installationInfo = await setupMSVC(
getVersion("msvc", version, osVersion),
join(setupCppDir, "msvc"),
arch,
)

successMessages.push(getSuccessMessage("msvc", installationInfo))
break
}
case "appleclang":
case "applellvm": {
notice("Assuming apple-clang is already installed")
await Promise.all([addEnv("CC", "clang", rcOptions), addEnv("CXX", "clang++", rcOptions)])
successMessages.push(getSuccessMessage("apple-clang", undefined))
break
}
default: {
errorMessages.push(`Unsupported compiler ${compiler}`)
}
if (compiler in llvmSetups) {
installationInfo = await setupLLVM(
getVersion("llvm", version, osVersion),
join(setupCppDir, "llvm"),
arch,
)
await activateGcovLLVM()
} else if (compiler in gccSetups) {
const gccVersion = getVersion("gcc", version, osVersion)
installationInfo = await setupGcc(gccVersion, join(setupCppDir, "gcc"), arch)
await activateGcovGCC(gccVersion)
} else if (compiler in mingwSetups) {
const gccVersion = getVersion("mingw", version, osVersion)
installationInfo = await setupMingw(gccVersion, join(setupCppDir, "gcc"), arch)
await activateGcovGCC(gccVersion)
} else if (compiler in msvcSetups) {
installationInfo = await setupMSVC(
getVersion("msvc", version, osVersion),
join(setupCppDir, "msvc"),
arch,
)
} else if (compiler in appleClangSetups) {
await setupAppleClang()
} else {
installationInfo = null
errorMessages.push(`Unsupported compiler ${compiler}`)
}
} catch (err) {
error(err as string | Error)
errorMessages.push(`Failed to install the ${compilerAndVersion}`)
}

if (installationInfo !== null) {
successMessages.push(getSuccessMessage(compiler, installationInfo))
}

endGroup()
}
4 changes: 2 additions & 2 deletions src/installTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { error } from "ci-log"
import pTimeout from "p-timeout"
import { setupBrew } from "setup-brew"
import { getSuccessMessage, rcOptions } from "./cli-options.js"
import { type ToolName, setups } from "./tool.js"
import { type ToolName, llvmTools, setups } from "./tool.js"
import type { InstallationInfo } from "./utils/setup/setupBin.js"
import { setupVCVarsall } from "./vcvarsall/vcvarsall.js"
import { getVersion } from "./versions/versions.js"
Expand Down Expand Up @@ -46,7 +46,7 @@ async function installToolImpl(
setupCppDir: string,
successMessages: string[],
) {
const hasLLVM = ["llvm", "clangformat", "clangtidy"].includes(tool)
const hasLLVM = llvmTools.includes(tool)

let installationInfo: InstallationInfo | undefined | void
if (tool === "vcvarsall") {
Expand Down
19 changes: 19 additions & 0 deletions src/llvm/apple-clang.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { error } from "console"
import { notice } from "ci-log"
import { addEnv } from "envosman"
import which from "which"
import { rcOptions } from "../cli-options.js"

export async function setupAppleClang() {
if (process.platform !== "darwin") {
return
}

if (await which("clang", { nothrow: true }) !== null && await which("clang++", { nothrow: true }) !== null) {
notice("Assuming clang is an Apple Clang compiler")
await Promise.all([addEnv("CC", "clang", rcOptions), addEnv("CXX", "clang++", rcOptions)])
}

// TODO install Apple Clang automatically
error("Apple Clang automatic installation is not supported yet")
}
6 changes: 3 additions & 3 deletions src/setup-cpp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { checkUpdates } from "./check-updates.js"
import { parseArgs, printHelp, rcOptions } from "./cli-options.js"
import { installCompiler } from "./compilers.js"
import { installTool } from "./installTool.js"
import { tools } from "./tool.js"
import { type Inputs, llvmTools, tools } from "./tool.js"
import { isArch } from "./utils/env/isArch.js"
import { ubuntuVersion } from "./utils/env/ubuntu_version.js"
import { setupPacmanPack } from "./utils/setup/setupPacmanPack.js"
Expand Down Expand Up @@ -56,8 +56,8 @@ async function main(args: string[]): Promise<number> {
const osVersion = await ubuntuVersion()

// sync the version for the llvm tools
if (!syncVersions(opts, ["llvm", "clangtidy", "clangformat"])) {
error("The same version must be used for llvm, clangformat and clangtidy")
if (!syncVersions(opts, llvmTools as Inputs[])) {
error("The same version must be used for llvm, clang-format and clang-tidy")
return 1
}

Expand Down
Loading
Loading