Introdução: Quando "funciona na minha máquina" é um desastre
Todo desenvolvedor C++ já ouviu pelo menos uma vez a frase: "Funciona aqui, estranho que está quebrando aí". Ou ele mesmo a disse. Compilação de templates, linkagem, peculiaridades de diferentes padrões (C++17, C++20), macros dependentes de plataforma — C++ está cheio de surpresas que surgem ao mudar de ambiente.
O pipeline CI/CD (Integração Contínua / Implantação Contínua) para C++ não é um luxo, mas uma necessidade. Ele compila o projeto automaticamente, executa testes, verifica a qualidade do código e, em caso de sucesso, implanta a aplicação no servidor (ou publica a biblioteca). Neste artigo, configuraremos um pipeline completo do zero, usando GitHub Actions, CMake e C++. Você receberá uma configuração pronta que pode ser adaptada ao seu projeto.
1. Preparação do projeto: estrutura e sistema de build
Antes de escrever o pipeline, é preciso organizar o projeto. Usaremos CMake — o padrão de facto para projetos C++ modernos. Nosso exemplo será um utilitário simples para processamento de strings com testes unitários usando Google Test.
Estrutura do repositório
my_cpp_project/├── .github/│ └── workflows/│ └── ci.yml # Arquivo do pipeline├── src/│ ├── main.cpp│ └── string_utils.cpp├── include/│ └── string_utils.hpp├── tests/│ ├── CMakeLists.txt│ └── test_string_utils.cpp├── CMakeLists.txt # CMake raiz├── Dockerfile # Para o deploy final└── README.mdCMakeLists.txt raiz
Compilamos a biblioteca e o executável. Observe a exportação dos testes:
cmake_minimum_required(VERSION 3.20)project(MyStringUtils VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Biblioteca principaladd_library(string_utils STATIC src/string_utils.cpp include/string_utils.hpp)target_include_directories(string_utils PUBLIC include)
# Executáveladd_executable(my_app src/main.cpp)target_link_libraries(my_app PRIVATE string_utils)
# Testes (opcionais, ativados por opção)option(BUILD_TESTS "Build unit tests" ON)if(BUILD_TESTS) enable_testing() add_subdirectory(tests)endif()Exemplo de teste (tests/test_string_utils.cpp)
#include <gtest/gtest.h>#include "string_utils.hpp"
TEST(StringUtilsTest, ToUpper) { EXPECT_EQ(to_upper("hello"), "HELLO"); EXPECT_EQ(to_upper("C++20"), "C++20");}
TEST(StringUtilsTest, Trim) { EXPECT_EQ(trim(" spaced "), "spaced"); EXPECT_EQ(trim("\\t\\r"), "");}Agora que o projeto está pronto, vamos ao principal — configurar o pipeline CI/CD para C++.
2. GitHub Actions: escrevendo o primeiro pipeline
GitHub Actions é a ferramenta mais popular para CI/CD em Open Source. Sua configuração é escrita em YAML e fica na pasta .github/workflows. Vamos criar o arquivo ci.yml.
Estrutura básica: execução ao fazer push e PR
name: C++ CI/CD Pipeline
on: push: branches: [ main, develop ] pull_request: branches: [ main ]
jobs: build-and-test: runs-on: ubuntu-latest
steps: - name: Checkout code uses: actions/checkout@v4
- name: Install dependencies run: | sudo apt-get update sudo apt-get install -y cmake g++ libgtest-dev
- name: Configure CMake run: cmake -B build -DCMAKE_BUILD_TYPE=Release
- name: Build run: cmake --build build --parallel $(nproc)
- name: Run tests run: cd build && ctest --output-on-failureEste é um pipeline CI/CD para C++ mínimo, mas já funcional. Se os testes falharem, o pipeline termina com erro e você recebe uma notificação. Mas vamos além