본문으로 건너뛰기
Previous
Next
C++ vcpkg 고급 활용 | Manifest·Triplet·오버레이·바이너리 캐시 가이드

C++ vcpkg 고급 활용 | Manifest·Triplet·오버레이·바이너리 캐시 가이드

C++ vcpkg 고급 활용 | Manifest·Triplet·오버레이·바이너리 캐시 가이드

이 글의 핵심

C++ vcpkg 고급 기능 Manifest 모드·커스텀 Triplet·오버레이·버전 제약·바이너리 캐시, CI 연동, 자주 발생하는 에러와 프로덕션 패턴까지 실전 예제로 다룹니다.

들어가며: vcpkg 기본을 넘어서

문제 시나리오

vcpkg로 fmt, spdlog를 설치하고 빌드에 성공했다면, 이제 이런 상황을 마주할 수 있습니다:

"Windows에서는 되는데 Linux 서버에서만 링크 에러가 나요."
"사내에서 수정한 라이브러리를 vcpkg로 쓰고 싶어요."
"CI에서 매번 30분씩 vcpkg 빌드하는데, 캐시로 줄일 수 없나요?"
"프로젝트 A는 Boost 1.82, 프로젝트 B는 1.84를 써야 하는데 충돌해요."
"정적 링크로 배포해야 하는데 triplet 설정이 복잡해요."
"builtin-baseline 업데이트 후 갑자기 빌드가 깨졌어요."

이 글에서 다루는 것:

  • Manifest 모드 심화: 버전 제약, 플랫폼별 의존성, builtin-baseline 전략
  • 커스텀 Triplet: 정적 링크, 특수 컴파일러, 크로스 컴파일
  • 오버레이 포트: 사내 라이브러리, 포트 수정본 통합
  • 바이너리 캐시: CI 빌드 시간 대폭 단축
  • 완전한 실전 예제: 복사 후 바로 사용 가능한 프로젝트 구조
  • 자주 발생하는 에러와 해결법
  • 베스트 프랙티스프로덕션 패턴 요구 환경: vcpkg 2024.01+, CMake 3.20+, C++17 이상

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

1. 문제 시나리오: vcpkg 고급 활용이 필요한 상황

시나리오 1: 멀티 플랫폼 빌드 실패

개발: Windows (MSVC) → 빌드 성공
CI: Ubuntu (GCC) → "undefined reference to spdlog::..."
배포: macOS (Clang) → "library not found for -lssl"

원인: triplet이 플랫폼별로 다르고, 동적/정적 링크 설정이 통일되지 않음. 해결 방향: 커스텀 triplet으로 팀 전체가 동일한 빌드 설정을 사용.

시나리오 2: 사내 라이브러리 통합

"우리 회사에서 fork한 OpenSSL을 vcpkg로 쓰고 싶어요."
"공식 포트에 버그가 있어서 패치를 적용했어요."

원인: vcpkg 공식 레지스트리에 없는 패키지 또는 수정된 버전 필요. 해결 방향: 오버레이 포트로 사내 포트 디렉터리를 vcpkg에 등록.

시나리오 3: CI 빌드 시간 폭증

"PR마다 vcpkg가 Boost, OpenSSL을 처음부터 빌드해서 40분 걸려요."
"캐시를 넣었는데도 매번 새로 빌드해요."

원인: vcpkg 빌드 결과를 캐시하지 않거나, 바이너리 캐시를 활용하지 않음. 해결 방향: 바이너리 캐시(아티팩트, GitHub Actions cache)로 빌드 결과 재사용.

시나리오 4: 버전 충돌과 재현성

"builtin-baseline을 올렸더니 fmt 10.2로 올라가서 우리 코드가 깨졌어요."
"팀원 A는 빌드되는데 B는 실패해요. vcpkg 버전이 다르대요."

원인: baseline·버전 제약이 없거나 팀원마다 vcpkg 상태가 다름. 해결 방향: builtin-baseline 고정, version>= 제약, vcpkg를 서브모듈로 관리.

