C++ CI/CD GitHub Actions 완벽 가이드 | 워크플로·매트릭스·캐싱·아티팩트·배포

C++ CI/CD GitHub Actions 완벽 가이드 | 워크플로·매트릭스·캐싱·아티팩트·배포

이 글의 핵심

C++ CI/CD GitHub Actions 입니다. 워크플로 작성, 매트릭스 빌드, 캐싱 전략, 아티팩트 관리 방법을 실전 예제로 다룹니다. C++ 프로젝트에 CI/CD를 붙이다 보면 이런 상황을 자주 마주합니다: "로컬에서는 되는데 CI에서만 빌드가 실패해요." "vcpkg로 fmt, spdlog 설치하는데 20분 넘게 걸려요.

들어가며: “로컬에서는 되는데 CI에서만 빌드 실패해요”

실제 겪는 문제 시나리오

C++ 프로젝트에 CI/CD를 붙이다 보면 이런 상황을 자주 마주합니다:

"로컬에서는 되는데 CI에서만 빌드가 실패해요."
"vcpkg로 fmt, spdlog 설치하는데 20분 넘게 걸려요."
"푸시할 때마다 전체 빌드가 돌아서 30분씩 기다려요."
"Linux는 되는데 Windows·macOS 빌드는 어떻게 해요?"
"빌드 결과물을 릴리스에 자동으로 올리고 싶어요."
"캐시가 적용됐는데 왜 매번 vcpkg를 다시 빌드해요?"
"find_package(fmt) failed — CI에서만 못 찾아요."
"매트릭스 빌드에서 Windows job만 실패해요."
"아티팩트 업로드 용량 초과 에러가 나요."
"시크릿·환경 변수 설정이 복잡해요."

GitHub Actions로 해결:

문제GitHub Actions 해결
로컬과 CI 환경 차이동일한 runner 이미지·CMake preset으로 재현
vcpkg 설치 지연Binary Caching(x-gha)·actions/cache로 캐싱
전체 빌드 반복build/·vcpkg installed/ 캐시 키 설계
멀티 플랫폼strategy.matrix로 ubuntu·macos·windows 병렬
릴리스 배포actions/upload-release-asset·create-release
find_package 실패CMAKE_TOOLCHAIN_FILE·vcpkg.json Manifest 모드
Windows 빌드 실패MSVC preset·Ninja Multi-Config
아티팩트 용량압축·필요한 파일만 업로드·split job

요구 환경: GitHub 저장소, CMake 3.19+, vcpkg Manifest 모드 또는 Conan

이 글을 읽으면:

  • GitHub Actions 기본 워크플로 구조를 이해할 수 있습니다.
  • 매트릭스 빌드로 Linux·macOS·Windows를 병렬 검증할 수 있습니다.
  • vcpkg·빌드 캐싱으로 CI 시간을 크게 단축할 수 있습니다.
  • 아티팩트 업로드·릴리스 배포를 자동화할 수 있습니다.
  • 자주 발생하는 에러와 해결법을 알 수 있습니다.
  • 프로덕션 수준의 CI/CD 패턴을 적용할 수 있습니다.

실무 적용 경험: 이 글은 대규모 C++ 프로젝트에서 실제로 겪은 문제와 해결 과정을 바탕으로 작성되었습니다. 책이나 문서에서 다루지 않는 실전 함정과 디버깅 팁을 포함합니다.

목차

  1. 문제 시나리오 상세
  2. 기본 워크플로 구조
  3. 완전한 CI 워크플로 예제
  4. 매트릭스 빌드
  5. 캐싱 전략
  6. 아티팩트 업로드·다운로드
  7. 배포 (릴리스·Docker)
  8. 자주 발생하는 에러와 해결법
  9. 베스트 프랙티스
  10. 프로덕션 패턴
  11. 구현 체크리스트
  12. 정리

1. 문제 시나리오 상세

시나리오 1: 로컬과 CI 환경 불일치

상황: 로컬 Ubuntu 22.04, GCC 12, Ninja로 빌드 성공
CI: ubuntu-latest(22.04), 기본 GCC, Makefile → "undefined reference"
원인: Generator·컴파일러·빌드 타입이 다름
해결: CMake Presets의 ci-release preset + 동일 runner 이미지

시나리오 2: vcpkg 의존성 설치 지연

