본문으로 건너뛰기 C++ Conan 2.x 레시피 작성 완벽 가이드 | conanfile.py·test_package·A...

C++ Conan 2.x 레시피 작성 완벽 가이드 | conanfile.py·test_package·Artifactory [2026 실전]

C++ Conan 2.x 레시피 작성 완벽 가이드 | conanfile.py·test_package·Artifactory [2026 실전]

들어가며: “우리 라이브러리를 Conan 패키지로 배포하고 싶어요”

실제 겪는 문제 시나리오

시나리오 1: 사내 라이브러리 배포 지옥

"lib-core를 프로젝트 A, B, C에서 쓰는데, 각각 다른 경로에 복사해 두고 있습니다."
"버전 1.2로 업데이트했는데, 프로젝트 B는 아직 1.1을 쓰고 있습니다. 언제 바꿀지 모르겠습니다."
"새 팀원이 lib-core를 빌드하려면 README 10페이지를 읽어야 해요."

원인: 수동 복사·빌드·경로 설정으로 버전 관리와 의존성 추적이 어렵습니다. 시나리오 2: Conan Center에 없는 라이브러리

"우리 회사에서 fork한 OpenSSL을 Conan으로 쓰고 싶습니다."
"레거시 C 라이브러리를 Conan 패키지로 감싸서 배포해야 해요."
"내부용 유틸리티를 팀 전체가 conan install로 쓰게 하고 싶습니다."

원인: Conan Center에 없는 패키지는 직접 레시피를 작성해야 합니다. 시나리오 3: 빌드 설정 불일치

"Windows에서는 shared=True로 빌드했는데, Linux에서는 static으로 빌드돼서 링크 에러가 나요."
"Debug/Release 혼용으로 ABI 호환성 문제가 발생해요."

원인: 레시피에 options·settings가 명확히 정의되지 않아 팀원마다 다른 바이너리가 생성됩니다. 시나리오 4: 패키지 품질 검증 부재

"conan create 했는데, 다른 프로젝트에서 링크하면 undefined reference가 나요."
"헤더 경로가 잘못되어 include가 안 돼요."

원인: test_package로 패키지 소비를 검증하지 않아, 실제 사용 시 문제가 드러납니다.

Conan 레시피로 해결

문제해결
수동 배포conan create + conan upload로 원격 저장소 배포
버전 불일치name/version으로 패키지 식별, conan install로 버전 지정
빌드 설정 차이settings·options로 바이너리 구성 통일
품질 검증test_package로 빌드·링크·실행 검증
flowchart LR
  subgraph Before["수동 배포 (Before)"]
    B1[소스 복사] --> B2[수동 빌드]
    B2 --> B3[경로 설정]
    B3 --> B4[프로젝트마다 다름]
  end
  subgraph After["Conan 레시피 (After)"]
    A1[conanfile.py] --> A2[conan create]
    A2 --> A3[캐시/원격 저장소]
    A3 --> A4[conan install로 통일]
  end

이 글에서 다루는 것

항목내용
레시피 구조conanfile.py 메타데이터, settings, options
완전한 예제헤더 전용, 정적/공유 라이브러리, CMake 연동
빌드·배포conan create, conan upload, test_package
원격 저장소Artifactory, Conan Server 연동
자주 발생하는 에러package_info 누락, exports_sources 오류 등
베스트 프랙티스버전 관리, 옵션 설계, CMake install
프로덕션 패턴CI/CD, 버전 태깅, 사내 레포 워크플로

1. 환경 설정

필수 요구사항

항목버전비고
Conan2.xpip install conan
Python3.8+Conan 2.x 요구
CMake3.15+CMake 기반 레시피 시
C++C++14 이상 권장-

Conan 설치 및 프로젝트 템플릿

# Conan 2.x 설치
pip install conan
# 버전 확인
conan --version
# CMake 라이브러리 레시피 템플릿 생성 (Hello World 수준)
conan new cmake_lib -d name=mylib -d version=1.0

conan new로 생성되는 구조:

