Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/lukka/get-vcpkg

The most effective workflow to leverage vcpkg on GitHub
https://github.com/lukka/get-vcpkg

Last synced: 26 days ago
JSON representation

The most effective workflow to leverage vcpkg on GitHub

Awesome Lists containing this project

README

        

[![Action Status](https://github.com/lukka/get-vcpkg/workflows/build-test/badge.svg)](https://github.com/lukka/get-vcpkg/actions)

# [The **get-vcpkg** action for caching artifacts and using vcpkg on GitHub](https://github.com/marketplace/actions/get-vcpkg)

## User Manual
* [Quickstart](#quickstart)
* [Flowchart](#flowchart)
* [The get-vcpkg action](#get-vcpkg)
* [Best practices](#best-practices)
* [Use vcpkg as a submodule of your repository](#use-vcpkg-as-a-submodule-of-your-repository)
* [Use vcpkg's vcpkg.json file to specify the dependencies](#vcpkgjson)
* [Action reference: all input/output parameters](#reference)
* [Rationale](#rationale)
* [Samples](#samples)
* [Contributing](#contributing)

### Rationale for creating the 'get-vcpkg' action

The reason this action is existing is the willing to abandon Javascript based actions based on honerous source code to write and maintain in favor of easy to implement and maintain declarative workflow template, that expresses reusable logic that could be consumed in several other workflow avoiding code duplication.
To underline what a `template workflow` is meant: suppose there are two projects that have two different but very similar workflows. Ideally both projects could reuse a common `yml` template file that express the commonality, and the input of the template specializes it for the project, e.g.:

file `build-project-with-cmake-and-vcpkg.yml`:
```yml
input:
configuration:
default: Debug # or RelWithDebInfo etc.
install:
default: false
steps:
- uses: ./get-vcpkg@main
- run: cmake -S . -B ./build && cmake --build ./build
- run: cmake --install
```

file: `project1.yml`
```yml
steps:
- uses: ./build-project-with-cmake-and-vcpkg.yml
with:
configuration: ${{ parameter.configuration }}
```

file: `project2.yml`
```yml
steps:
- uses: ./build-project-with-cmake-and-vcpkg.yml
with:
configuration: ${{ parameter.configuration }}
install: true
```

This is simply not possible with GitHub, as "_inclusion_" of one yml from another one is not possible.
If The 'inclusion' operation would allow to split a workflow in its foundation pieces, and creating the resulting workflow by composition of the foundations. This is what happens on Azure DevOps, where it is possible to update several workflows just by updating the foundation workflow.

### The action foundations

Given the recent development of `vcpkg` and `CMake`, it is very easy to write a workflow that is purely based on invocation to the tools itself, without relying on any ad-hoc GitHub Action. As an example, I encourage any user of [`run-vcpkg`](https://github.com/lukka/run-vcpkg) or [`run-cmake`](https://github.com/lukka/run-cmake) to author workflows similat to the ['pure' workflow](https://github.com/lukka/run-vcpkg#before-using-this-action-consider-writing-a-pure-workflow). The definition of 'pure' is "not polluted by special GitHub Actions that you canot easily run locally on your development computer". A polluted workflow makes very hard to reproduce any problem that typically arises only on the GitHub runners and not locally on your development environment, which makes investigating workflow failures possible only by using a _trial and error_ method.
In particular using the `vcpkg.json` manifest, `vcpkg` is **(1)bootstrapped** and **(2)run** when `cmake` is running, which makes the 'pure' workflow easy to write, to understandand to maintain. And also possbile!

Caching is still needed to cache the output generated by vcpkg, which rarely changes, and taht mean *caching is absolutely necessary*. This also implies that a general action like [github/actions/cache](https://github.com/actions/cache), which is perfectly fine as usage of the GitHub caching sservice is only needed on the workflow execution, but locally on our box we already have local cache.

#### How to implement such declarative template

While Azure DevOps supports a form of [templates](https://docs.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops) that can be reused by other templates or workflow, GitHub workflows based on Action do not yet, but there is somethign close to it: ["composite"](https://docs.github.com/en/actions/creating-actions/creating-a-composite-run-steps-action) GitHub actions.

The idea is to create a template that implements logic:
- using the GitHub cache service, restore the previously built vcpkg's ports.
- bootstrap and run vcpkg with a manifest file to built and install the ports..
- if not done yet, save with the cache servicethe the built and installed ports.

The templace would look like this:

```yml
steps:
- name: Restore ports from cache.
uses: action/cache@v2
- uses: ./get-vcpkg.yml
- run: cmake && cmake --build
```

where the get-vcpkg.yml file that can be consumed in different way: for example as a local file or as a Git submodule.

Nonetheless this is not possible on GitHub, because a workflow file cannot include another template workflow file.

The **get-vcpkg** action is an attempt to create a declarative action for facilitating the workflow for projects based on the following:
- C/C++ based projects.
- CMake based build system.
- vcpkg used for dependency management.

- `vpckg` is assumed to be fetched and checked at at location `${{ github.workspace }}/vcpkg`, or you can set it to whatever you want by fetching it with action/checkout
- The cache key is computed.
- The cache key is used to restore `vcpkg` and its previously built binaries from the GitHub cache service.

#### Notes

Good companions are:
- the [get-cmake](https://github.com/marketplace/actions/get-cmake) action.

Alternative to this action are the following actions:
- the [run-cmake](https://github.com/marketplace/actions/run-cmake) action.
- the [run-cmake](https://github.com/marketplace/actions/run-cmake) action.

# vcpkg must be already checked out. Two options:
# 1. Highly suggested: use vcpkg as submodule of your repository, for example under /vcpkg/.
# - uses: lukka/get-vcpkg
# # This is useless as it is the default, but shown here anyway:
# with:
# ${{ github.workspace }}/vcpkg
# 2. Another option is to checkout it prior this action, e.g.,:
# - uses: actions/checkout@v2
# with:
# repository: myname/myvcpkg
# path: vcpkg

## Quickstart

### Setup vcpkg and use CMake with a vcpkg.json manifest to install dependencies and build your project

```yaml
jobs:
build:
steps:
# Install latest CMake.
- uses: lukka/get-cmake@latest

TBD
```

### Flowchart

![get-vcpkg flowchart](https://raw.githubusercontent.com/lukka/get-vcpkg/flowchart.png
)

## The ***get-vcpkg*** action

Features:
TBD

### Action reference: all input/output parameters

Description of all input parameters: [action.yml](https://github.com/lukka/get-vcpkg/blob/main/action.yml)

## Best practices

### Use **vcpkg** as a submodule of your repository

When using **vcpkg**, be aware of how it works, specifically:
- a specific version of `vcpkg` must be used either locally and on build servers;
- a specific version of `vcpkg` is identified by the commit id of the used vcpkg repository;
- it not possible to choose which version of a port to install, instead it is the used version of `vcpkg` that establishes which version (just one) of a port is available;

To sum up, **you need to pin the specific version of vcpkg you want to use to keep a consistent development experience between local and remote build environments.** This is accomplished by **using vcpkg as submodule of your Git repository**; this way the version of `vcpkg` used is implied by the commit id specified by the submodule for `vcpkg`.

### Use vcpkg's vcpkg.json file to specify the dependencies

The [vcpkg.json](https://github.com/microsoft/vcpkg/blob/master/docs/specifications/manifests.md) is a manifest file that declaratively specifies the dependencies to be installed.
The file is being used automatically by running CMake when:
- starting CMake with the `vcpkg.cmake` toolchain file.
- the root CMake source directory contains a [vcpkg.json](https://github.com/microsoft/vcpkg/blob/master/docs/specifications/manifests.md) file.

When conditions are satisfied, the toolchain execution starts [vcpkg](https://github.com/microsoft/vcpkg) to install the packages declared in the manifest file.

*Putting this manifest-like file under source control is highly recommended as this helps to run vcpkg the same exact way locally and remotely on the build servers.**
The dependencies specified in the vcpkg.json file are installed when CMake runs (e.g., at [run-cmake](https://github.com/lukka/run-cmake) time).

## Samples

TBD
## Contributing

Read [CONTRIBUTING.md](CONTRIBUTING.md)

# License

All the content in this repository is licensed under the [MIT License](LICENSE.txt).

Copyright (c) 2021 Luca Cappa