상황: vcpkg.json에 fmt, spdlog, boost-asio 등 10개 패키지
문제: 매 CI 실행마다 vcpkg install → 15~25분 소요
해결: vcpkg Binary Caching(x-gha) 또는 actions/cache로 installed/ 캐싱

시나리오 3: 푸시할 때마다 전체 빌드

상황: 소스 일부만 수정했는데 매번 configure·build·test 전체 실행
문제: 5분이면 될 빌드가 30분 걸림
해결: hashFiles로 CMakeLists.txt·vcpkg.json·소스 변경 시에만 캐시 무효화

시나리오 4: 멀티 플랫폼 검증 필요

상황: Windows·macOS 사용자도 있어 세 플랫폼 모두 빌드 검증 필요
문제: 로컬에서 Windows 빌드 환경 구축이 어려움
해결: strategy.matrix로 ubuntu-22.04, macos-14, windows-2022 병렬 실행

시나리오 5: 릴리스 배포 수동 작업

상황: 태그 푸시 시 수동으로 바이너리 빌드·업로드
문제: 실수·누락·시간 소모
해결: release workflow에서 빌드 → 아티팩트 → GitHub Release에 업로드

시나리오 6: find_package CI에서만 실패

상황: 로컬 Classic 모드로 vcpkg install한 패키지가 CI에 없음
문제: CI에는 빈 runner라 패키지가 없음
해결: Manifest 모드(vcpkg.json) + CMAKE_TOOLCHAIN_FILE로 CI에서 자동 설치

시나리오 7: Windows에서 MSVC 빌드 실패

상황: Linux용 CMake 설정을 Windows에 그대로 적용
문제: Ninja 단일 설정 vs MSVC 멀티 설정 차이
해결: Windows용 preset에서 Ninja Multi-Config, --config Release

시나리오 8: 캐시 키 설계 실패

상황: actions/cache를 넣었는데 매번 "Cache not found"
문제: key가 너무 구체적이거나 hashFiles 대상이 잘못됨
해결: restore-keys로 fallback, vcpkg.json·CMakeLists.txt 포함
flowchart TB
  subgraph Problems[문제]
    P1[로컬 vs CI 불일치]
    P2[vcpkg 설치 지연]
    P3[전체 빌드 반복]
    P4[멀티 플랫폼]
    P5[수동 배포]
  end

  subgraph Solutions[GitHub Actions 해결]
    S1[CMake Presets + 동일 이미지]
    S2[Binary Caching / actions/cache]
    S3[캐시 키 설계]
    S4[strategy.matrix]
    S5[release workflow]
  end

  P1 --> S1
  P2 --> S2
  P3 --> S3
  P4 --> S4
  P5 --> S5

2. 기본 워크플로 구조

2.1 파일 위치

.github/
  workflows/
    ci.yml          # PR·push 시 빌드·테스트
    release.yml     # 태그 푸시 시 릴리스 배포

2.2 최소 워크플로 예제

name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  build:
    runs-on: ubuntu-22.04
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Install CMake
        uses: jwlawson/actions-setup-cmake@v2
        with:
          cmake-version: '3.28'

      - name: Configure
        run: cmake --preset ci-release

      - name: Build
        run: cmake --build --preset ci-release

      - name: Test
        run: ctest --preset ci-test

핵심:

  • on: 트리거 조건 (push, pull_request, workflow_dispatch 등)
  • jobs.build: 단일 job, runs-on으로 runner 지정
  • steps: 순차 실행. uses로 액션, run으로 셸 명령

2.3 CMake Presets와 연동

CMakePresets.jsonci-release preset이 있어야 합니다. CMake Presets 가이드 참고.

{
  "name": "ci-release",
  "inherits": "base",
  "cacheVariables": {
    "CMAKE_BUILD_TYPE": "Release"
  }
}

vcpkg 사용 시 toolchainFile로 vcpkg.cmake 지정. CI에서는 vcpkg.json Manifest 모드로 자동 설치됩니다.


3. 완전한 CI 워크플로 예제

3.1 vcpkg Manifest 모드 + CMake Presets

name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

env:
  VCPKG_BINARY_SOURCES: 'clear;x-gha,readwrite'

jobs:
  build:
    runs-on: ubuntu-22.04
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup vcpkg
        uses: lukka/run-vcpkg@v11
        with:
          vcpkgDirectory: '${{ github.workspace }}/vcpkg'
          runVcpkgInstall: false

      - name: Configure
        run: cmake --preset ci-release

      - name: Build
        run: cmake --build --preset ci-release

      - name: Test
        run: ctest --preset ci-test --output-on-failure