mylib/
├── CMakeLists.txt
├── conanfile.py
├── include/
│   └── mylib.h
├── src/
│   └── mylib.cpp
└── test_package/
    ├── CMakeLists.txt
    ├── conanfile.py
    └── src/
        └── example.cpp

2. conanfile.txt vs conanfile.py

언제 무엇을 쓸까?

형식용도빌드·패키징
conanfile.txt패키지 소비만 할 때없음 (requires, generators만)
conanfile.py패키지 생성 또는 고급 소비build(), package(), package_info()
레시피 작성은 반드시 conanfile.py를 사용합니다. conanfile.txt는 [requires]에 패키지 목록만 적고, 빌드·패키징 로직을 정의할 수 없습니다.

conanfile.txt (소비 전용)

[requires]
mylib/1.0
[generators]
CMakeDeps
CMakeToolchain

conanfile.py (레시피 = 패키지 생성)

from conan import ConanFile
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
class MylibConan(ConanFile):
    name = "mylib"
    version = "1.0"
    settings = "os", "compiler", "build_type", "arch"
    def layout(self):
        cmake_layout(self)
    def generate(self):
        tc = CMakeToolchain(self)
        tc.generate()
    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()
    def package(self):
        cmake = CMake(self)
        cmake.install()
    def package_info(self):
        self.cpp_info.libs = [mylib]

3. 완전한 conanfile.py 레시피

3.1 레시피 전체 구조

Conan 레시피의 핵심 메서드와 역할:

flowchart TD
  A[conanfile.py] --> B[layout]
  A --> C[generate]
  A --> D[build]
  A --> E[package]
  A --> F[package_info]
  B --> G[소스·빌드 경로 정의]
  C --> H[CMakeToolchain 등 생성]
  D --> I[실제 빌드 수행]
  E --> J[아티팩트를 package 폴더로 복사]
  F --> K[소비자에게 전달할 정보]

3.2 완전한 CMake 라이브러리 레시피

from conan import ConanFile
from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps, cmake_layout
from conan.tools.build import check_min_cppstd
from conan.tools.files import copy
class MylibConan(ConanFile):
    name = "mylib"
    version = "1.0.0"
    # 메타데이터 (선택이지만 권장)
    license = "MIT"
    author = "Your Name <your@email.com>"
    url = "https://github.com/yourorg/mylib"
    description = "A sample C++ library for Conan packaging"
    topics = ("conan", "library", "example")
    # 바이너리 구성
    settings = "os", "compiler", "build_type", "arch"
    options = {
        "shared": [True, False],
        "fPIC": [True, False],
    }
    default_options = {
        "shared": False,
        "fPIC": True,
    }
    # 소스 파일 (레시피와 함께 export됨)
    exports_sources = "CMakeLists.txt", "src/*", "include/*"
    def config_options(self):
        # Windows에서는 fPIC 의미 없음
        if self.settings.os == "Windows":
            del self.options.fPIC
    def configure(self):
        if self.options.shared:
            self.options.rm_safe("fPIC")
    def layout(self):
        cmake_layout(self)
    def requirements(self):
        # 의존성 예: self.requires("fmt/10.1.1")
        pass
    def generate(self):
        deps = CMakeDeps(self)
        deps.generate()
        tc = CMakeToolchain(self)
        tc.generate()
    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()
    def package(self):
        cmake = CMake(self)
        cmake.install()
    def package_info(self):
        self.cpp_info.libs = [mylib]
        # 헤더 경로는 CMake install이 설정하면 자동
        # 수동 지정 시: self.cpp_info.includedirs = [include]

3.3 CMakeLists.txt (레시피와 연동)

레시피의 cmake.install()이 동작하려면 CMake에 install 타겟이 있어야 합니다.

cmake_minimum_required(VERSION 3.15)
project(mylib VERSION 1.0.0 LANGUAGES CXX)
add_library(mylib
    src/mylib.cpp
)
target_include_directories(mylib PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
)
target_compile_features(mylib PUBLIC cxx_std_17)
# Conan이 package()에서 cmake.install() 호출 시 사용
install(TARGETS mylib
    RUNTIME DESTINATION bin
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
)
install(DIRECTORY include/ DESTINATION include)