flowchart TD
  subgraph problems[문제]
    P1[멀티 플랫폼 불일치]
    P2[사내 라이브러리]
    P3[CI 빌드 지연]
    P4[버전·재현성]
  end
  subgraph solutions[해결]
    S1[커스텀 Triplet]
    S2[오버레이 포트]
    S3[바이너리 캐시]
    S4[Manifest + baseline]
  end
  P1 --> S1
  P2 --> S2
  P3 --> S3
  P4 --> S4

2. Manifest 모드 심화

버전 제약 문법

vcpkg.json에서 의존성 버전을 세밀히 제어할 수 있습니다.

{
  "name": "my-production-app",
  "version": "1.0.0",
  "dependencies": [
    "fmt",
    {
      "name": "spdlog",
      "version>=": "1.11.0",
      "version<": "2.0.0"
    },
    {
      "name": "openssl",
      "version>=": "3.0.0",
      "platform": "!windows"
    },
    {
      "name": "zlib",
      "platform": "windows"
    }
  ],
  "builtin-baseline": "a1b2c3d4e5f6789012345678901234567890abc"
}

설명:

  • version>=: 최소 버전 (이 버전 이상)
  • version<: 최대 버전 (이 버전 미만, 호환성 깨짐 방지)
  • platform: 특정 플랫폼에서만 의존성 추가
    • "windows": Windows에서만
    • "!windows": Windows 제외 (Linux, macOS)
    • "linux", "osx"

builtin-baseline 전략

builtin-baseline은 vcpkg 포트 저장소의 특정 커밋 해시입니다. 이 해시에 따라 사용 가능한 패키지 버전이 결정됩니다.

# vcpkg 최신 커밋 해시 확인
cd vcpkg
git pull
git rev-parse HEAD
# 출력: a1b2c3d4e5f6789012345678901234567890abc

권장 전략:

  1. 프로덕션: baseline을 고정하고, 별도 브랜치에서 업데이트 테스트 후 반영
  2. 개발: 주기적으로 baseline 업데이트, 전체 테스트 후 커밋
  3. CI: vcpkg.jsonvcpkg.lock을 Git에 커밋해 재현성 확보

vcpkg.lock 활용

Manifest 모드로 빌드하면 vcpkg.lock이 생성됩니다. 이 파일을 Git에 커밋하면 정확히 동일한 버전으로 빌드됩니다.

{
  "version": 1,
  "port-version": 0,
  "builtin-baseline": "a1b2c3d4e5f6789012345678901234567890abc",
  "packages": [
    {
      "name": "fmt",
      "version": "10.1.1",
      "port-version": 0
    },
    {
      "name": "spdlog",
      "version": "1.12.1",
      "port-version": 0
    }
  ]
}

주의: vcpkg.lock이 있으면 vcpkg가 이 버전을 우선 사용합니다. 의존성 추가/변경 시 lock 파일이 자동 갱신되므로, 변경 후 테스트하고 커밋하세요.

플랫폼별 의존성 예제

Windows에서는 시스템 SSL 대신 vcpkg OpenSSL, Linux에서는 시스템 OpenSSL을 쓰는 예:

{
  "dependencies": [
    "fmt",
    "spdlog",
    {
      "name": "openssl",
      "platform": "windows"
    }
  ]
}
# CMakeLists.txt - OpenSSL은 Windows에서만 vcpkg, Linux는 시스템
if(WIN32)
  find_package(OpenSSL REQUIRED)
  target_link_libraries(myapp PRIVATE OpenSSL::SSL OpenSSL::Crypto)
endif()

3. 커스텀 Triplet

Triplet이란?

Tripletarch-vendor-os 형식으로, 대상 플랫폼·아키텍처·빌드 타입을 지정합니다.

Triplet설명
x64-windowsWindows 64비트, 동적 링크
x64-windows-staticWindows 64비트, 정적 링크
x64-linuxLinux 64비트
x64-osxmacOS Intel
arm64-osxmacOS Apple Silicon

커스텀 Triplet 생성

정적 링크 + 특정 컴파일러 플래그가 필요할 때 커스텀 triplet을 만듭니다. triplets/custom-static.cmake (프로젝트 내):

