Dans cet article, je vais fournir un fichier yaml de configuration GitHub Actions pour les projets C++ utilisant CMake.
GitHub Actions est une infrastructure CI/CD fournie par GitHub. GitHub Actions Propose actuellement les machines virtuelles suivantes (exécuteurs) :
| Environnement virtuel | Étiquette de flux de travail YAML |
|---|---|
| Windows Server 2019 | windows-latest |
| Ubuntu 18.04 | ubuntu-latest ou ubuntu-18.04 |
| Ubuntu 16.04 | ubuntu-16.04 |
| macOS Catalina 10.15 | macOS-latest |
Chaque machine virtuelle dispose des mêmes ressources matérielles :
- Processeur à 2 cœurs
- 7 Go de mémoire RAM
- 14 Go d’espace disque SSD
Chaque tâche d’un workflow peut s’exécuter jusqu’à 6 heures d’exécution.
Malheureusement, lorsque j’ai activé GitHub Actions sur un projet C++, ce flux de travail m’a été présenté :
./configure make make check make distcheck
Ce n’est pas quelque chose que vous pouvez utiliser avec CMake cependant 
Hello world
Cistian adam a construit le programme C++ hello world suivant :
#include <iostream>
int main()
{
std::cout << "Hello world\n";
}
Avec le projet CMake suivant :
cmake_minimum_required(VERSION 3.16) project(main) add_executable(main main.cpp) install(TARGETS main) enable_testing() add_test(NAME main COMMAND main)
TL; DR voir le projet sur GitHub.
Matrice de construction
Cistian adam a commencé avec la matrice de construction suivante :
name: CMake Build Matrix
on: [push]
jobs:
build:
name: ${ { matrix.config.name } }
runs-on: ${ { matrix.config.os } }
strategy:
fail-fast: false
matrix:
config:
- {
name: "Windows Latest MSVC", artifact: "Windows-MSVC.tar.xz",
os: windows-latest,
build_type: "Release", cc: "cl", cxx: "cl",
environment_script: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat"
}
- {
name: "Windows Latest MinGW", artifact: "Windows-MinGW.tar.xz",
os: windows-latest,
build_type: "Release", cc: "gcc", cxx: "g++"
}
- {
name: "Ubuntu Latest GCC", artifact: "Linux.tar.xz",
os: ubuntu-latest,
build_type: "Release", cc: "gcc", cxx: "g++"
}
- {
name: "macOS Latest Clang", artifact: "macOS.tar.xz",
os: macos-latest,
build_type: "Release", cc: "clang", cxx: "clang++"
}
Latest CMake and Ninja
In the software installed on the runners page we can see that CMake is installed on all runners, but with different versions:
| Virtual environment | CMake Version |
|---|---|
| Windows Server 2019 | 3.16.0 |
| Ubuntu 18.04 | 3.12.4 |
| macOS Catalina 10.15 | 3.15.5 |
This would mean that one would have to limit the minimum CMake version to 3.12, or upgrade CMake.
CMake 3.16 comes with support for Precompile Headers and Unity Builds, which help reducing build times.
Since CMake and Ninja have GitHub Releases, I decided to download those GitHub releases. 
I used CMake as a scripting language, since the default scripting language for runners is different (bash, and powershell). CMake can execute processes, download files, extract archives.
- name: Download Ninja and CMake
id: cmake_and_ninja
shell: cmake -P {0}
run: |
set(ninja_version "1.9.0")
set(cmake_version "3.16.2")
message(STATUS "Using host CMake version: ${CMAKE_VERSION}")
if ("${ { runner.os } }" STREQUAL "Windows")
set(ninja_suffix "win.zip")
set(cmake_suffix "win64-x64.zip")
set(cmake_dir "cmake-${cmake_version}-win64-x64/bin")
elseif ("${ { runner.os } }" STREQUAL "Linux")
set(ninja_suffix "linux.zip")
set(cmake_suffix "Linux-x86_64.tar.gz")
set(cmake_dir "cmake-${cmake_version}-Linux-x86_64/bin")
elseif ("${ { runner.os } }" STREQUAL "macOS")
set(ninja_suffix "mac.zip")
set(cmake_suffix "Darwin-x86_64.tar.gz")
set(cmake_dir "cmake-${cmake_version}-Darwin-x86_64/CMake.app/Contents/bin")
endif()
set(ninja_url "https://github.com/ninja-build/ninja/releases/download/v${ninja_version}/ninja-${ninja_suffix}")
file(DOWNLOAD "${ninja_url}" ./ninja.zip SHOW_PROGRESS)
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ./ninja.zip)
set(cmake_url "https://github.com/Kitware/CMake/releases/download/v${cmake_version}/cmake-${cmake_version}-${cmake_suffix}")
file(DOWNLOAD "${cmake_url}" ./cmake.zip SHOW_PROGRESS)
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ./cmake.zip)
# Save the path for other steps
file(TO_CMAKE_PATH "$ENV{GITHUB_WORKSPACE}/${cmake_dir}" cmake_dir)
message("::set-output name=cmake_dir::${cmake_dir}")
if (NOT "${ { runner.os } }" STREQUAL "Windows")
execute_process(
COMMAND chmod +x ninja
COMMAND chmod +x ${cmake_dir}/cmake
)
endif()
Configure step
Now that I have CMake and Ninja, all I have to do is configure the project like this:
- name: Configure
shell: cmake -P {0}
run: |
set(ENV{CC} ${ { matrix.config.cc } })
set(ENV{CXX} ${ { matrix.config.cxx } })
if ("${ { runner.os } }" STREQUAL "Windows" AND NOT "x${ { matrix.config.environment_script } }" STREQUAL "x")
execute_process(
COMMAND "${ { matrix.config.environment_script } }" && set
OUTPUT_FILE environment_script_output.txt
)
file(STRINGS environment_script_output.txt output_lines)
foreach(line IN LISTS output_lines)
if (line MATCHES "^([a-zA-Z0-9_-]+)=(.*)$")
set(ENV{${CMAKE_MATCH_1} } "${CMAKE_MATCH_2}")
endif()
endforeach()
endif()
file(TO_CMAKE_PATH "$ENV{GITHUB_WORKSPACE}/ninja" ninja_program)
execute_process(
COMMAND ${ { steps.cmake_and_ninja.outputs.cmake_dir } }/cmake
-S .
-B build
-D CMAKE_BUILD_TYPE=${ { matrix.config.build_type } }
-G Ninja
-D CMAKE_MAKE_PROGRAM=${ninja_program}
RESULT_VARIABLE result
)
if (NOT result EQUAL 0)
message(FATAL_ERROR "Bad exit status")
endif()
Cistian adam a définit les variables d’environnement et pour MSVC, il a dû exécuter le script, pour obtenir toutes les variables d’environnement et les définir pour le script d’exécution de CMake.CCCXXvcvars64.bat
Étape de construction
L’étape de génération implique l’exécution du paramètre CMake avec :--build
- name: Build
shell: cmake -P {0}
run: |
set(ENV{NINJA_STATUS} "[%f/%t %o/sec] ")
if ("${ { runner.os } }" STREQUAL "Windows" AND NOT "x${ { matrix.config.environment_script } }" STREQUAL "x")
file(STRINGS environment_script_output.txt output_lines)
foreach(line IN LISTS output_lines)
if (line MATCHES "^([a-zA-Z0-9_-]+)=(.*)$")
set(ENV{${CMAKE_MATCH_1} } "${CMAKE_MATCH_2}")
endif()
endforeach()
endif()
execute_process(
COMMAND ${ { steps.cmake_and_ninja.outputs.cmake_dir } }/cmake --build build
RESULT_VARIABLE result
)
if (NOT result EQUAL 0)
message(FATAL_ERROR "Bad exit status")
endif()
Cistian adam a définit la variable, pour voir à quelle vitesse la compilation est dans les coureurs respectifs.NINJA_STATUS
Pour MSVC,il a réutilisé le script de l’étape Configurer.environment_script_output.txt
Étape Exécuter les tests
Cette étape appelle avec le nombre de cœurs passés en argument :ctest-j
- name: Run tests
shell: cmake -P {0}
run: |
include(ProcessorCount)
ProcessorCount(N)
execute_process(
COMMAND ${ { steps.cmake_and_ninja.outputs.cmake_dir } }/ctest -j ${N}
WORKING_DIRECTORY build
RESULT_VARIABLE result
)
if (NOT result EQUAL 0)
message(FATAL_ERROR "Running tests failed!")
endif()
Étapes d’installation, d’emballage et de téléchargement
Cette étape implique l’exécution de CMake avec , puis la création d’une archive avec CMake, et en le téléchargeant en tant qu’artefact de build.--installtar.xz
- name: Install Strip
run: ${ { steps.cmake_and_ninja.outputs.cmake_dir } }/cmake --install build --prefix instdir --strip
- name: Pack
working-directory: instdir
run: ${ { steps.cmake_and_ninja.outputs.cmake_dir } }/cmake -E tar cJfv ../${ { matrix.config.artifact } } .
- name: Upload
uses: actions/upload-artifact@v1
with:
path: ./${ { matrix.config.artifact } }
name: ${ { matrix.config.artifact } }
il n’a pas utilisé CMake comme langage de script, car cela implique simplement d’appeler CMake avec des paramètres, et le les shells par défaut peuvent gérer cela 
Gestion des rejets
Lorsque vous marquez une version dans git, vous souhaitez également que les artefacts de build soient promus en tant que versions :
git tag -a v1.0.0 -m "Release v1.0.0" git push origin v1.0.0
Le code pour ce faire est ci-dessous, est déclenché si le refpath git contient :tags/v
release:
if: contains(github.ref, 'tags/v')
runs-on: ubuntu-latest
needs: build
steps:
- name: Create Release
id: create_release
uses: actions/create-release@v1.0.0
env:
GITHUB_TOKEN: ${ { secrets.GITHUB_TOKEN } }
with:
tag_name: ${ { github.ref } }
release_name: Release ${ { github.ref } }
draft: false
prerelease: false
- name: Store Release url
run: |
echo "${ { steps.create_release.outputs.upload_url } }" > ./upload_url
- uses: actions/upload-artifact@v1
with:
path: ./upload_url
name: upload_url
publish:
if: contains(github.ref, 'tags/v')
name: ${ { matrix.config.name } }
runs-on: ${ { matrix.config.os } }
strategy:
fail-fast: false
matrix:
config:
- {
name: "Windows Latest MSVC", artifact: "Windows-MSVC.tar.xz",
os: ubuntu-latest
}
- {
name: "Windows Latest MinGW", artifact: "Windows-MinGW.tar.xz",
os: ubuntu-latest
}
- {
name: "Ubuntu Latest GCC", artifact: "Linux.tar.xz",
os: ubuntu-latest
}
- {
name: "macOS Latest Clang", artifact: "macOS.tar.xz",
os: ubuntu-latest
}
needs: release
steps:
- name: Download artifact
uses: actions/download-artifact@v1
with:
name: ${ { matrix.config.artifact } }
path: ./
- name: Download URL
uses: actions/download-artifact@v1
with:
name: upload_url
path: ./
- id: set_upload_url
run: |
upload_url=`cat ./upload_url`
echo ::set-output name=upload_url::$upload_url
- name: Upload to Release
id: upload_to_release
uses: actions/upload-release-asset@v1.0.1
env:
GITHUB_TOKEN: ${ { secrets.GITHUB_TOKEN } }
with:
upload_url: ${ { steps.set_upload_url.outputs.upload_url } }
asset_path: ./${ { matrix.config.artifact } }
asset_name: ${ { matrix.config.artifact } }
asset_content_type: application/x-gtar
This looks complicated, but it’s needed since needs to be called only once, otherwise it will fail. See issue #14, issue #27 for more information.actions/create-release
Même si vous pouvez utiliser un flux de travail pendant 6 heures, le expire dans une heure. Vous pouvez soit créer un jeton personnel, soit Téléchargez les artefacts manuellement dans la version. Voir cette communauté GitHub pour plus d’informations.secrets.GITHUB_TOKEN
Fermeture
L’activation de GitHub Actions sur votre projet CMake est aussi simple que de créer un fichier avec le contenu de .github/workflows/build_cmake.ymlbuild_cmake.yml.
Et si vous souhaitez nous soutenir davantage, vous pouvez nous offrir un café virtuel ☕️. Merci pour votre soutien ❤️ !
Nous ne soutenons ni ne promouvons aucune forme de piraterie, de violation du droit d’auteur ou d’utilisation illégale de logiciels, de contenus vidéo ou de ressources numériques.
Toute mention de sites, outils ou plateformes tiers est uniquement à titre informatif. Il incombe à chaque lecteur de respecter les lois de son pays ainsi que les conditions d’utilisation des services mentionnés.
Nous encourageons fortement l’utilisation de solutions légales, open source ou officielles, de manière responsable.


Commentaires