3.4 주요 속성·메서드 설명

항목설명
exports_sources레시피와 함께 Conan 캐시로 복사할 파일. conan create 시 사용
config_options()플랫폼별로 옵션 제거 (예: Windows에서 fPIC)
configure()옵션 간 의존성 (shared=True면 fPIC 불필요)
layout()소스·빌드·패키지 폴더 구조. cmake_layout()이 표준
generate()CMakeToolchain, CMakeDeps 등 빌드 설정 파일 생성
build()실제 빌드 (cmake configure + build)
package()빌드 결과를 package 폴더로 복사
package_info()소비자가 링크·include할 때 필요한 정보

4. 헤더 전용 라이브러리 레시피

헤더 전용 라이브러리는 빌드 단계가 없습니다. build()를 생략하며, package()에서 헤더만 복사합니다.

from conan import ConanFile
from conan.tools.files import copy
class HeaderOnlyConan(ConanFile):
    name = "headeronly"
    version = "1.0.0"
    description = "Header-only C++ library"
    # 헤더 전용: settings 불필요 (바이너리 없음)
    # 단, 의존성이 있으면 settings 필요
    settings = "os", "compiler", "build_type", "arch"
    no_copy_source = True  # 소스를 그대로 package에 복사
    exports_sources = "include/*"
    def package(self):
        copy(self, "*.hpp", self.source_folder, self.package_folder)
        copy(self, "*.h", self.source_folder, self.package_folder)
    def package_info(self):
        self.cpp_info.bindirs = []
        self.cpp_info.libdirs = []
        # includedirs 기본값이 "include"이므로, include/ 아래에 있으면 생략 가능
        self.cpp_info.includedirs = [include]

주의: no_copy_source = True이면 self.source_folder에 소스가 있으므로, exports_sources로 지정한 파일이 package() 시점에 사용 가능합니다.

5. 패키지 빌드 및 검증

5.1 conan create — 빌드 + test_package

# 현재 디렉터리의 conanfile.py로 패키지 생성
conan create .
# 특정 설정
conan create . -s build_type=Debug
conan create . -o mylib/1.0.0:shared=True
# 프로필 지정
conan create . -pr=default

conan create는 다음을 수행합니다:

  1. 레시피와 exports_sources를 캐시로 export
  2. generate()build()package() 실행
  3. test_package/로 이동해 패키지 소비 테스트

5.2 test_package 구조

test_package는 패키지가 올바르게 생성되었는지 검증하는 소규모 Conan 프로젝트입니다.

test_package/
├── CMakeLists.txt
├── conanfile.py
└── src/
    └── example.cpp

test_package/conanfile.py:

import os
from conan import ConanFile
from conan.tools.cmake import CMake, cmake_layout
class TestPackageConan(ConanFile):
    settings = "os", "compiler", "build_type", "arch"
    generators = "CMakeDeps", "CMakeToolchain"
    def layout(self):
        cmake_layout(self)
    def requirements(self):
        # 생성 중인 패키지를 의존성으로
        self.requires(self.tested_reference_str())
    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()
    def test(self):
        # 빌드된 실행 파일 실행
        self.run(f".{os.sep}example")

test_package/CMakeLists.txt:

cmake_minimum_required(VERSION 3.15)
project(test_package LANGUAGES CXX)
find_package(mylib REQUIRED)
add_executable(example src/example.cpp)
target_link_libraries(example PRIVATE mylib::mylib)

test_package/src/example.cpp:

#include <mylib.h>
int main() {
    mylib::hello();
    return 0;
}

5.3 conan create 출력 예시

======== Exporting recipe to the cache ========
mylib/1.0.0: Exporting package recipe
...
======== Installing packages ========
-------- Installing package mylib/1.0.0 (1 of 1) --------
mylib/1.0.0: Building from source
mylib/1.0.0: Calling build()
...
mylib/1.0.0: Package 'xxx' built
======== Testing the package: Building ========
...
======== Testing the package: Executing test ========
mylib/1.0.0 (test package): Running test()
mylib/1.0.0 (test package): RUN: ./example