// 실행 예제
set(VCPKG_TARGET_ARCHITECTURE x64)
set(VCPKG_CRT_LINKAGE static)
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_CMAKE_SYSTEM_NAME WindowsDesktop)
# 추가 컴파일러 플래그
set(VCPKG_CXX_FLAGS "/MT /W4")
set(VCPKG_CXX_FLAGS_DEBUG "/MTd /Od")
set(VCPKG_CXX_FLAGS_RELEASE "/MT /O2")

triplets/x64-linux-static.cmake (Linux 정적):

set(VCPKG_TARGET_ARCHITECTURE x64)
set(VCPKG_CRT_LINKAGE static)
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_CMAKE_SYSTEM_NAME Linux)

Triplet 사용

cmake -B build -S . \
  -DCMAKE_TOOLCHAIN_FILE="$(pwd)/vcpkg/scripts/buildsystems/vcpkg.cmake" \
  -DVCPKG_TARGET_TRIPLET=custom-static

또는 VCPKG_DEFAULT_TRIPLET 환경 변수:

export VCPKG_DEFAULT_TRIPLET=x64-windows-static
cmake -B build -S .

Triplet 오버레이

프로젝트별 triplet을 triplets/ 디렉터리에 두고 vcpkg에 알려줍니다:

cmake -B build -S . \
  -DCMAKE_TOOLCHAIN_FILE="$(pwd)/vcpkg/scripts/buildsystems/vcpkg.cmake" \
  -DVCPKG_OVERLAY_TRIPLETS="$(pwd)/triplets"

4. 오버레이 포트

오버레이란?

오버레이는 vcpkg 공식 레지스트리보다 우선 적용되는 포트 디렉터리입니다. 사내 라이브러리, 수정된 포트, 아직 upstream되지 않은 패키지를 사용할 때 씁니다.

오버레이 디렉터리 구조

my-ports/
├── company-openssl/          # 사내 fork OpenSSL
│   ├── portfile.cmake
│   └── vcpkg.json
├── patched-spdlog/          # 공식 spdlog에 패치 적용
│   ├── portfile.cmake
│   ├── vcpkg.json
│   └── patches/
│       └── fix-logging.patch
└── internal-lib/             # 완전히 사내 라이브러리
    ├── portfile.cmake
    └── vcpkg.json

사내 포트 예제: internal-lib

my-ports/internal-lib/vcpkg.json:

{
  "name": "internal-lib",
  "version": "1.0.0",
  "description": "사내 공통 라이브러리",
  "license": "Proprietary",
  "dependencies": [fmt]
}

my-ports/internal-lib/portfile.cmake:

vcpkg_from_git(
    OUT_SOURCE_PATH SOURCE_PATH
    URL "https://git.company.com/libs/internal-lib.git"
    REF "v1.0.0"
)
vcpkg_cmake_configure(
    SOURCE_PATH "${SOURCE_PATH}"
)
vcpkg_cmake_install()
vcpkg_copy_pdbs()
file(INSTALL "${SOURCE_PATH}/LICENSE" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright)

오버레이 사용

cmake -B build -S . \
  -DCMAKE_TOOLCHAIN_FILE="$(pwd)/vcpkg/scripts/buildsystems/vcpkg.cmake" \
  -DVCPKG_OVERLAY_PORTS="$(pwd)/my-ports"

vcpkg.json에서 오버레이 포트를 의존성으로 추가:

{
  "dependencies": [
    "fmt",
    "internal-lib"
  ]
}

공식 포트 패치 적용

공식 spdlog 포트를 복사한 뒤 패치만 추가하는 예: my-ports/patched-spdlog/portfile.cmake:

# 공식 포트를 가져온 뒤
vcpkg_from_github(
    OUT_SOURCE_PATH SOURCE_PATH
    REPO gabime/spdlog
    REF "v1.12.1"
    SHA512 "..."
)
# 패치 적용
vcpkg_apply_patches(
    SOURCE_PATH "${SOURCE_PATH}"
    PATCHES "${CMAKE_CURRENT_LIST_DIR}/patches/fix-logging.patch"
)
vcpkg_cmake_configure(
    SOURCE_PATH "${SOURCE_PATH}"
    OPTIONS -DSPDLOG_ENABLE_PCH=OFF
)
vcpkg_cmake_install()
vcpkg_copy_pdbs()

5. 바이너리 캐시

