Skip to content
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
6 changes: 6 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 20

- name: Smoke Test Modern Bundle
if: ${{ !contains(github.event.head_commit.message, '[skip test]') }}
run: |
Expand All @@ -208,6 +209,11 @@ jobs:
env:
RUNNER_OS_NAME: ${{ matrix.os }}

- name: Smoke Test Global Install
if: ${{ !contains(github.event.head_commit.message, '[skip test]') }}
run: |
setup-cpp --help

- name: Setup Node 12
if: ${{ !contains(matrix.os, 'macos-14') && !contains(matrix.os, 'macos-15') }}
uses: actions/setup-node@v4
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Setting up a **cross-platform** environment for building and testing C++/C proje
| --------------- | ----------------------------------------------------------------------------------------------------------- |
| compiler | llvm, gcc, msvc, apple-clang, vcvarsall |
| build system | cmake, ninja, meson, make, task, bazel |
| package manager | vcpkg, conan, choco, brew, nala |
| package manager | vcpkg, conan, choco, brew, nala, setup-cpp |
| analyzer/linter | clang-tidy, clang-format, cppcheck, cpplint, flawfinder, lizard, infer, cmakelang, cmake-format, cmake-lint |
| cache | ccache, sccache |
| documentation | doxygen, graphviz |
Expand Down Expand Up @@ -195,6 +195,19 @@ jobs:
cppcheck: true # instead of `true`, which chooses the default version, you can pass a specific version.
```

When using the `setup-cpp` action in GitHub Actions, by default it will also install the `setup-cpp` CLI, which you can use in the subsequent commands. You can modify the default behaviour if needed.

```yaml
- name: Setup Cpp
uses: aminya/setup-cpp@v1
with:
setup-cpp: true
node-package-manager: "npm"