5.4 로컬 개발 워크플로 (conan install + build)

패키지를 매번 conan create하지 않으며, 로컬에서 수정하면서 빌드할 때:

# 1. 의존성 설치 (자기 자신은 제외)
conan install . --output-folder=build --build=missing
# 2. CMake 빌드
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake
cmake --build build

6. 원격 저장소 배포

6.1 conan upload — 로컬 캐시 → 원격

# 특정 패키지 업로드
conan upload "mylib/1.0.0" -r myremote --all
# 모든 리비전·바이너리 포함
conan upload "mylib/*" -r myremote --all

6.2 remote 추가 및 확인

# remote 목록
conan remote list
# 사내 Artifactory 추가
conan remote add mycompany https://mycompany.jfrog.io/artifactory/api/conan/conan-local
# remote 우선순위 (0이 가장 높음)
conan remote add mycompany https://... --insert=0

6.3 Artifactory 연동 예시

# 1. remote 추가
conan remote add mycompany https://mycompany.jfrog.io/artifactory/api/conan/conan-local
# 2. 패키지 생성
conan create . mylib/1.0.0@
# 3. 업로드
conan upload "mylib/1.0.0" -r mycompany --all

6.4 소비 측에서 사내 레포 사용

# conanfile.txt
[requires]
mylib/1.0.0
[generators]
CMakeDeps
CMakeToolchain
# mycompany remote에서 먼저 찾도록
conan install . --output-folder=build --build=missing

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

에러 1: “package_info() missing cpp_info.libs”

ERROR: .../package_info(): self.cpp_info.libs is empty

원인: package_info()에서 self.cpp_info.libs를 설정하지 않음 (라이브러리 패키지인 경우). 해결법:

def package_info(self):
    self.cpp_info.libs = [mylib]  # 실제 라이브러리 이름

헤더 전용이면:

def package_info(self):
    self.cpp_info.bindirs = []
    self.cpp_info.libdirs = []

에러 2: “exports_sources” 파일을 찾을 수 없음

ERROR: ... exports_sources ... not found

원인: exports_sources에 지정한 경로가 레시피 디렉터리에 없음. 해결법:

# 존재하는 경로만 지정
exports_sources = "CMakeLists.txt", "src/*", "include/*"
# 디렉터리 전체
exports_sources = "include/*"

에러 3: “CMake install failed” / “No install target”

CMake Error: ... install TARGETS given no RUNTIME DESTINATION

원인: CMakeLists.txt에 install() 타겟이 없거나 잘못됩니다. 해결법:

install(TARGETS mylib
    RUNTIME DESTINATION bin
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
)
install(DIRECTORY include/ DESTINATION include)

에러 4: test_package에서 “find_package(mylib) failed”

원인: package_info()cpp_info가 CMakeDeps에 제대로 전달되지 않음. 또는 CMake 타겟 이름 불일치. 해결법:

def package_info(self):
    self.cpp_info.libs = [mylib]
    # CMake 타겟 이름 명시 (기본은 패키지 이름)
    self.cpp_info.set_property("cmake_target_name", "mylib::mylib")

에러 5: “Binary not found” / “Can’t find a compatible binary”

ERROR: Missing prebuilt package for 'mylib/1.0.0'

원인: 해당 설정(OS, 컴파일러, arch 등)에 맞는 바이너리가 원격·캐시에 없음. 해결법:

# 소스에서 빌드
conan create . --build=missing
# 특정 패키지만 빌드
conan create . --build=mylib

에러 6: “Version conflict” (의존성 간)

ERROR: Conflict in mylib/1.0.0: requirement 'fmt/9.x' conflicts with 'fmt/10.1.1'

원인: 직접·간접 의존성의 버전 요구가 충돌. 해결법:

def requirements(self):
    self.requires("fmt/10.1.1", override=True)  # 강제로 이 버전 사용

에러 7: “conan create” 시 “layout()” 관련 오류

ERROR: ... layout(): self.source_folder is None