바이너리 캐시란?

vcpkg가 패키지를 빌드한 결과를 재사용하는 기능입니다. CI에서 매번 소스부터 빌드하는 대신, 이전에 빌드한 바이너리를 가져와 빌드 시간을 크게 줄입니다.

로컬 디렉터리 캐시

# 빌드 결과를 ./vcpkg-cache에 저장
export VCPKG_BINARY_SOURCES="clear;default,readwrite,./vcpkg-cache"
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=...

첫 빌드 후 vcpkg-cache/에 바이너리가 쌓이고, 이후 빌드에서는 여기서 읽어옵니다.

GitHub Actions 아티팩트 캐시

# .github/workflows/build.yml
env:
  VCPKG_BINARY_SOURCES: "clear;default,readwrite,github,https://github.com/${{ github.repository }},readwrite"
steps:
  - uses: actions/checkout@v4
    with:
      submodules: recursive
  - name: Configure and Build
    run: |
      cmake -B build -S . \
        -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake
      cmake --build build

주의: GitHub 아티팩트는 저장소별·용량 제한이 있습니다. 대안으로 actions/cache를 사용합니다.

actions/cache로 vcpkg 캐시

- name: Cache vcpkg
  uses: actions/cache@v4
  with:
    path: |
      ${{ github.workspace }}/vcpkg/buildtrees
      ${{ github.workspace }}/vcpkg/packages
      ${{ github.workspace }}/vcpkg/downloads
    key: vcpkg-${{ runner.os }}-${{ hashFiles('vcpkg.json', 'vcpkg.lock') }}
    restore-keys: vcpkg-${{ runner.os }}-
- name: Configure CMake
  run: |
    cmake -B build -S . \
      -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake

hashFiles('vcpkg.json', 'vcpkg.lock')가 바뀌면 새 캐시가 만들어지고, 그렇지 않으면 이전 빌드 결과를 재사용합니다.

6. 완전한 vcpkg 고급 예제

예제 1: 프로덕션 수준 프로젝트 구조

my-vcpkg-app/
├── .github/
│   └── workflows/
│       └── build.yml
├── CMakeLists.txt
├── CMakePresets.json
├── vcpkg.json
├── vcpkg.lock          # Git 커밋 권장
├── triplets/
│   └── x64-windows-static.cmake
├── vcpkg/              # git submodule
└── src/
    └── main.cpp

vcpkg.json (완전한 예제)

{
  "name": "my-vcpkg-app",
  "version": "1.0.0",
  "description": "vcpkg 고급 활용 예제",
  "dependencies": [
    {
      "name": "fmt",
      "version>=": "10.0.0"
    },
    {
      "name": "spdlog",
      "version>=": "1.11.0",
      "version<": "2.0.0"
    },
    {
      "name": "openssl",
      "platform": "windows"
    }
  ],
  "builtin-baseline": "a1b2c3d4e5f6789012345678901234567890abc"
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.20)
project(my-vcpkg-app VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake"
    CACHE STRING "Vcpkg toolchain")
add_executable(my-app src/main.cpp)
find_package(fmt CONFIG REQUIRED)
find_package(spdlog CONFIG REQUIRED)
if(WIN32)
  find_package(OpenSSL REQUIRED)
  target_link_libraries(my-app PRIVATE OpenSSL::SSL OpenSSL::Crypto)
endif()
target_link_libraries(my-app PRIVATE
    fmt::fmt
    spdlog::spdlog
)
target_compile_features(my-app PRIVATE cxx_std_17)

main.cpp

#include <spdlog/spdlog.h>
#include <fmt/core.h>
int main() {
    spdlog::set_level(spdlog::level::debug);
    spdlog::info("vcpkg 고급 예제: {}", fmt::format("Hello, vcpkg!"));
    return 0;
}

CMakePresets.json (팀 설정 통일)

{
  "version": 3,
  "configurePresets": [
    {
      "name": "vcpkg-default",
      "cacheVariables": {
        "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake"
      }
    },
    {
      "name": "vcpkg-static",
      "inherits": "vcpkg-default",
      "cacheVariables": {
        "VCPKG_TARGET_TRIPLET": "x64-windows-static"
      }
    }
  ]
}

