Skip to content

Commit 8a39523

Browse files
committed
feat: support more compiler/tool aliases (e.g. clang, clang-tidy)
1 parent fc60b25 commit 8a39523

15 files changed

+177
-106
lines changed

.vscode/extensions.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"orta.vscode-jest",
44
"esbenp.prettier-vscode",
55
"dbaeumer.vscode-eslint",
6-
"biomejs.biome"
6+
"biomejs.biome",
7+
"p42ai.refactor"
78
]
89
}

README.md

+10-10
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ Setting up a **cross-platform** environment for building and testing C++/C proje
1414

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

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

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

@@ -149,7 +149,7 @@ jobs:
149149
ninja: true
150150
vcpkg: true
151151
cppcheck: true
152-
clangtidy: true # instead of `true`, which chooses the default version, you can pass a specific version.
152+
clang-tidy: true # instead of `true`, which chooses the default version, you can pass a specific version.
153153
# ...
154154
```
155155

action.yml

+33
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,51 @@ inputs:
1919
llvm:
2020
description: "Wether to install llvm (true/false) or the specific version to install"
2121
required: false
22+
clang:
23+
description: "Wether to install clang (true/false) or the specific version to install"
24+
required: false
2225
gcc:
2326
description: "Wether to install gcc (true/false) or the specific version to install"
2427
required: false
2528
msvc:
2629
description: "Wether to install msvc (true/false) or the specific version to install"
2730
required: false
31+
cl:
32+
description: "Wether to install cl (true/false) or the specific version to install"
33+
required: false
34+
msbuild:
35+
description: "Wether to install msbuild (true/false) or the specific version to install"
36+
required: false
37+
visualstudio:
38+
description: "Wether to install visualstudio (true/false) or the specific version to install"
39+
required: false
40+
apple-clang:
41+
description: "Wether to install apple-clang (true/false) or the specific version to install"
42+
required: false
43+
apple-llvm:
44+
description: "Wether to install apple-llvm (true/false) or the specific version to install"
45+
required: false
46+
appleclang:
47+
description: "Wether to install apple-clang (true/false) or the specific version to install"
48+
required: false
49+
applellvm:
50+
description: "Wether to install apple-llvm (true/false) or the specific version to install"
51+
required: false
2852
vcvarsall:
2953
description: "If should run vcvarsall?"
3054
required: false
3155
cppcheck:
3256
description: "Wether to install cppcheck (true/false) or the specific version to install."
3357
required: false
58+
clang-tidy:
59+
description: "Wether to install clang-tidy (true/false) or the specific version to install."
60+
required: false
3461
clangtidy:
3562
description: "The clangWether to install tidy (true/false) or the specific version to install."
3663
required: false
64+
clang-format:
65+
description: "The clangWether to install format (true/false) or the specific version to install."
66+
required: false
3767
clangformat:
3868
description: "The clangWether to install format (true/false) or the specific version to install."
3969
required: false
@@ -94,6 +124,9 @@ inputs:
94124
powershell:
95125
description: "Wether to install powershell (true/false) or the specific version to install."
96126
required: false
127+
pwsh:
128+
description: "Wether to install pwsh (true/false) or the specific version to install."
129+
required: false
97130
python:
98131
description: "Wether to install python (true/false) or the specific version to install."
99132
required: false

dist/legacy/setup-cpp.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/legacy/setup-cpp.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/modern/setup-cpp.mjs

+1-1
Large diffs are not rendered by default.

dist/modern/setup-cpp.mjs.map

+1-1
Large diffs are not rendered by default.

src/__tests__/main.test.ts

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { parseArgs } from "../cli-options.js"
22
import { getCompilerInfo } from "../compilers.js"
3-
import type { Inputs } from "../tool.js"
3+
import { type Inputs, llvmTools } from "../tool.js"
44
import { DefaultUbuntuVersion, DefaultVersions } from "../versions/default_versions.js"
55
import { getVersion, syncVersions } from "../versions/versions.js"
66

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

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

3534
const opts1 = parseArgs(["--llvm", "14.0.0", "--clangtidy", "true"])
36-
expect(syncVersions(opts1, llvmTools)).toBe(true)
35+
expect(syncVersions(opts1, llvmTools as Inputs[])).toBe(true)
3736
expect(opts1.llvm).toBe(opts1.clangtidy)
3837
expect(opts1.clangformat).toBe(undefined)
3938

4039
const opts2 = parseArgs(["--clangtidy", "15.0.0", "--clangformat", "true"])
41-
expect(syncVersions(opts2, llvmTools)).toBe(true)
40+
expect(syncVersions(opts2, llvmTools as Inputs[])).toBe(true)
4241
expect(opts2.llvm).toBe(undefined)
4342
expect(opts2.clangtidy).toBe("15.0.0")
4443
expect(opts2.clangformat).toBe("15.0.0")
4544

4645
const opts3 = parseArgs(["--llvm", "true", "--clangformat", "true"])
47-
expect(syncVersions(opts3, llvmTools)).toBe(true)
46+
expect(syncVersions(opts3, llvmTools as Inputs[])).toBe(true)
4847
expect(opts3.llvm).toBe("true")
4948
expect(opts3.clangtidy).toBe(undefined)
5049
expect(opts3.clangformat).toBe("true")

src/cli-options.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ All the available tools:
3232

3333
console.table(
3434
{
35-
"compiler and analyzer": { tools: "--llvm, --gcc, --msvc, --vcvarsall, --cppcheck, --clangtidy, --clangformat" },
35+
"compiler and analyzer": {
36+
tools: "--llvm, --gcc, --msvc, --apple-clang, --vcvarsall, --cppcheck, --clang-tidy, --clang-format",
37+
},
3638
"build system": { tools: "--cmake, --ninja, --meson, --make, --task, --bazel" },
3739
"package manager": { tools: "--vcpkg, --conan, --choco, --brew, --nala" },
3840
cache: { tools: "--ccache, --sccache" },

src/compilers.ts

+58-72
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,41 @@
11
import { join } from "path"
2-
import { endGroup, notice, startGroup } from "@actions/core"
2+
import { endGroup, startGroup } from "@actions/core"
33
import { error, info } from "ci-log"
4-
import { addEnv } from "envosman"
54
import semverValid from "semver/functions/valid"
6-
import { getSuccessMessage, rcOptions } from "./cli-options.js"
5+
import { getSuccessMessage } from "./cli-options.js"
76
import { setupGcc, setupMingw } from "./gcc/gcc.js"
87
import { activateGcovGCC, activateGcovLLVM } from "./gcovr/gcovr.js"
8+
import { setupAppleClang } from "./llvm/apple-clang.js"
99
import { setupLLVM } from "./llvm/llvm.js"
1010
import { setupMSVC } from "./msvc/msvc.js"
11+
import { appleClangSetups, gccSetups, llvmSetups, mingwSetups, msvcSetups } from "./tool.js"
12+
import type { InstallationInfo } from "./utils/setup/setupBin.js"
1113
import { getVersion } from "./versions/versions.js"
1214

13-
/** Detecting the compiler version. Divide the given string by `-` and use the second element as the version */
15+
/**
16+
* Detecting the compiler version. Divide the given string by `-` and use the second element as the version
17+
*
18+
* @param compilerAndVersion - The compiler and version string
19+
* @returns The compiler and version
20+
*
21+
* @nothrow It doesn't throw any error, but it logs the error if it fails to parse the compiler info
22+
*/
1423
export function getCompilerInfo(compilerAndVersion: string) {
15-
const compilerAndMaybeVersion = compilerAndVersion.split("-")
16-
const compiler = compilerAndMaybeVersion[0]
17-
if (1 in compilerAndMaybeVersion) {
18-
const maybeVersion = compilerAndMaybeVersion[1]
19-
if (semverValid(maybeVersion) !== null) {
20-
return { compiler, version: maybeVersion }
21-
} else {
22-
info(`Invalid semver version ${maybeVersion} used for the compiler.`)
24+
try {
25+
const compilerAndMaybeVersion = compilerAndVersion.split("-")
26+
const compiler = compilerAndMaybeVersion[0]
27+
if (1 in compilerAndMaybeVersion) {
28+
const maybeVersion = compilerAndMaybeVersion[1]
29+
if (semverValid(maybeVersion) === null) {
30+
info(`Invalid semver version ${maybeVersion} used for the compiler.`)
31+
}
2332
return { compiler, version: maybeVersion }
2433
}
34+
return { compiler, version: undefined }
35+
} catch (err) {
36+
error(`Failed to parse the compiler info ${compilerAndVersion}: ${err}`)
37+
return { compiler: compilerAndVersion, version: undefined }
2538
}
26-
return { compiler, version: undefined }
2739
}
2840

2941
/** Installing the specified compiler */
@@ -35,73 +47,47 @@ export async function installCompiler(
3547
successMessages: string[],
3648
errorMessages: string[],
3749
) {
38-
try {
39-
const { compiler, version } = getCompilerInfo(compilerAndVersion)
50+
const { compiler, version } = getCompilerInfo(compilerAndVersion)
4051

52+
let installationInfo: InstallationInfo | undefined | void | null // null means the compiler is not supported
53+
try {
4154
// install the compiler. We allow some aliases for the compiler name
4255
startGroup(`Installing ${compiler} ${version ?? ""}`)
43-
switch (compiler) {
44-
case "llvm":
45-
case "clang":
46-
case "clang++": {
47-
const installationInfo = await setupLLVM(
48-
getVersion("llvm", version, osVersion),
49-
join(setupCppDir, "llvm"),
50-
arch,
51-
)
52-
53-
await activateGcovLLVM()
54-
55-
successMessages.push(getSuccessMessage("llvm", installationInfo))
56-
break
57-
}
58-
case "gcc":
59-
case "mingw":
60-
case "cygwin":
61-
case "msys": {
62-
const gccVersion = compiler === "mingw"
63-
? getVersion("mingw", version, osVersion)
64-
: getVersion("gcc", version, osVersion)
65-
const installationInfo = compiler === "mingw"
66-
? await setupMingw(gccVersion, join(setupCppDir, "gcc"), arch)
67-
: await setupGcc(gccVersion, join(setupCppDir, "gcc"), arch)
68-
69-
await activateGcovGCC(gccVersion)
70-
71-
successMessages.push(getSuccessMessage("gcc", installationInfo))
72-
break
73-
}
74-
case "cl":
75-
case "msvc":
76-
case "msbuild":
77-
case "vs":
78-
case "visualstudio":
79-
case "visualcpp":
80-
case "visualc++": {
81-
const installationInfo = await setupMSVC(
82-
getVersion("msvc", version, osVersion),
83-
join(setupCppDir, "msvc"),
84-
arch,
85-
)
86-
87-
successMessages.push(getSuccessMessage("msvc", installationInfo))
88-
break
89-
}
90-
case "appleclang":
91-
case "applellvm": {
92-
notice("Assuming apple-clang is already installed")
93-
await Promise.all([addEnv("CC", "clang", rcOptions), addEnv("CXX", "clang++", rcOptions)])
94-
successMessages.push(getSuccessMessage("apple-clang", undefined))
95-
break
96-
}
97-
default: {
98-
errorMessages.push(`Unsupported compiler ${compiler}`)
99-
}
56+
if (compiler in llvmSetups) {
57+
installationInfo = await setupLLVM(
58+
getVersion("llvm", version, osVersion),
59+
join(setupCppDir, "llvm"),
60+
arch,
61+
)
62+
await activateGcovLLVM()
63+
} else if (compiler in gccSetups) {
64+
const gccVersion = getVersion("gcc", version, osVersion)
65+
installationInfo = await setupGcc(gccVersion, join(setupCppDir, "gcc"), arch)
66+
await activateGcovGCC(gccVersion)
67+
} else if (compiler in mingwSetups) {
68+
const gccVersion = getVersion("mingw", version, osVersion)
69+
installationInfo = await setupMingw(gccVersion, join(setupCppDir, "gcc"), arch)
70+
await activateGcovGCC(gccVersion)
71+
} else if (compiler in msvcSetups) {
72+
installationInfo = await setupMSVC(
73+
getVersion("msvc", version, osVersion),
74+
join(setupCppDir, "msvc"),
75+
arch,
76+
)
77+
} else if (compiler in appleClangSetups) {
78+
await setupAppleClang()
79+
} else {
80+
installationInfo = null
81+
errorMessages.push(`Unsupported compiler ${compiler}`)
10082
}
10183
} catch (err) {
10284
error(err as string | Error)
10385
errorMessages.push(`Failed to install the ${compilerAndVersion}`)
10486
}
10587

88+
if (installationInfo !== null) {
89+
successMessages.push(getSuccessMessage(compiler, installationInfo))
90+
}
91+
10692
endGroup()
10793
}

src/installTool.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { error } from "ci-log"
44
import pTimeout from "p-timeout"
55
import { setupBrew } from "setup-brew"
66
import { getSuccessMessage, rcOptions } from "./cli-options.js"
7-
import { type ToolName, setups } from "./tool.js"
7+
import { type ToolName, llvmTools, setups } from "./tool.js"
88
import type { InstallationInfo } from "./utils/setup/setupBin.js"
99
import { setupVCVarsall } from "./vcvarsall/vcvarsall.js"
1010
import { getVersion } from "./versions/versions.js"
@@ -46,7 +46,7 @@ async function installToolImpl(
4646
setupCppDir: string,
4747
successMessages: string[],
4848
) {
49-
const hasLLVM = ["llvm", "clangformat", "clangtidy"].includes(tool)
49+
const hasLLVM = llvmTools.includes(tool)
5050

5151
let installationInfo: InstallationInfo | undefined | void
5252
if (tool === "vcvarsall") {

src/llvm/apple-clang.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { error } from "console"
2+
import { notice } from "ci-log"
3+
import { addEnv } from "envosman"
4+
import which from "which"
5+
import { rcOptions } from "../cli-options.js"
6+
7+
export async function setupAppleClang() {
8+
if (process.platform !== "darwin") {
9+
return
10+
}
11+
12+
if (await which("clang", { nothrow: true }) !== null && await which("clang++", { nothrow: true }) !== null) {
13+
notice("Assuming clang is an Apple Clang compiler")
14+
await Promise.all([addEnv("CC", "clang", rcOptions), addEnv("CXX", "clang++", rcOptions)])
15+
}
16+
17+
// TODO install Apple Clang automatically
18+
error("Apple Clang automatic installation is not supported yet")
19+
}

src/setup-cpp.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { checkUpdates } from "./check-updates.js"
1313
import { parseArgs, printHelp, rcOptions } from "./cli-options.js"
1414
import { installCompiler } from "./compilers.js"
1515
import { installTool } from "./installTool.js"
16-
import { tools } from "./tool.js"
16+
import { type Inputs, llvmTools, tools } from "./tool.js"
1717
import { isArch } from "./utils/env/isArch.js"
1818
import { ubuntuVersion } from "./utils/env/ubuntu_version.js"
1919
import { setupPacmanPack } from "./utils/setup/setupPacmanPack.js"
@@ -56,8 +56,8 @@ async function main(args: string[]): Promise<number> {
5656
const osVersion = await ubuntuVersion()
5757

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

0 commit comments

Comments
 (0)