원인: exports_sources만 있고 외부 소스를 쓰지 않을 때, layout()에서 self.source_folder를 잘못 참조. 해결법: cmake_layout(self) 사용 시, Conan이 source_folderexports_sources 기준으로 설정합니다. conan create는 레시피 디렉터리를 소스로 사용합니다.

에러 8: Windows에서 “fPIC” 옵션 에러

ERROR: option 'fPIC' doesn't exist

원인: Windows에서는 fPIC가 의미 없는데 옵션에 남아 있음. 해결법:

def config_options(self):
    if self.settings.os == "Windows":
        del self.options.fPIC

에러 9: “Package not found” (upload 후)

원인: remote 순서, 인증, 또는 패키지 참조 형식 오류. 해결법:

# remote 확인
conan remote list
# 패키지 검색
conan search mylib -r mycompany
# 인증 (Artifactory)
conan remote add mycompany https://... --insert=0
# 사용자/비밀번호는 conan config set으로 또는 환경변수

에러 10: package_info의 includedirs가 비어 있음

원인: CMake install(DIRECTORY include/ DESTINATION include)로 설치했는데, 패키지 폴더 구조가 다름. 해결법:

def package_info(self):
    self.cpp_info.includedirs = [include]
    # 또는 실제 구조에 맞게
    self.cpp_info.includedirs = [include/mylib]

8. 베스트 프랙티스

8.1 버전 관리

  • 시맨틱 버전링: 1.2.3, 2.0.0 형식 사용
  • conanfile.py의 version: 가능하면 단일 소스(예: scm 또는 외부 파일)에서 가져오기
from conan.tools.scm import Git
from conan import ConanFile
class MylibConan(ConanFile):
    name = "mylib"
    version = "1.0.0"  # 또는 동적: self.version = ...

8.2 options 설계

  • shared: 정적/동적 라이브러리 선택 — 대부분의 C++ 라이브러리가 지원
  • fPIC: Linux/macOS에서 공유 라이브러리 시 필요
  • with_xxx: 기능 플래그 (예: with_ssl, with_tests)
options = {
    "shared": [True, False],
    "fPIC": [True, False],
    "with_ssl": [True, False],
}
default_options = {
    "shared": False,
    "fPIC": True,
    "with_ssl": True,
}

8.3 CMake install 규칙

  • install(TARGETS ...)로 라이브러리·실행 파일 설치
  • install(DIRECTORY include/ DESTINATION include)로 헤더 설치
  • Conan의 cmake.install()CMAKE_INSTALL_PREFIX를 패키지 폴더로 설정하므로, CMake 표준 경로 사용

8.4 test_package 필수화

  • conan create 전에 반드시 test_package로 검증
  • 실제 소비 시나리오(빌드·링크·실행)를 테스트

8.5 package_info 명확화

def package_info(self):
    self.cpp_info.libs = [mylib]
    self.cpp_info.includedirs = [include]
    # 필요 시
    self.cpp_info.defines = [MYLIB_VERSION=100]
    self.cpp_info.cxxflags = []

8.6 exports_sources 최소화

  • 빌드에 필요한 파일만 포함
  • *.md, *.txt 등 불필요한 파일 제외
exports_sources = "CMakeLists.txt", "src/*", "include/*"

9. 프로덕션 패턴

패턴 1: CI에서 conan create

# .github/workflows/conan-package.yml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Conan
        run: pip install conan
      - name: Create package
        run: conan create . --build=missing
      - name: Upload to Artifactory
        if: github.ref == 'refs/heads/main'
        run: |
          conan remote add mycompany ${{ secrets.CONAN_REMOTE_URL }} --insert=0
          conan user -r mycompany -p ${{ secrets.CONAN_PASSWORD }} ${{ secrets.CONAN_USER }}
          conan upload "mylib/*" -r mycompany --all

패턴 2: 버전 태그와 연동

# Git 태그에서 버전 추출
VERSION=$(git describe --tags --abbrev=0)
conan create . mylib/${VERSION}@
conan upload "mylib/${VERSION}" -r mycompany --all

패턴 3: conan export-pkg (기존 빌드 결과 패키징)

이미 빌드된 바이너리가 있을 때, 다시 빌드하지 않고 패키지로 만들 수 있습니다.