GitHub Actions 워크플로 (완전한 예제)

name: Build (vcpkg)
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive
      - name: Cache vcpkg
        uses: actions/cache@v4
        with:
          path: |
            ${{ github.workspace }}/vcpkg/buildtrees
            ${{ github.workspace }}/vcpkg/packages
            ${{ github.workspace }}/vcpkg/downloads
          key: vcpkg-${{ runner.os }}-${{ hashFiles('vcpkg.json', 'vcpkg.lock') }}
          restore-keys: vcpkg-${{ runner.os }}-
      - name: Configure
        run: |
          cmake -B build -S . \
            -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake \
            -DCMAKE_BUILD_TYPE=Release
      - name: Build
        run: cmake --build build --config Release

예제 2: 오버레이 + 커스텀 triplet

# vcpkg를 서브모듈로
git submodule add https://github.com/Microsoft/vcpkg.git vcpkg
# CMake 설정 (오버레이 + triplet)
cmake -B build -S . \
  -DCMAKE_TOOLCHAIN_FILE="$(pwd)/vcpkg/scripts/buildsystems/vcpkg.cmake" \
  -DVCPKG_OVERLAY_PORTS="$(pwd)/my-ports" \
  -DVCPKG_OVERLAY_TRIPLETS="$(pwd)/triplets" \
  -DVCPKG_TARGET_TRIPLET=x64-windows-static

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

에러 1: “Could not find a package configuration file provided by ‘fmt’”

CMake Error: Could not find a package configuration file provided by "fmt"

원인: CMAKE_TOOLCHAIN_FILE을 지정하지 않았거나, vcpkg가 패키지를 아직 빌드하지 않음. 해결법:

# 1. 툴체인 파일 반드시 지정
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE="$(pwd)/vcpkg/scripts/buildsystems/vcpkg.cmake"
# 2. build 폴더 삭제 후 재시도 (캐시된 잘못된 설정 제거)
rm -rf build
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=...

에러 2: “Port xxx is not in the baseline”

Error: Could not find a version that satisfies the requirement ...

원인: builtin-baseline이 오래되었거나, 해당 패키지가 baseline에 없음. 해결법:

cd vcpkg
git pull
git rev-parse HEAD   # 이 해시를 vcpkg.json의 builtin-baseline에 넣기
{
  "builtin-baseline": "최신_커밋_해시"
}

에러 3: “Building package xxx failed”

Building package spdlog:x64-linux failed

원인: 패키지 빌드 중 컴파일 에러, 의존성 누락, 네트워크 오류 등. 해결법:

# 상세 로그로 원인 파악
export VCPKG_VERBOSE=1
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=...
# 특정 패키지만 수동 빌드
./vcpkg install spdlog --debug

에러 4: “A suitable version of cmake was not found”

Error: vcpkg was unable to find the version of cmake in your PATH

원인: PATH에 CMake가 없거나 버전이 낮음 (3.20+ 권장). 해결법:

which cmake
cmake --version
# 3.20 이상이어야 함. PATH에 추가하거나 최신 CMake 설치

에러 5: “Multiple definitions” / 링크 에러

error: multiple definition of 'spdlog::...'

원인: 정적/동적 링크 혼용, triplet 불일치. 해결법:

  • triplet을 팀 전체가 동일하게 사용 (예: x64-windows-static)
  • vcpkg로 설치한 라이브러리와 시스템 라이브러리 혼용 금지

에러 6: “C++ 표준 불일치”

error: #error "spdlog requires C++17 or later"

원인: 프로젝트가 C++14로 빌드되는데 의존성이 C++17 요구. 해결법:

target_compile_features(my-app PRIVATE cxx_std_17)
# 또는
set(CMAKE_CXX_STANDARD 17)

에러 7: 오버레이 포트를 찾을 수 없음

Error: Could not find port internal-lib

원인: VCPKG_OVERLAY_PORTS 경로가 잘못되었거나, 포트 디렉터리 구조가 맞지 않음. 해결법:

# 경로 확인 (절대 경로 권장)
ls -la my-ports/internal-lib/vcpkg.json
cmake -B build -S . \
  -DVCPKG_OVERLAY_PORTS="$(pwd)/my-ports"