설명:

  • VCPKG_BINARY_SOURCES: 'clear;x-gha,readwrite': vcpkg Binary Caching을 GitHub Actions 캐시에 저장. run-vcpkg가 자동 설정해 주기도 함.
  • runVcpkgInstall: false: vcpkg install을 이 단계에서 하지 않음. CMake configure 시 vcpkg.cmake toolchain이 vcpkg.json을 읽고 자동 설치.
  • vcpkg를 submodule로 두면 vcpkgDirectory에 맞게 지정.

3.2 vcpkg 서브모듈 없이 사용

- name: Setup vcpkg
  uses: lukka/run-vcpkg@v11
  with:
    vcpkgGitCommitId: '2024.01.15'
    runVcpkgInstall: false

vcpkgGitCommitId로 고정 커밋을 사용하면 재현 가능한 빌드가 됩니다.

3.3 수동 캐시 (run-vcpkg 미사용 시)

- name: Cache vcpkg
  uses: actions/cache@v4
  with:
    path: |
      ${{ github.workspace }}/vcpkg/installed
      ${{ github.workspace }}/vcpkg/buildtrees
    key: ${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json', 'vcpkg.lock') }}
    restore-keys: |
      ${{ runner.os }}-vcpkg-

- name: Install vcpkg dependencies
  run: |
    ./vcpkg/bootstrap-vcpkg.sh
    ./vcpkg install --triplet ${{ env.VCPKG_DEFAULT_TRIPLET }}

주의: vcpkg의 x-gha Binary Caching을 쓰는 편이 더 안정적입니다.


4. 매트릭스 빌드

4.1 Linux·macOS·Windows

jobs:
  build:
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-22.04
            preset: linux-release
          - os: macos-14
            preset: macos-release
          - os: windows-2022
            preset: msvc-release
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4

      - name: Setup vcpkg
        uses: lukka/run-vcpkg@v11
        with:
          vcpkgDirectory: '${{ github.workspace }}/vcpkg'
          runVcpkgInstall: false

      - name: Configure
        run: cmake --preset ${{ matrix.preset }}

      - name: Build
        run: cmake --build --preset ${{ matrix.preset }}

      - name: Test
        run: ctest --preset ci-test --output-on-failure

설명:

  • fail-fast: false: 한 job 실패 시 다른 job은 계속 실행.
  • matrix.include: os·preset 조합을 명시.
  • CMakePresets.jsonlinux-release, macos-release, msvc-release preset 필요.

4.2 컴파일러 매트릭스 (Linux)

strategy:
  matrix:
    compiler: [gcc, clang]
    build_type: [Debug, Release]
runs-on: ubuntu-22.04
steps:
  - uses: actions/checkout@v4

  - name: Install ${{ matrix.compiler }}
    run: |
      if [ "${{ matrix.compiler }}" = "gcc" ]; then
        sudo apt-get update && sudo apt-get install -y g++-12
        echo "CXX=g++-12" >> $GITHUB_ENV
      else
        sudo apt-get update && sudo apt-get install -y clang-15
        echo "CXX=clang++-15" >> $GITHUB_ENV
      fi

  - name: Configure
    run: |
      cmake --preset ci-release \
        -DCMAKE_CXX_COMPILER=${{ matrix.compiler == 'gcc' && 'g++-12' || 'clang++-15' }}

  - name: Build
    run: cmake --build --preset ci-release

4.3 exclude로 조합 제외

strategy:
  matrix:
    os: [ubuntu-22.04, macos-14, windows-2022]
    config: [Debug, Release]
    exclude:
      - os: windows-2022
        config: Debug

Windows Debug는 제외하고 싶을 때 사용.

4.4 Windows에서 MSVC 설정

- name: Configure (Windows)
  if: runner.os == 'Windows'
  run: cmake --preset msvc-release

- name: Build (Windows)
  if: runner.os == 'Windows'
  run: cmake --build --preset msvc-release --config Release

MSVC preset은 Ninja Multi-Config 또는 Visual Studio 17 2022 generator 사용. 빌드 시 --config Release 필요.


5. 캐싱 전략

5.1 vcpkg Binary Caching (x-gha)

vcpkg 2021.01+에서 GitHub Actions 캐시를 Binary Cache로 사용할 수 있습니다.

env:
  VCPKG_BINARY_SOURCES: 'clear;x-gha,readwrite'

lukka/run-vcpkg 사용 시 기본으로 설정됩니다. 별도 actions/cache 불필요.

5.2 actions/cache로 빌드 디렉터리

- name: Cache build
  uses: actions/cache@v4
  with:
    path: |
      build
      out
    key: ${{ runner.os }}-cmake-${{ hashFiles('CMakeLists.txt', 'CMakePresets.json', '**/CMakeLists.txt', 'vcpkg.json') }}
    restore-keys: |
      ${{ runner.os }}-cmake-

주의: configure 결과가 캐시되면 CMake 변수 변경이 반영되지 않을 수 있습니다. 소스·설정 변경 시 캐시가 무효화되도록 hashFiles에 필요한 파일을 넣습니다.

5.3 vcpkg installed 캐시 (수동)

- name: Cache vcpkg
  uses: actions/cache@v4
  with:
    path: ${{ github.workspace }}/vcpkg/installed
    key: ${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json', 'vcpkg.lock') }}
    restore-keys: |
      ${{ runner.os }}-vcpkg-

5.4 Conan 캐시

- name: Cache Conan
  uses: actions/cache@v4
  with:
    path: ~/.conan2
    key: ${{ runner.os }}-conan-${{ hashFiles('conanfile.txt', 'conanfile.py') }}
    restore-keys: |
      ${{ runner.os }}-conan-

5.5 캐시 키 설계 원칙

대상key에 포함할 것restore-keys
vcpkgvcpkg.json, vcpkg.lockos-vcpkg- (fallback)
CMake buildCMakeLists.txt, preset, 소스os-cmake-
Conanconanfile.txt, conanfile.pyos-conan-

restore-keys에 prefix만 두면 부분 일치로 이전 캐시를 사용합니다. 완전 일치가 없을 때 유용합니다.


6. 아티팩트 업로드·다운로드

6.1 빌드 결과물 업로드

- name: Upload artifacts
  uses: actions/upload-artifact@v4
  with:
    name: build-${{ matrix.os }}-${{ matrix.preset }}
    path: |
      build/*/myapp
      build/*/myapp.exe
    if-no-files-found: warn

path에 와일드카드 사용 가능. preset별로 build/ci-release/ 등 경로가 다를 수 있으니 build/*/로 유연하게 지정.

6.2 여러 아티팩트를 하나로 합치기

jobs:
  build:
    # ... 빌드 단계 ...
    - uses: actions/upload-artifact@v4
      with:
        name: build-${{ matrix.os }}
        path: build/

  merge:
    needs: build
    runs-on: ubuntu-22.04
    steps:
      - name: Download all
        uses: actions/download-artifact@v4
        with:
          pattern: build-*
          path: artifacts
          merge-multiple: true

      - name: List
        run: ls -la artifacts/

6.3 아티팩트 압축으로 용량 절감

- name: Create archive
  run: |
    cd build
    tar czvf ../release-linux.tar.gz myapp
    cd ..

- name: Upload
  uses: actions/upload-artifact@v4
  with:
    name: release-linux
    path: release-linux.tar.gz

6.4 아티팩트 보존 기간

- uses: actions/upload-artifact@v4
  with:
    name: build
    path: build/
    retention-days: 7

기본 90일. 저장소 용량 관리 시 조정.

6.5 용량 제한

  • 저장소당 아티팩트 총 용량 제한 있음 (GitHub 플랜별 상이).
  • 개별 아티팩트는 압축 후 업로드.
  • 필요한 바이너리만 업로드 (path를 좁게 지정).

7. 배포 (릴리스·Docker)

7.1 GitHub Release에 자동 업로드

name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    strategy:
      matrix:
        include:
          - os: ubuntu-22.04
            preset: linux-release
            artifact: myapp
          - os: macos-14
            preset: macos-release
            artifact: myapp
          - os: windows-2022
            preset: msvc-release
            artifact: myapp.exe
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4

      - name: Setup vcpkg
        uses: lukka/run-vcpkg@v11
        with:
          vcpkgDirectory: '${{ github.workspace }}/vcpkg'
          runVcpkgInstall: false

      - name: Configure
        run: cmake --preset ${{ matrix.preset }}

      - name: Build
        run: cmake --build --preset ${{ matrix.preset }}

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.os }}-${{ matrix.artifact }}

  release:
    needs: build
    runs-on: ubuntu-22.04
    permissions:
      contents: write
    steps:
      - name: Download all artifacts
        uses: actions/download-artifact@v4
        with:
          path: artifacts

      - name: Create Release
        uses: softprops/action-gh-release@v2
        with:
          files: |
            artifacts/ubuntu-22.04-myapp
            artifacts/macos-14-myapp
            artifacts/windows-2022-myapp.exe
          generate_release_notes: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

설명:

  • on.push.tags: 'v*': v1.0.0 같은 태그 푸시 시 실행.
  • permissions.contents: write: 릴리스 생성·업로드에 필요.
  • GITHUB_TOKEN: 자동 제공, 별도 시크릿 불필요.

7.2 Docker 이미지 빌드·푸시

- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3

- name: Login to Container Registry
  uses: docker/login-action@v3
  with:
    registry: ghcr.io
    username: ${{ github.actor }}
    password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
  uses: docker/build-push-action@v6
  with:
    context: .
    file: ./Dockerfile
    push: true
    tags: ghcr.io/${{ github.repository }}:latest

7.3 Dockerfile 예시 (멀티 스테이지)

FROM ubuntu:22.04 AS builder
RUN apt-get update && apt-get install -y cmake ninja-build g++
COPY . /src
WORKDIR /src
RUN cmake --preset ci-release && cmake --build --preset ci-release

FROM ubuntu:22.04
COPY --from=builder /src/build/ci-release/myapp /usr/local/bin/
CMD [myapp]

7.4 조건부 배포 (main 브랜치만)

release:
  if: github.ref == 'refs/heads/main' && github.event_name == 'push'
  needs: build
  # ...

8. 자주 발생하는 에러와 해결법

에러 1: “Could not find preset “ci-release""

원인: CMakePresets.jsonci-release가 없거나, condition으로 현재 환경에서 비활성화됨.

해결법:

# 로컬에서 preset 목록 확인
cmake --list-presets

CMakePresets.jsonci-release를 추가하고, condition이 CI 환경($env{CI} 등)에서 true인지 확인하세요.

에러 2: “find_package(fmt) failed”

원인: CI에 vcpkg 패키지가 설치되지 않음. Classic 모드만 로컬에서 사용했거나, CMAKE_TOOLCHAIN_FILE 미지정.

해결법:

# vcpkg Manifest 모드 + toolchain 지정
# CMakePresets.json의 ci-release에:
# "toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"

그리고 run-vcpkg 또는 vcpkg install 단계가 configure 전에 실행되는지 확인하세요.

에러 3: “Cache not found” — 캐시가 매번 miss

원인: key가 너무 구체적이거나, hashFiles 대상 파일이 없음.

해결법:

# hashFiles에 존재하는 파일만
key: ${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json') }}

# vcpkg.lock이 없으면 hashFiles가 실패할 수 있음
key: ${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json', 'vcpkg.lock') }}

vcpkg.lock이 없으면 vcpkg.json만 넣거나, hashFiles('**/vcpkg.json')로 경로를 유연하게.

에러 4: “Resource not accessible by integration”

원인: GITHUB_TOKEN 권한 부족. Release 생성·푸시에 contents: write 필요.

해결법:

permissions:
  contents: write

워크플로 또는 job 레벨에 추가.

에러 5: Windows에서 “cmake: command not found”

원인: Windows runner에 CMake가 기본 설치되어 있지만, 경로가 다를 수 있음. 또는 actions-setup-cmake 미사용.

해결법:

- name: Install CMake
  uses: jwlawson/actions-setup-cmake@v2
  with:
    cmake-version: '3.28'

에러 6: “VCPKG_ROOT not set”

원인: vcpkg 경로를 모르는 상태에서 toolchain 또는 vcpkg install 실행.

해결법:

- name: Setup vcpkg
  uses: lukka/run-vcpkg@v11
  # run-vcpkg가 VCPKG_ROOT 설정

- name: Configure
  run: cmake --preset ci-release
  env:
    VCPKG_ROOT: ${{ github.workspace }}/vcpkg

run-vcpkg 사용 시 보통 자동 설정됩니다.

에러 7: “Artifact upload failed: Resource not found”

원인: path에 지정한 파일·디렉터리가 없음.

해결법:

- uses: actions/upload-artifact@v4
  with:
    name: build
    path: build/
    if-no-files-found: warn

if-no-files-found: warn으로 실패 대신 경고만. 또는 path를 실제 빌드 출력 경로에 맞게 수정 (preset별로 build/ci-release/ 등).

에러 8: “The process ‘/usr/bin/bash’ failed with exit code 1”

원인: run 단계에서 명령이 실패. CMake configure/build 에러, 테스트 실패 등.

해결법: 해당 step의 로그를 확인. --output-on-failure로 ctest 출력을 늘리기:

- name: Test
  run: ctest --preset ci-test --output-on-failure

에러 9: macOS에서 “xcode-select” 관련 에러

원인: Xcode 명령줄 도구 미설정.

해결법:

- name: Select Xcode
  run: sudo xcode-select -s /Applications/Xcode_15.2.app/Contents/Developer
  if: runner.os == 'macOS'

또는 macos-14 등 최신 runner는 기본 설정된 경우가 많습니다.

에러 10: “No space left on device”

원인: runner 디스크 부족. vcpkg·빌드 산출물이 큼.

해결법:

  • 불필요한 캐시 정리.
  • path를 좁혀서 캐시에 넣는 데이터 축소.
  • Docker 등에서 멀티 스테이지로 최종 이미지 크기 축소.

에러 11: 매트릭스에서 Windows만 실패

원인: Windows는 MSVC·Ninja Multi-Config 등 설정이 다름. --config Release 누락.

해결법:

- name: Build (Windows)
  run: cmake --build --preset msvc-release --config Release

에러 12: “conan: command not found”

원인: Conan 미설치.

해결법:

- name: Install Conan
  run: pip install conan
  # 또는
- uses: conan-io/setup-conan@v2
  with:
    conan-version: '2.x'

9. 베스트 프랙티스

9.1 액션 버전 고정

# ❌ 나쁜 예
uses: actions/checkout@main

# ✅ 좋은 예
uses: actions/checkout@v4

@main은 변경될 수 있어 재현성이 떨어집니다. @v4처럼 major 버전을 고정하세요.

9.2 fail-fast 설정

strategy:
  fail-fast: false

매트릭스에서 한 job 실패 시 나머지도 중단하지 않으려면 false로 설정.

9.3 timeout 설정

jobs:
  build:
    timeout-minutes: 30

무한 대기 방지.

9.4 concurrency로 중복 실행 제한

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

같은 브랜치에 연속 푸시 시 이전 실행을 취소.

9.5 환경 변수는 env로

env:
  VCPKG_BINARY_SOURCES: 'clear;x-gha,readwrite'
  CXX: g++-12

job 또는 step 레벨에서 env로 지정하면 가독성이 좋습니다.

9.6 시크릿 노출 방지

# ❌ 나쁜 예
run: echo "Key is ${{ secrets.API_KEY }}"

# ✅ 좋은 예
run: ./deploy.sh
env:
  API_KEY: ${{ secrets.API_KEY }}

secrets를 로그에 출력하지 않도록 합니다. GitHub는 자동 마스킹을 하지만, 스크립트에서 echo하지 않는 것이 안전합니다.

9.7 필요 시에만 checkout

- uses: actions/checkout@v4
  with:
    fetch-depth: 0

fetch-depth: 0은 전체 히스토리. Git describe·캐시 키에 커밋이 필요할 때 사용. 기본 1이면 shallow clone으로 빠름.

9.8 빌드 산출물 경로 통일

CMake Presets에서 binaryDir${sourceDir}/build/${presetName}로 통일하면, 아티팩트 pathbuild/*/myapp처럼 단순하게 지정할 수 있습니다.


10. 프로덕션 패턴

10.1 PR과 Push 분리

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

jobs:
  build:
    steps: [...]
  # PR에서는 빌드·테스트만
  # push에서는 추가로 아티팩트 업로드 등

10.2 빌드·테스트·배포 단계 분리

jobs:
  build:
    outputs:
      build_id: ${{ steps.meta.outputs.id }}
  test:
    needs: build
  deploy:
    needs: [build, test]
    if: github.ref == 'refs/heads/main'

10.3 재사용 가능한 워크플로

workflow_call로 입력을 받는 워크플로를 정의하고, 다른 워크플로에서 uses: ./.github/workflows/build.yml로 호출할 수 있습니다.

# .github/workflows/build.yml
name: Build
on:
  workflow_call:
    inputs:
      preset:
        required: true
        type: string
jobs:
  build:
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4
      - run: cmake --preset ${{ inputs.preset }}
      - run: cmake --build --preset ${{ inputs.preset }}

10.4 Self-hosted runner

runs-on: [self-hosted, linux, x64]

사내 하드웨어·특수 환경이 필요할 때 사용. GitHub 호스트 runner보다 설정이 필요합니다.

10.5 의존성 업데이트 자동화 (Dependabot)

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"

액션 버전 업데이트 PR을 자동 생성.

10.6 워크플로 상태 배지

README에 ![CI Status](https://github.com/OWNER/REPO/actions/workflows/ci.yml/badge.svg) 추가.

10.7 Slack·이메일 알림 (선택)

- name: Notify on failure
  if: failure()
  uses: slackapi/slack-github-action@v1
  with:
    payload: |
      {
        "text": "Build failed: ${{ github.repository }}"
      }
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

11. 구현 체크리스트

기본 설정:

  • .github/workflows/ci.yml 생성
  • on.push, on.pull_request 트리거 설정
  • actions/checkout@v4 사용
  • CMake·Ninja 설치 (jwlawson/actions-setup-cmake, lukka/get-cmake 등)
  • 액션 버전 고정 (@v4, @v11 등)

CMake Presets:

  • CMakePresets.jsonci-release preset 정의
  • vcpkg 사용 시 toolchainFile 지정
  • cmake --preset, cmake --build --preset, ctest --preset 사용

캐싱:

  • vcpkg: VCPKG_BINARY_SOURCES: 'clear;x-gha,readwrite' 또는 run-vcpkg
  • build: actions/cachebuild/ 캐시 (선택)
  • 캐시 키에 hashFiles('vcpkg.json', 'CMakeLists.txt', ...) 포함

매트릭스:

  • strategy.matrix로 os·preset 조합
  • fail-fast: false (선택)
  • Windows 시 --config Release 지정

아티팩트·배포:

  • actions/upload-artifact로 빌드 결과 업로드
  • Release workflow: on.push.tags, softprops/action-gh-release
  • permissions.contents: write (릴리스 시)

에러 대응:

  • ctest --output-on-failure
  • if-no-files-found: warn (아티팩트)
  • timeout-minutes 설정

12. 정리

항목설명
트리거on.push, on.pull_request, on.push.tags
매트릭스strategy.matrix로 os·compiler·config 조합
vcpkg 캐싱VCPKG_BINARY_SOURCES: x-gha 또는 run-vcpkg
빌드 캐시actions/cache + hashFiles
아티팩트upload-artifact, download-artifact
릴리스softprops/action-gh-release, contents: write
CMake Presetsci-release 등 CI 전용 preset

핵심: CMake Presets로 로컬·CI 설정 통일 → vcpkg Binary Caching으로 의존성 설치 가속 → 매트릭스로 멀티 플랫폼 검증 → 아티팩트·릴리스로 배포 자동화


자주 묻는 질문 (FAQ)

  • run-vcpkg vs 수동 vcpkg? run-vcpkg가 Binary Caching·경로 설정을 자동으로 해 줘서 권장. 수동이면 x-gha 또는 actions/cache로 캐싱.
  • 캐시가 적용됐는데 왜 느려요? 캐시 키가 매번 바뀌면 miss. hashFiles에 불필요한 파일이 들어가면 소스 수정 시마다 캐시 무효화.
  • Windows에서 Ninja vs MSVC? Ninja Multi-Config + MSVC 조합이 일반적. --config Release 필수.
  • 아티팩트 용량 초과? 압축(tar.gz, zip), 필요한 파일만 업로드, retention-days 줄이기.
  • Self-hosted runner? GitHub 호스트 대신 자체 서버 사용. 설정·보안 관리 필요.

참고 자료

한 줄 요약: GitHub Actions로 C++/CMake 프로젝트 CI/CD를 구축하고, vcpkg 캐싱·매트릭스 빌드·아티팩트·릴리스 배포까지 자동화할 수 있습니다.


관련 글

  • C++ CMake Presets 완벽 가이드 | 멀티 플랫폼·vcpkg·Conan·CI/CD 통합
  • C++ vcpkg 기초 완벽 가이드 | 설치·Manifest·Triplet·버전·커스텀 포트 [#53-3]
  • C++ Conan 기초 완벽 가이드 | 설치·conanfile·프로필·CMake 연동 [#53-4]
  • CMake 입문 | 수십 개 파일 컴파일할 때 필요한 빌드 자동화 (CMakeLists.txt 기초)
... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3