conan export-pkg . mylib/1.0.0@ -pf build/package

패턴 4: 프로필 공유

conan/
└── profiles/
    ├── linux-gcc12
    ├── windows-msvc2022
    └── macos-clang
conan create . -pr=conan/profiles/linux-gcc12

패턴 5: lockfile로 재현 가능한 빌드

# lockfile 생성
conan lock create .
# lockfile로 create (의존성 버전 고정)
conan create . --lockfile=conan.lock --build=missing

패턴 6: Docker로 멀티 플랫폼 패키지 생성

FROM ubuntu:22.04
RUN apt-get update && apt-get install -y python3-pip cmake g++ build-essential
RUN pip install conan
WORKDIR /app
COPY . .
RUN conan profile detect --force
RUN conan create . --build=missing

10. 구현 체크리스트

레시피 작성

  • name, version 정의
  • settings = “os”, “compiler”, “build_type”, “arch”
  • options (shared, fPIC 등) 필요 시 정의
  • config_options()에서 Windows fPIC 제거
  • exports_sources에 빌드 필요 파일만 포함
  • layout()에서 cmake_layout(self) 사용
  • generate()에서 CMakeToolchain, CMakeDeps 생성
  • build()에서 CMake configure + build
  • package()에서 cmake.install() 또는 copy()
  • package_info()에서 libs, includedirs 설정

CMake

  • install(TARGETS ...) 정의
  • install(DIRECTORY include/ ...) 정의
  • target_include_directories에 INSTALL_INTERFACE 포함

test_package

  • test_package/conanfile.py에서 self.tested_reference_str() 사용
  • test_package에서 실제 사용 시나리오 검증

배포

  • conan create 성공 확인
  • conan upload 전 remote·인증 설정
  • CI에서 자동 create·upload (선택)

정리

항목설명
레시피conanfile.py로 패키지 빌드·패키징·정보 정의
빌드conan create로 캐시에 패키지 생성
검증test_package로 소비 가능 여부 확인
배포conan upload로 원격 저장소에 업로드
에러package_info, exports_sources, CMake install 등 점검
핵심 원칙:
  1. package_info()를 반드시 올바르게 작성 — 소비자가 링크·include할 수 있게
  2. test_package로 패키지 품질 검증
  3. CMake install과 레시피의 package() 연동
  4. options로 플랫폼·기능별 바이너리 구성

자주 묻는 질문 (FAQ)

Q. 이 내용을 실무에서 언제 쓰나요?

A. 사내 라이브러리를 Conan 패키지로 배포할 때, Conan Center에 없는 라이브러리를 패키징할 때, 오픈소스 프로젝트를 Conan으로 배포할 때 활용합니다. conan install 한 번으로 팀 전체가 동일한 버전을 사용할 수 있습니다.

Q. conanfile.txt와 conanfile.py 중 뭘 써야 하나요?

A. 패키지를 만들 때는 반드시 conanfile.py입니다. 패키지를 쓸 때만 conanfile.txt로 충분합니다. 고급 옵션·조건부 의존성이 필요하면 소비 측에서도 conanfile.py를 씁니다.

Q. 선행으로 읽으면 좋은 글은?

A. vcpkg와 Conan 기초(#40-1)에서 Conan 사용법을 먼저 익히면 좋습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.

Q. 더 깊이 공부하려면?

A. Conan 2.x 공식 문서, JFrog Academy Conan 과정, Conan Center 레시피 GitHub를 참고하세요. 한 줄 요약: conanfile.py 레시피로 라이브러리를 Conan 패키지로 만들으며, conan create·upload로 빌드·배포할 수 있습니다. 다음 글: [C++ #53-4] Conan 고급 완벽 가이드 | lockfile·크로스 빌드·사내 레포 이전 글: [C++ #53-3] vcpkg 고급 활용 | Manifest·Triplet·오버레이·바이너리 캐시

관련 글


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

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


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

C++, Conan, 패키지관리, 빌드, CMake, 레시피 등으로 검색하시면 이 글이 도움이 됩니다.