에러 8: vcpkg.lock과 vcpkg.json 충돌

Error: Version conflict: lock file expects [email protected] but vcpkg.json allows 10.2.0

원인: vcpkg.json을 수정했는데 vcpkg.lock을 갱신하지 않음. 해결법:

# lock 파일 삭제 후 재생성
rm vcpkg.lock
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=...
# 새 vcpkg.lock 생성됨 → Git 커밋

에러 9: CI에서만 “Could NOT find” 발생

원인: 로컬에 Classic 모드로 설치한 패키지에 의존. CI에는 해당 패키지가 없음. 해결법: Manifest 모드로 전환. vcpkg.json에 의존성 선언하고 CMAKE_TOOLCHAIN_FILE 지정.

에러 10: 바이너리 캐시에서 손상된 패키지

Error: Failed to restore package from binary cache

원인: 캐시가 손상되었거나 triplet/버전이 달라서 호환되지 않음. 해결법:

# 캐시 비우고 재빌드
rm -rf vcpkg-cache
# 또는 CI에서 cache key 변경

8. 베스트 프랙티스

1. Manifest 모드 사용

  • vcpkg.json을 프로젝트 루트에 두고 Git에 커밋
  • Classic 모드(vcpkg install 전역 설치)는 레거시. 신규 프로젝트는 Manifest 모드

2. builtin-baseline 고정

  • 재현 가능한 빌드를 위해 특정 커밋 해시 사용
  • 업데이트 시 별도 브랜치에서 테스트 후 main 반영

3. vcpkg.lock 커밋

  • vcpkg.lock을 Git에 커밋하면 팀 전체가 동일한 버전 사용
  • 의존성 추가/변경 시 lock 갱신 후 테스트·커밋

4. vcpkg 서브모듈

git submodule add https://github.com/Microsoft/vcpkg.git vcpkg
  • vcpkg 버전을 프로젝트와 함께 고정
  • CI에서 submodules: recursive로 체크아웃

5. find_package CONFIG 모드

find_package(fmt CONFIG REQUIRED)
target_link_libraries(my-app PRIVATE fmt::fmt)
  • vcpkg 패키지는 대부분 Config 모드. CONFIG 명시 권장

6. 의존성 최소화

  • 꼭 필요한 패키지만 추가
  • 헤더 전용 라이브러리(nlohmann-json 등)는 빌드 없이 사용 가능

7. CI 캐시 활용

  • buildtrees, packages, downloads 캐시
  • hashFiles('vcpkg.json', 'vcpkg.lock')를 key에 포함

8. CMake Presets

  • CMakePresets.json으로 팀 전체 설정 통일
  • cmake --preset vcpkg-default로 간편 설정

9. 프로덕션 패턴

패턴 1: 멀티 플랫폼 CI 매트릭스

strategy:
  matrix:
    include:
      - os: ubuntu-latest
        triplet: x64-linux
      - os: windows-latest
        triplet: x64-windows-static
      - os: macos-latest
        triplet: arm64-osx
steps:
  - run: |
      cmake -B build -S . \
        -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake \
        -DVCPKG_TARGET_TRIPLET=${{ matrix.triplet }}

패턴 2: 사내 오버레이 공유

회사 레포지토리: company/vcpkg-ports
각 프로젝트에서:
  -DVCPKG_OVERLAY_PORTS="$(pwd)/../vcpkg-ports"
또는 서브모듈로 vcpkg-ports 포함

패턴 3: Docker + vcpkg

FROM ubuntu:22.04
RUN apt-get update && apt-get install -y git cmake g++ build-essential
RUN git clone https://github.com/Microsoft/vcpkg.git /vcpkg && \
    /vcpkg/bootstrap-vcpkg.sh
ENV CMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake
WORKDIR /app
COPY . .
RUN cmake -B build -S . && cmake --build build

패턴 4: 의존성 업데이트 전략

1. 개발: 주기적으로 baseline 업데이트, 로컬 테스트
2. 스테이징: 업데이트 후 CI 전체 통과 확인
3. 프로덕션: vcpkg.lock 커밋으로 버전 고정

패턴 5: 버전 제약으로 호환성 유지

