C++ vcpkg 기초 완벽 가이드 | 설치·Manifest·Triplet·버전·커스텀 포트 [#53-3]
이 글의 핵심
C++ vcpkg 패키지 매니저 기초 가이드입니다. 설치, Manifest 모드, Triplet 설정, 버전 관리, 커스텀 포트 작성 방법을 실전 예제로 다룹니다. findpackage(fmt) failed — fmt를 못 찾아요 로컬에서는 되는데 CI에서만 빌드가 실패해요 팀원 A는 빌드되는데 B는 실패해요.
들어가며: “vcpkg가 뭔데 이렇게 복잡해요”
문제 시나리오
"find_package(fmt) failed — fmt를 못 찾아요"
"로컬에서는 되는데 CI에서만 빌드가 실패해요"
"팀원 A는 빌드되는데 B는 실패해요. vcpkg 버전이 다르대요"
"Boost 설치하는데 30분 넘게 걸려요"
"정적 링크로 배포해야 하는데 동적 링크만 되요"
"공식 레지스트리에 없는 라이브러리를 쓰고 싶어요"
"undefined reference 에러가 나는데 헤더는 잘 찾아요"
"vcpkg install 했는데 CMake가 여전히 못 찾아요"
이 글은 vcpkg 기초 완벽 가이드입니다. 설치부터 Manifest 모드·Triplet·버전 관리·커스텀 포트까지, 실전 예제와 함께 다룹니다. 실무 문제 시나리오, 자주 발생하는 에러, 베스트 프랙티스, 프로덕션 패턴까지 900줄 분량으로 정리합니다. 이 글을 읽으면:
- vcpkg를 설치하고 CMake 프로젝트에 연동할 수 있습니다.
- Manifest 모드로 프로젝트별 의존성을 관리할 수 있습니다.
- Triplet으로 동적/정적 링크·플랫폼을 선택할 수 있습니다.
- 버전 관리(builtin-baseline, vcpkg.lock)로 재현 가능한 빌드를 만들 수 있습니다.
- 커스텀 포트(오버레이)로 사내 라이브러리를 통합할 수 있습니다.
- 자주 발생하는 에러와 해결법을 알 수 있습니다. 요구 환경: vcpkg 2024.01+, CMake 3.20+, C++17 이상
실무 적용 경험: 이 글은 대규모 C++ 프로젝트에서 실제로 겪은 문제와 해결 과정을 바탕으로 작성되었습니다. 책이나 문서에서 다루지 않는 실전 함정과 디버깅 팁을 포함합니다.
1. 문제 시나리오 상세
시나리오 1: 신규 프로젝트 — 라이브러리 설치 지옥
상황: C++ 프로젝트에 fmt, spdlog를 추가하려 함
문제: 수동으로 소스 다운로드·빌드·경로 설정 반복
결과: vcpkg Manifest 모드로 vcpkg.json에 의존성 선언 → 한 번에 해결
시나리오 2: CI에서만 빌드 실패
상황: 로컬에서는 빌드 성공, GitHub Actions에서 find_package 실패
문제: 로컬에 Classic 모드로 설치한 패키지가 CI에 없음
결과: Manifest 모드 + vcpkg.json + CMAKE_TOOLCHAIN_FILE 지정
시나리오 3: 팀원마다 vcpkg 상태가 다름
상황: 팀원 A는 fmt 10.1, B는 10.2가 설치됨
문제: API 차이로 A는 되는데 B는 실패
결과: builtin-baseline 고정, vcpkg.lock Git 커밋
시나리오 4: 정적 링크 배포 필요
상황: 단일 실행 파일로 배포해야 함 (DLL 없이)
문제: 기본 triplet은 동적 링크
결과: x64-windows-static triplet 사용
시나리오 5: 사내 라이브러리 통합
상황: 공식 레지스트리에 없는 사내 유틸리티 라이브러리
문제: vcpkg install로 설치 불가
결과: 오버레이 포트로 사내 포트 디렉터리 등록
시나리오별 기술 선택
| 시나리오 | vcpkg 기능 | 적용 방법 |
|---|---|---|
| 신규 프로젝트 | Manifest 모드 | vcpkg.json 생성 |
| CI 빌드 | Manifest + 툴체인 | CMAKE_TOOLCHAIN_FILE |
| 버전 통일 | builtin-baseline, vcpkg.lock | vcpkg.json, lock 커밋 |
| 정적 링크 | Triplet | VCPKG_TARGET_TRIPLET |
| 사내 라이브러리 | 오버레이 | VCPKG_OVERLAY_PORTS |
flowchart TD
subgraph 문제[실무 문제]
P1[라이브러리 설치 지옥] --> S1[Manifest 모드]
P2[CI 빌드 실패] --> S2[툴체인 + vcpkg.json]
P3[버전 불일치] --> S3[baseline + lock]
P4[정적 링크] --> S4[Triplet]
P5[사내 라이브러리] --> S5[오버레이]
end
2. vcpkg 설치
2.1 설치 방법
vcpkg는 Git 저장소를 클론한 뒤 bootstrap 스크립트를 실행해 실행 파일을 만듭니다. Linux/macOS:
# 1. vcpkg 클론 (프로젝트 밖 또는 프로젝트 내 서브모듈로)
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
# 2. bootstrap 실행
./bootstrap-vcpkg.sh
# 3. 설치 확인
./vcpkg version
Windows (PowerShell 또는 cmd):
# 1. vcpkg 클론
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
# 2. bootstrap 실행
.\bootstrap-vcpkg.bat
# 3. 설치 확인
.\vcpkg.exe version
설치 결과: vcpkg(또는 vcpkg.exe) 실행 파일이 생성됩니다. vcpkg 디렉터리에서 실행하거나, PATH에 추가해 전역에서 사용할 수 있습니다.
2.2 프로젝트에 vcpkg 서브모듈로 추가 (권장)
팀 전체가 동일한 vcpkg 버전을 쓰려면 프로젝트에 서브모듈로 추가합니다.
# 프로젝트 루트에서
git submodule add https://github.com/Microsoft/vcpkg.git vcpkg
# 서브모듈 초기화
git submodule update --init --recursive
# vcpkg bootstrap
cd vcpkg
./bootstrap-vcpkg.sh # Linux/macOS
# .\bootstrap-vcpkg.bat # Windows
cd ..
장점: 프로젝트와 vcpkg 버전이 함께 고정되어, “팀원 A는 되는데 B는 안 된다” 문제를 줄입니다.
2.3 사전 요구사항
| 항목 | 최소 버전 |
|---|---|
| Git | 2.x |
| CMake | 3.20+ |
| C++ 컴파일러 | MSVC 2019+, GCC 9+, Clang 10+ |
| Python | 3.8+ (일부 포트에서 필요) |
# CMake 버전 확인
cmake --version
# C++ 컴파일러 확인
g++ --version # Linux
clang++ --version # macOS
cl # Windows (Visual Studio Developer Command Prompt)
3. Manifest 모드 완벽 예제
3.1 Classic 모드 vs Manifest 모드
| 구분 | Classic 모드 | Manifest 모드 |
|---|---|---|
| 설치 방식 | vcpkg install fmt 전역 설치 | vcpkg.json에 선언, CMake 설정 시 자동 설치 |
| 의존성 위치 | vcpkg 설치 디렉터리 | 프로젝트별 격리 |
| 재현성 | 낮음 (팀원마다 다름) | 높음 (vcpkg.json + lock) |
| 권장 | 레거시 | 신규 프로젝트는 Manifest 모드 |
3.2 최소 Manifest 모드 예제
프로젝트 구조:
my-app/
├── CMakeLists.txt
├── vcpkg.json
├── vcpkg/ # git submodule (선택)
└── src/
└── main.cpp
vcpkg.json:
// 실행 예제
{
"name": "my-app",
"version": "1.0.0",
"description": "vcpkg Manifest 모드 예제",
"dependencies": [
"fmt",
"spdlog"
]
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.20)
project(my-app VERSION 1.0.0 LANGUAGES CXX)
# vcpkg 툴체인 지정 (필수!)
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)
target_link_libraries(my-app PRIVATE
fmt::fmt
spdlog::spdlog
)
target_compile_features(my-app PRIVATE cxx_std_17)
src/main.cpp:
#include <spdlog/spdlog.h>
#include <fmt/core.h>
int main() {
spdlog::set_level(spdlog::level::debug);
spdlog::info("Hello, vcpkg! {}", fmt::format("vcpkg works!"));
return 0;
}
3.3 빌드 실행
# vcpkg가 서브모듈인 경우
cmake -B build -S . \
-DCMAKE_TOOLCHAIN_FILE="$(pwd)/vcpkg/scripts/buildsystems/vcpkg.cmake"
cmake --build build
./build/my-app # 또는 build\my-app.exe (Windows)
vcpkg 패키지 다운로드 및 빌드 메커니즘:
cmake -DCMAKE_TOOLCHAIN_FILE=.../vcpkg.cmake 실행:
1. CMake가 toolchain 파일 로드:
vcpkg.cmake 내부:
- VCPKG_INSTALLED_DIR 설정
- vcpkg.json 파싱
- 의존성 목록 추출
2. vcpkg.json 파싱:
{
"dependencies": ["fmt", "spdlog"]
}
→ 의존성 그래프 생성:
app
├─ fmt
└─ spdlog
3. 포트 메타데이터 조회:
각 패키지에 대해:
a. 레지스트리에서 포트 검색:
vcpkg/ports/fmt/vcpkg.json
vcpkg/ports/spdlog/vcpkg.json
b. 버전 정보 읽기:
vcpkg/versions/f-/fmt.json
→ "version": "10.1.1"
→ "git-tree": "abc123def456..."
c. 포트 파일 다운로드:
git clone (sparse checkout)
OR git tree object 읽기
4. 전이적 의존성 해석:
spdlog/vcpkg.json:
{
"dependencies": ["fmt"]
}
최종 그래프:
app
├─ fmt (직접)
└─ spdlog
└─ fmt (전이) → 중복 제거
5. Package ID (해시) 계산:
Package ID = hash(
패키지명,
버전,
Triplet,
포트 파일 내용,
의존성 해시
)
예: fmt/10.1.1/x64-linux
→ package_id: 1a2b3c4d5e6f...
6. 캐시 확인:
~/.cache/vcpkg/archives/ (Linux/Mac)
%LOCALAPPDATA%\vcpkg\archives\ (Windows)
if (캐시에 package_id 존재):
→ 압축 해제만 (빠름!)
else:
→ 소스 다운로드 + 빌드
7. 소스 다운로드:
portfile.cmake 읽기:
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO fmtlib/fmt
REF 10.1.1
SHA512 abc123...
)
동작:
a. GitHub에서 tarball 다운로드:
https://github.com/fmtlib/fmt/archive/10.1.1.tar.gz
b. SHA512 검증:
downloaded_sha512 == expected_sha512?
→ 불일치 시 에러
c. 압축 해제:
downloads/fmt-10.1.1/
→ buildtrees/fmt/src/10.1.1-xxx/
8. 빌드 실행:
portfile.cmake:
vcpkg_cmake_configure(
SOURCE_PATH ${SOURCE_PATH}
OPTIONS
-DFMT_DOC=OFF
-DFMT_TEST=OFF
)
vcpkg_cmake_build()
vcpkg_cmake_install()
내부 동작:
a. CMake 설정:
cd buildtrees/fmt/x64-linux-rel
cmake ../../src/ \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=packages/fmt_xxx
b. 빌드:
cmake --build . --target install
c. 설치:
packages/fmt_xxx/
├── include/
│ └── fmt/
├── lib/
│ └── libfmt.a
└── share/
└── fmt/
└── fmtConfig.cmake
9. 패키지 압축 및 캐시:
packages/fmt_xxx/
→ 압축: archives/1a2b3c4d5e6f.zip
→ 캐시 저장 (다음에 재사용)
10. 설치 디렉터리로 복사:
packages/fmt_xxx/
→ installed/x64-linux/
├── include/fmt/
├── lib/libfmt.a
└── share/fmt/fmtConfig.cmake
11. find_package 실행:
find_package(fmt CONFIG REQUIRED)
CMake 검색 경로:
- installed/x64-linux/share/fmt/
→ fmtConfig.cmake 발견!
fmtConfig.cmake 로드:
- fmt::fmt 타겟 생성
- 헤더 경로: installed/x64-linux/include
- 라이브러리: installed/x64-linux/lib/libfmt.a
12. target_link_libraries:
target_link_libraries(my-app PRIVATE fmt::fmt)
→ CMake가 fmt::fmt의 속성 사용:
- INTERFACE_INCLUDE_DIRECTORIES
- INTERFACE_LINK_LIBRARIES
→ my-app에 자동 전파
빌드 디렉터리 구조:
vcpkg_root/
├── downloads/ # 소스 tarball
│ └── fmt-10.1.1.tar.gz
├── buildtrees/ # 빌드 중간 산물
│ └── fmt/
│ └── src/
│ └── x64-linux-rel/
├── packages/ # 빌드 완료 (설치 전)
│ └── fmt_xxx/
├── installed/ # 최종 설치 경로
│ └── x64-linux/
│ ├── include/
│ ├── lib/
│ └── share/
└── .cache/ (archives/) # 바이너리 캐시
Triplet별 빌드:
x64-windows (동적):
→ installed/x64-windows/bin/fmt.dll
→ installed/x64-windows/lib/fmt.lib
x64-windows-static:
→ installed/x64-windows-static/lib/fmt.lib (정적)
병렬 빌드:
fmt와 nlohmann_json은 독립적:
→ 동시 빌드 가능!
spdlog는 fmt 의존:
→ fmt 완료 후 spdlog 빌드
vcpkg는 자동으로 의존성 순서 관리
동작 흐름:
- CMake가
CMAKE_TOOLCHAIN_FILE을 로드 - vcpkg 툴체인이 vcpkg.json을 읽음
- fmt, spdlog가 없으면 자동 설치
- find_package가 vcpkg 설치 경로에서 패키지 검색
- 빌드 완료
3.4 Manifest 모드 — 의존성 객체 형태
버전 제약, 플랫폼별 의존성을 지정할 때는 객체 형태입니다.
{
"name": "my-app",
"version": "1.0.0",
"dependencies": [
"fmt",
{
"name": "spdlog",
"version>=": "1.11.0",
"version<": "2.0.0"
},
{
"name": "openssl",
"platform": "windows"
}
]
}
| 필드 | 설명 |
|---|---|
name | 패키지 이름 |
version>= | 최소 버전 (이 버전 이상) |
version< | 최대 버전 (호환성 깨짐 방지) |
platform | 플랫폼 조건 (windows, !windows, linux, osx) |
4. Triplet 기초
4.1 Triplet이란?
Triplet은 arch-vendor-os 형식으로, 대상 플랫폼·아키텍처·빌드 타입을 지정합니다.
| Triplet | 설명 |
|---|---|
x64-windows | Windows 64비트, 동적 링크 |
x64-windows-static | Windows 64비트, 정적 링크 |
x64-linux | Linux 64비트 |
x64-osx | macOS Intel |
arm64-osx | macOS Apple Silicon (M1/M2) |
4.2 Triplet 지정 방법
방법 1: CMake 옵션
cmake -B build -S . \
-DCMAKE_TOOLCHAIN_FILE="$(pwd)/vcpkg/scripts/buildsystems/vcpkg.cmake" \
-DVCPKG_TARGET_TRIPLET=x64-windows-static
방법 2: 환경 변수
export VCPKG_DEFAULT_TRIPLET=x64-windows-static
cmake -B build -S .
방법 3: vcpkg.json (vcpkg-configuration.json)
{
"default-registry": {
"kind": "git",
"repository": "https://github.com/microsoft/vcpkg",
"baseline": "..."
},
"triplet": "x64-windows-static"
}
4.3 정적 링크 vs 동적 링크
| 용도 | Triplet |
|---|---|
| 개발 (빌드 속도 우선) | x64-windows, x64-linux |
| 배포 (단일 실행 파일) | x64-windows-static, x64-linux-static |
4.4 Triplet 확인
# 현재 기본 triplet
vcpkg version
# 설치된 패키지 확인 (triplet별)
vcpkg list
5. 버전 관리
5.1 builtin-baseline
builtin-baseline은 vcpkg 포트 저장소의 특정 커밋 해시입니다. 이 해시에 따라 사용 가능한 패키지 버전이 결정됩니다.
{
"name": "my-app",
"version": "1.0.0",
"dependencies": ["fmt", "spdlog"],
"builtin-baseline": "a1b2c3d4e5f6789012345678901234567890abc"
}
baseline 해시 가져오기:
cd vcpkg
git pull
git rev-parse HEAD
# 출력: a1b2c3d4e5f6789012345678901234567890abc
권장: 프로덕션에서는 baseline을 고정하고, 별도 브랜치에서 업데이트 테스트 후 반영합니다.
5.2 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 파일이 자동 갱신되므로, 변경 후 테스트하고 커밋하세요.
5.3 버전 제약 문법
{
"dependencies": [
{
"name": "spdlog",
"version>=": "1.11.0",
"version<": "2.0.0"
}
]
}
version>=: 최소 버전version<: 최대 버전 (마이저 업그레이드 시 예기치 않은 깨짐 방지)
6. 커스텀 포트(오버레이)
6.1 오버레이란?
오버레이는 vcpkg 공식 레지스트리보다 우선 적용되는 포트 디렉터리입니다. 사내 라이브러리, 수정된 포트, 아직 upstream되지 않은 패키지를 사용할 때 씁니다.
6.2 오버레이 디렉터리 구조
my-ports/
├── internal-lib/
│ ├── vcpkg.json
│ └── portfile.cmake
└── patched-spdlog/
├── vcpkg.json
├── portfile.cmake
└── patches/
└── fix-logging.patch
6.3 최소 오버레이 포트 예제 (헤더-온리)
my-ports/header-only-lib/vcpkg.json:
{
"name": "header-only-lib",
"version": "1.0.0",
"description": "헤더 전용 유틸리티 라이브러리",
"license": "MIT",
"dependencies": []
}
my-ports/header-only-lib/portfile.cmake:
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO example/header-only-lib
REF "v1.0.0"
SHA512 0
HEAD_REF main
)
# 헤더만 복사 (빌드 없음)
file(INSTALL "${SOURCE_PATH}/include/"
DESTINATION "${CURRENT_PACKAGES_DIR}/include"
FILES_MATCHING PATTERN "*.hpp"
)
file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage"
DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")
주의: SHA512 0으로 두고 설치 시도 → 에러 메시지에 실제 해시가 출력됨 → 복사해 넣기.
6.4 오버레이 사용
cmake -B build -S . \
-DCMAKE_TOOLCHAIN_FILE="$(pwd)/vcpkg/scripts/buildsystems/vcpkg.cmake" \
-DVCPKG_OVERLAY_PORTS="$(pwd)/my-ports"
vcpkg.json에서 오버레이 포트를 의존성으로 추가:
{
"dependencies": [
"fmt",
"header-only-lib"
]
}
6.5 vcpkg-configuration.json으로 오버레이 등록
프로젝트 루트에 vcpkg-configuration.json을 두면 CMake 옵션 없이 오버레이가 적용됩니다.
{
"default-registry": {
"kind": "git",
"repository": "https://github.com/microsoft/vcpkg",
"baseline": "a1b2c3d4e5f6..."
},
"overlay-ports": [./my-ports]
}
7. 완전한 예제 프로젝트
7.1 예제 1: 기본 Manifest 모드
vcpkg-basics-demo/
├── CMakeLists.txt
├── vcpkg.json
├── vcpkg.lock # Git 커밋 권장
├── vcpkg/ # git submodule
└── src/
└── main.cpp
vcpkg.json:
{
"name": "vcpkg-basics-demo",
"version": "1.0.0",
"description": "vcpkg 기초 완벽 예제",
"dependencies": [
"fmt",
"spdlog",
"nlohmann-json"
],
"builtin-baseline": "a1b2c3d4e5f6789012345678901234567890abc"
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.20)
project(vcpkg-basics-demo 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(demo src/main.cpp)
find_package(fmt CONFIG REQUIRED)
find_package(spdlog CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
target_link_libraries(demo PRIVATE
fmt::fmt
spdlog::spdlog
nlohmann_json::nlohmann_json
)
target_compile_features(demo PRIVATE cxx_std_17)
src/main.cpp:
#include <spdlog/spdlog.h>
#include <fmt/core.h>
#include <nlohmann/json.hpp>
int main() {
spdlog::info("vcpkg 기초 예제");
nlohmann::json j = {{"name", "vcpkg"}, {"version", "1.0"}};
spdlog::info("JSON: {}", j.dump());
return 0;
}
7.2 예제 2: Triplet + 정적 링크
cmake -B build -S . \
-DCMAKE_TOOLCHAIN_FILE="$(pwd)/vcpkg/scripts/buildsystems/vcpkg.cmake" \
-DVCPKG_TARGET_TRIPLET=x64-windows-static \
-DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
7.3 예제 3: 오버레이 + Manifest
my-project/
├── CMakeLists.txt
├── vcpkg.json
├── vcpkg-configuration.json
├── vcpkg/
├── my-ports/
│ └── internal-lib/
│ ├── vcpkg.json
│ └── portfile.cmake
└── src/
└── main.cpp
vcpkg-configuration.json:
{
"default-registry": {
"kind": "git",
"repository": "https://github.com/microsoft/vcpkg",
"baseline": "a1b2c3d4e5f6..."
},
"overlay-ports": [./my-ports]
}
8. 자주 발생하는 에러와 해결법
에러 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: “undefined reference” / 링크 에러
undefined reference to `spdlog::...'
원인: target_link_libraries에 누락, 또는 정적/동적 링크 혼용.
해결법:
# find_package 후 반드시 target_link_libraries에 추가
find_package(spdlog CONFIG REQUIRED)
target_link_libraries(my-app PRIVATE spdlog::spdlog)
에러 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: “vcpkg integrate install” 했는데 안 됨
원인: integrate install은 Classic 모드용. Manifest 모드는 CMAKE_TOOLCHAIN_FILE을 명시적으로 지정해야 함.
해결법: Manifest 모드에서는 -DCMAKE_TOOLCHAIN_FILE=...를 반드시 CMake 설정 시 전달합니다.
9. 베스트 프랙티스
1. Manifest 모드 사용
vcpkg.json을 프로젝트 루트에 두고 Git에 커밋- Classic 모드는 레거시. 신규 프로젝트는 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로 간편 설정
10. 프로덕션 패턴
패턴 1: 멀티 플랫폼 CI 매트릭스
# .github/workflows/build.yml
strategy:
matrix:
include:
- os: ubuntu-latest
triplet: x64-linux
- os: windows-latest
triplet: x64-windows-static
- os: macos-latest
triplet: arm64-osx
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Configure
run: |
cmake -B build -S . \
-DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake \
-DVCPKG_TARGET_TRIPLET=${{ matrix.triplet }}
패턴 2: CI 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 }}-
패턴 3: 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"
}
}
]
}
패턴 4: 의존성 업데이트 전략
1. 개발: 주기적으로 baseline 업데이트, 로컬 테스트
2. 스테이징: 업데이트 후 CI 전체 통과 확인
3. 프로덕션: vcpkg.lock 커밋으로 버전 고정
패턴 5: 사내 오버레이 공유
회사 레포지토리: company/vcpkg-ports
각 프로젝트에서:
-DVCPKG_OVERLAY_PORTS="$(pwd)/../vcpkg-ports"
또는 서브모듈로 vcpkg-ports 포함
11. 구현 체크리스트
vcpkg 기초 설정
- vcpkg 설치 (bootstrap 완료)
- vcpkg 서브모듈 추가 (권장)
- CMAKE_TOOLCHAIN_FILE 지정
- Manifest 모드 + vcpkg.json
버전 관리
- builtin-baseline 고정
- vcpkg.lock Git 커밋
- 버전 제약 (version>=, version<) 사용
Triplet
- 배포용 정적 링크 시 x64-windows-static 등 사용
- 팀 전체 triplet 통일
오버레이 (사내 라이브러리)
- my-ports/ 디렉터리 구조
- VCPKG_OVERLAY_PORTS 또는 vcpkg-configuration.json
CI/CD
- submodules: recursive
- vcpkg 캐시 (buildtrees, packages, downloads)
- hashFiles(‘vcpkg.json’, ‘vcpkg.lock’) key
자주 묻는 질문 (FAQ)
Q. vcpkg Classic 모드와 Manifest 모드 차이는?
A. Classic 모드는 vcpkg install로 전역 설치. Manifest 모드는 프로젝트 vcpkg.json에 의존성을 선언하고 CMake 설정 시 자동 설치. 재현 가능한 빌드를 위해 Manifest 모드를 권장합니다.
Q. CMAKE_TOOLCHAIN_FILE을 매번 지정해야 하나요?
A. CMakePresets.json에 cacheVariables로 넣어 두면 cmake --preset vcpkg-default로 한 번에 설정됩니다. IDE(CLion, VS)에서도 preset을 선택하면 됩니다.
Q. vcpkg.lock은 꼭 커밋해야 하나요?
A. 팀 전체가 동일한 버전으로 빌드하려면 커밋하는 것이 좋습니다. 의존성 변경 시 lock이 자동 갱신되므로, 변경 후 테스트하고 함께 커밋합니다.
Q. 사내 라이브러리를 vcpkg로 쓰려면?
A. 오버레이 포트를 만듭니다. my-ports/내라이브러리/에 vcpkg.json과 portfile.cmake를 두고, -DVCPKG_OVERLAY_PORTS로 경로를 지정합니다. 자세한 내용은 vcpkg 패키지 만들기를 참고하세요.
Q. CI 빌드가 너무 느려요.
A. actions/cache로 vcpkg의 buildtrees, packages, downloads를 캐시하세요. hashFiles('vcpkg.json', 'vcpkg.lock')를 key에 넣으면 의존성 변경 시에만 캐시가 갱신됩니다.
Q. builtin-baseline을 언제 업데이트하나요?
A. 보안 패치·버그 수정이 필요할 때. 별도 브랜치에서 업데이트 후 전체 테스트를 돌리고, 통과하면 main에 반영합니다. 한 줄 요약: vcpkg Manifest 모드 + vcpkg.json + CMAKE_TOOLCHAIN_FILE 지정만으로 대부분의 C++ 의존성 관리 문제를 해결할 수 있습니다. 다음 글: [C++ #53-3] vcpkg 고급 활용 | Manifest·Triplet·오버레이·바이너리 캐시 이전 글: [C++ #53-2] Visual Studio C++ 완벽 가이드
관련 글
- C++ vcpkg 고급 활용 | Manifest·Triplet·오버레이·바이너리 캐시 가이드
- C++ vcpkg 패키지 만들기 | 포트 파일·빌드·배포 완벽 가이드 [#53-3]
- C++ Conan 기초 완벽 가이드 | 설치·conanfile·프로필·CMake 연동 [#53-4]
- CMake 입문 | 수십 개 파일 컴파일할 때 필요한 빌드 자동화 (CMakeLists.txt 기초)
- C++ Conan 완벽 가이드 | 현대적인 C++ 패키지 관리
심화 부록: 구현·운영 관점
이 부록은 앞선 본문에서 다룬 주제(「C++ vcpkg 기초 완벽 가이드 | 설치·Manifest·Triplet·버전·커스텀 포트 [#53-3]」)를 구현·런타임·운영 관점에서 다시 압축합니다. 도메인별 세부 구현은 글마다 다르지만, 입력 검증 → 핵심 연산 → 부작용(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·버전·커스텀 포트 [#53-3]」)를 배포·운영 흐름에 맞춰 옮긴 체크리스트입니다. 도메인에 맞게 단계 이름만 바꿔 적용할 수 있습니다.
- 입력 계약 고정: 스키마·버전·최대 페이로드·타임아웃·에러 코드를 경계에 둔다.
- 핵심 경로 계측: 요청 ID, 단계별 지연, 외부 호출 결과 코드를 로그·메트릭·트레이스에서 한 흐름으로 본다.
- 실패 주입: 의존성 타임아웃·5xx·부분 데이터·락 대기를 스테이징에서 재현한다.
- 호환·롤백: 설정/마이그레이션/클라이언트 버전을 되돌릴 수 있는지 확인한다.
- 부하 후 검증: 피크 대비 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 스냅샷 비교 |
| 빌드·배포만 실패 | 환경 변수, 권한, 플랫폼 차이, lockfile | CI 로그와 로컬 diff, 런타임·이미지 버전 핀 |
| 설정 불일치 | 프로필·시크릿·기본값, 리전 | 스키마 검증된 설정 단일 소스와 배포 매트릭스 표준화 |
| 데이터 불일치 | 비멱등 재시도, 부분 쓰기, 캐시 무효화 누락 | 멱등 키·아웃박스·트랜잭션 경계 재검토 |
권장 순서: (1) 최소 재현 (2) 최근 변경 범위 축소 (3) 환경·의존성 차이 (4) 관측으로 가설 검증 (5) 수정 후 회귀·부하 테스트.
배포 전에는 git add → git commit → git push 후 npm run deploy 순서를 권장합니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- C++ vcpkg 고급 활용 | Manifest·Triplet·오버레이·바이너리 캐시 가이드
- C++ Conan 기초 완벽 가이드 | 설치·conanfile·프로필·CMake 연동 [#53-4]
- C++ 패키지 관리 실무: vcpkg와 Conan으로 외부 라이브러리 의존성 지옥 탈출 [#40-1]
이 글에서 다루는 키워드 (관련 검색어)
C++, vcpkg, 패키지관리, CMake, 의존성관리, 빌드시스템 등으로 검색하시면 이 글이 도움이 됩니다.