- name: Use Setup Cpp CLI
run: setup-cpp --compiler llvm --cmake true --ninja true --ccache true --vcpkg true
```

### Prebuilt Docker Images

To provide fast development environments, `setup-cpp` provides several prebuilt docker images that have the tools you need. You can use these images as a base image for your project.
Expand Down
6 changes: 6 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ inputs:
python:
description: "Wether to install python (true/false) or the specific version to install."
required: false
setup-cpp:
description: "Wether to install setup-cpp (true/false) or the specific version to install. (Default to the current version called by the action)"
required: false
node-package-manager:
description: "The node package manager to use (npm/yarn/pnpm) when installing setup-cpp globally"
required: false

runs:
using: "node20"
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.

21 changes: 14 additions & 7 deletions src/cli-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import { type Inputs, inputs } from "./tool.js"
import type { InstallationInfo } from "./utils/setup/setupBin.js"

export function parseArgs(args: string[]): Opts {
return mri<Record<Inputs, string | undefined> & { help: boolean }>(args, {
string: [...inputs, "timeout"],
default: Object.fromEntries(inputs.map((inp) => [inp, maybeGetInput(inp)])),
alias: { h: "help" },
boolean: "help",
const defaults = Object.fromEntries(inputs.map((inp) => [inp, maybeGetInput(inp)]))
return mri<Record<Inputs, string | undefined> & { help: boolean; version: boolean; "setup-cpp": boolean }>(args, {
string: [...inputs, "timeout", "node-package-manager"],
default: defaults,
alias: { h: "help", v: "version" },
boolean: ["help", "version", "setup-cpp"],
})
}

Expand All @@ -25,7 +26,10 @@ Install all the tools required for building and testing C++/C projects.
--timeout\t the timeout for the installation of each tool in minutes. By default it is 10 minutes.
--compiler\t the <compiler> to install.
\t You can specify the version instead of specifying just the name e.g: --compiler 'llvm-13.0.0'
--$tool_name\t pass "true" or pass the <version> you would like to install for this tool. e.g. --conan true or --conan "1.42.1"
--tool_name\t pass "true" or pass the <version> you would like to install for this tool. e.g. --conan true or --conan "1.42.1"
--nodePackageManager\t the node package manager to use (npm/yarn/pnpm) when installing setup-cpp globally
--help\t show this help message
--version\t show the version of setup-cpp

All the available tools:
`)
Expand All @@ -38,7 +42,7 @@ All the available tools:
"build system": {
tools: "--cmake, --ninja, --meson, --make, --task, --bazel",
},
"package manager": { tools: "--vcpkg, --conan, --choco, --brew, --nala" },
"package manager": { tools: "--vcpkg, --conan, --choco, --brew, --nala, --setup-cpp" },
"analyzer/linter": {
tools:
"--clang-tidy, --clang-format, --cppcheck, --cpplint, --flawfinder, --lizard, --infer, , --cmakelang, --cmake-lint, --cmake-format",
Expand All @@ -63,7 +67,10 @@ export function maybeGetInput(key: string) {
export type Opts = mri.Argv<
Record<Inputs, string | undefined> & {
help: boolean
version: boolean
"setup-cpp"?: boolean
timeout?: string
"node-package-manager"?: string
}
>

Expand Down
27 changes: 27 additions & 0 deletions src/setup-cpp-installer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { error, info } from "ci-log"
import { execa } from "execa"
import which from "which"
/**
* Install the setup-cpp CLI globally
* @param version - The version of setup-cpp to install
* @param packageManager - The package manager to use
*/
export async function installSetupCpp(version: string, packageManager: string = "npm") {
try {
// check if `setup-cpp` is available in the shell, if so, skip the installation to avoid overwriting the existing version
const setupCppPath = await which("setup-cpp", { nothrow: true })
if (setupCppPath !== null) {
return
}

// Install setup-cpp globally
info(`Installing setup-cpp@${version} via ${packageManager}...`)
await execa(packageManager, ["install", "-g", `setup-cpp@${version}`], {
stdio: "inherit",
// 1 minutes timeout
timeout: 1000 * 60 * 1,
})
} catch (err) {
error(`Failed to install the setup-cpp@${version} CLI: ${err}. Ignoring...`)
}
}
63 changes: 37 additions & 26 deletions src/setup-cpp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import numerousLocale from "numerous/locales/en.js"
import timeDelta from "time-delta"
import timeDeltaLocale from "time-delta/locales/en.js"
import { untildifyUser } from "untildify-user"
import packageJson from "../package-version.json"
import { checkUpdates } from "./check-updates.js"
import { parseArgs, printHelp, rcOptions } from "./cli-options.js"
import { getCompilerInfo, installCompiler } from "./compilers.js"
import { installTool } from "./installTool.js"
import { installSetupCpp } from "./setup-cpp-installer.js"
import { type Inputs, llvmTools, tools } from "./tool.js"
import { isArch } from "./utils/env/isArch.js"
import { ubuntuVersion } from "./utils/env/ubuntu_version.js"
Expand All @@ -21,11 +23,7 @@ import { syncVersions } from "./versions/versions.js"

/** The main entry function */
async function main(args: string[]): Promise<number> {
let checkUpdatePromise = Promise.resolve()
if (!GITHUB_ACTIONS) {
checkUpdatePromise = checkUpdates()
process.env.ACTIONS_ALLOW_UNSECURE_COMMANDS = "true"
}
const checkUpdatePromise = GITHUB_ACTIONS ? Promise.resolve() : checkUpdates()

// parse options using mri or github actions
const opts = parseArgs(args)
Expand All @@ -35,6 +33,11 @@ async function main(args: string[]): Promise<number> {
printHelp()
}

// print version
if (opts.version) {
info(`${packageJson.version}`)
}

// cpu architecture
const arch = opts.architecture ?? process.arch

Expand Down Expand Up @@ -122,11 +125,20 @@ async function main(args: string[]): Promise<number> {

await finalizeRC(rcOptions)

if (successMessages.length === 0 && errorMessages.length === 0) {
warning("setup-cpp was called without any arguments. Nothing to do.")
return 0
const noTool = successMessages.length === 0 && errorMessages.length === 0

// if setup-cpp option is not passed, install setup-cpp by default unless only help or version is passed
// So that --help and --version are immutable
if (opts["setup-cpp"] === undefined) {
opts["setup-cpp"] = !(noTool && (opts.version || opts.help))
}

const installSetupCppPromise = opts["setup-cpp"]
? installSetupCpp(packageJson.version, opts["node-package-manager"])
: Promise.resolve()

await Promise.all([checkUpdatePromise, installSetupCppPromise])

// report the messages in the end
for (const tool of successMessages) {
success(tool)
Expand All @@ -135,27 +147,26 @@ async function main(args: string[]): Promise<number> {
error(tool)
}

info("setup-cpp finished")

if (!GITHUB_ACTIONS) {
switch (process.platform) {
case "win32": {
warning("Run `RefreshEnv.cmd` or restart your shell to update the environment.")
break
}
case "linux":
case "darwin": {
warning("Run `source ~/.cpprc` or restart your shell to update the environment.")
break
}
default: {
// nothing
if (successMessages.length !== 0 || errorMessages.length !== 0) {
info("setup-cpp finished")

if (!GITHUB_ACTIONS) {
switch (process.platform) {
case "win32": {
warning("Run `RefreshEnv.cmd` or restart your shell to update the environment.")
break
}
case "linux":
case "darwin": {
warning("Run `source ~/.cpprc` or restart your shell to update the environment.")
break
}
default: {
// nothing
}
}
}
}

await checkUpdatePromise

return errorMessages.length === 0 ? 0 : 1 // exit with non-zero if any error message
}

Expand Down