{
  "dependencies": [
    {
      "name": "spdlog",
      "version>=": "1.11.0",
      "version<": "2.0.0"
    }
  ]
}
  • version<로 마이저 업그레이드 시 예기치 않은 깨짐 방지

10. 정리

항목설명
Manifest 심화버전 제약, 플랫폼별 의존성, builtin-baseline, vcpkg.lock
커스텀 Triplet정적 링크, 특수 컴파일러, 오버레이 triplet
오버레이사내 라이브러리, 패치된 포트 통합
바이너리 캐시로컬/CI 캐시로 빌드 시간 단축
에러 해결툴체인 지정, baseline 업데이트, triplet 통일
프로덕션멀티 플랫폼 CI, 오버레이 공유, Docker, 업데이트 전략

구현 체크리스트

  • Manifest 모드 + vcpkg.json
  • builtin-baseline 고정
  • vcpkg.lock Git 커밋
  • vcpkg 서브모듈
  • CMAKE_TOOLCHAIN_FILE 지정
  • CI에서 vcpkg 캐시
  • 필요 시 오버레이·커스텀 triplet

자주 묻는 질문 (FAQ)

Q. vcpkg Classic 모드와 Manifest 모드 차이는?

A. Classic 모드는 vcpkg install로 전역 설치. Manifest 모드는 프로젝트 vcpkg.json에 의존성을 선언하고 CMake 설정 시 자동 설치. 재현 가능한 빌드를 위해 Manifest 모드를 권장합니다.

Q. 사내 라이브러리를 vcpkg로 쓰려면?

A. 오버레이 포트를 만듭니다. my-ports/내라이브러리/vcpkg.jsonportfile.cmake를 두고, -DVCPKG_OVERLAY_PORTS로 경로를 지정합니다.

Q. CI 빌드가 너무 느려요.

A. actions/cache로 vcpkg의 buildtrees, packages, downloads를 캐시하세요. hashFiles('vcpkg.json', 'vcpkg.lock')를 key에 넣으면 의존성 변경 시에만 캐시가 갱신됩니다.

Q. builtin-baseline을 언제 업데이트하나요?

A. 보안 패치·버그 수정이 필요할 때. 별도 브랜치에서 업데이트 후 전체 테스트를 돌리고, 통과하면 main에 반영합니다. 한 줄 요약: vcpkg Manifest·Triplet·오버레이·바이너리 캐시를 활용하면 멀티 플랫폼·재현 가능·빠른 CI 빌드를 구축할 수 있습니다. 다음 글: [C++ #53-4] Conan 레시피 작성 | 패키지 배포·의존성 관리 이전 글: [C++ #53-2] Visual Studio C++ 완벽 가이드

관련 글

심화 부록: 구현·운영 관점

이 부록은 앞선 본문에서 다룬 주제(「C++ vcpkg 고급 활용 | Manifest·Triplet·오버레이·바이너리 캐시 가이드」)를 구현·런타임·운영 관점에서 다시 압축합니다. 도메인별 세부 구현은 글마다 다르지만, 입력 검증 → 핵심 연산 → 부작용(I/O·네트워크·동시성) → 관측의 흐름으로 장애를 나누면 원인 추적이 빨라집니다.

내부 동작과 핵심 메커니즘

flowchart TD
  A[입력·요청·이벤트] --> B[파싱·검증·디코딩]
  B --> C[핵심 연산·상태 전이]
  C --> D[부작용: I/O·네트워크·동시성]
  D --> E[결과·관측·저장]
sequenceDiagram
  participant C as 클라이언트/호출자
  participant B as 경계(런타임·게이트웨이·프로세스)
  participant D as 의존성(API·DB·큐·파일)
  C->>B: 요청/이벤트
  B->>D: 조회·쓰기·RPC
  D-->>B: 지연·부분 실패·재시도 가능
  B-->>C: 응답 또는 오류(코드·상관 ID)
  • 불변 조건(Invariant): 버퍼 경계, 프로토콜 상태, 트랜잭션 격리, FD 상한 등 단계별로 문장으로 적어 두면 디버깅 비용이 줄어듭니다.
  • 결정성: 순수 층과 시간·네트워크·스케줄에 의존하는 층을 분리해야 테스트와 장애 분석이 쉬워집니다.
  • 경계 비용: 직렬화, 인코딩, syscall 횟수, 락 경합, 할당·GC, 캐시 미스를 의심 목록에 둡니다.
  • 백프레셔: 생산자가 소비자보다 빠를 때 버퍼·큐·스트림에서 속도를 줄이는 신호를 어디에 둘지 정의합니다.

프로덕션 운영 패턴

영역운영 관점 질문
관측성요청 단위 상관 ID, 에러율·지연 p95/p99, 의존성 타임아웃·재시도가 대시보드에 보이는가
안전성입력 검증·권한·비밀·감사 로그가 코드 경로마다 일관적인가
신뢰성재시도는 멱등 연산에만 적용되는가, 서킷 브레이커·백오프·DLQ가 있는가
성능캐시·배치 크기·커넥션 풀·인덱스·백프레셔가 데이터 규모에 맞는가
배포롤백 룬북, 카나리/블루그린, 마이그레이션·피처 플래그가 문서화되어 있는가
용량피크 트래픽·디스크·FD·스레드 풀 상한을 주기적으로 검증하는가

스테이징은 데이터 양·네트워크 RTT·동시성을 프로덕션에 가깝게 맞출수록 재현율이 올라갑니다.

확장 예시: 엔드투엔드 미니 시나리오

앞선 본문 주제(「C++ vcpkg 고급 활용 | Manifest·Triplet·오버레이·바이너리 캐시 가이드」)를 배포·운영 흐름에 맞춰 옮긴 체크리스트입니다. 도메인에 맞게 단계 이름만 바꿔 적용할 수 있습니다.

  1. 입력 계약 고정: 스키마·버전·최대 페이로드·타임아웃·에러 코드를 경계에 둔다.
  2. 핵심 경로 계측: 요청 ID, 단계별 지연, 외부 호출 결과 코드를 로그·메트릭·트레이스에서 한 흐름으로 본다.
  3. 실패 주입: 의존성 타임아웃·5xx·부분 데이터·락 대기를 스테이징에서 재현한다.
  4. 호환·롤백: 설정/마이그레이션/클라이언트 버전을 되돌릴 수 있는지 확인한다.
  5. 부하 후 검증: 피크 대비 p95/p99, 에러율, 리소스 상한, 알림 임계값을 점검한다.
handle(request):
  ctx = newCorrelationId()
  validated = validateSchema(request)
  authorize(validated, ctx)
  result = domainCore(validated)
  persistOrEmit(result, idempotentKey)
  recordMetrics(ctx, latency, outcome)
  return result

문제 해결(Troubleshooting)

증상가능 원인조치
간헐적 실패레이스, 타임아웃, 외부 의존성, DNS최소 재현 스크립트, 분산 트레이스·로그 상관관계, 재시도·서킷 설정 점검
성능 저하N+1, 동기 I/O, 락 경합, 과도한 직렬화, 캐시 미스프로파일러·APM으로 핫스팟 확인 후 한 가지씩 제거
메모리 증가캐시 무제한, 구독/리스너 누수, 대용량 버퍼, 커넥션 미반납상한·TTL·힙/FD 스냅샷 비교
빌드·배포만 실패환경 변수, 권한, 플랫폼 차이, lockfileCI 로그와 로컬 diff, 런타임·이미지 버전 핀
설정 불일치프로필·시크릿·기본값, 리전스키마 검증된 설정 단일 소스와 배포 매트릭스 표준화
데이터 불일치비멱등 재시도, 부분 쓰기, 캐시 무효화 누락멱등 키·아웃박스·트랜잭션 경계 재검토

권장 순서: (1) 최소 재현 (2) 최근 변경 범위 축소 (3) 환경·의존성 차이 (4) 관측으로 가설 검증 (5) 수정 후 회귀·부하 테스트.

배포 전에는 git addgit commitgit pushnpm run deploy 순서를 권장합니다.


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.


이 글에서 다루는 키워드 (관련 검색어)

C++, vcpkg, 패키지관리, CMake, CI/CD, 빌드시스템 등으로 검색하시면 이 글이 도움이 됩니다.