iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0
Software Development

C++ 套件管理器求生指南 Conan vs Vcpkg系列 第 15 篇

D15:自己打包第一個 Conan 套件

  • 分享至 

  • xImage
  •  

到前 14 天為止,我們都是從「消費者」的角度來用套件管理器,輕鬆寫幾行設定,就能近乎無痛的導入第三方函式庫,然後心存感激的一邊開發,一邊謝謝 Conan 幫我們扛掉麻煩的編譯和設定。

但如果今天要用的函式庫,是我自己寫的呢?也能用 Conan 管理我自己的函式庫嗎?

答案是:當然可以!而且這正是 Conan 管理器的標準用法之一。

套件打包完就可以直接用了嗎?是喔。

需要先上傳套件到 ConanCenter 才能用嗎?不需要。

那今天我們就來學怎麼打包自己的 Conan Package 套件吧!

今天的目標:

  1. 用最簡單的方法把自己的函式庫打包成 Conan 套件。
  2. 學會 conan create 指令。
  3. 在另一個專案裡使用這個套件。

Conan 其實有個 conan new 指令可以一鍵產生專案。但是產生的東西有點雜,剛開始一下子看只會頭暈。所以今天我們先全部手搓,用最少的檔案,搞懂核心概念。

步驟一:超好用函式庫 super-lib

假設今天你寫了一個超級好用的函式庫,你給他取名叫 super-lib!

雖然 super-lib 超好用,但是以檔案結構來看,就是一個極為尋常普通的 CMake 專案,函式庫本身相當迷你。

super-lib/
├── conanfile.py
├── CMakeLists.txt
├── include/
│   └── super_lib.h
└── src/
    └── super_lib.cpp

include/super_lib.h:

#pragma once

void super_init();

src/super_lib.cpp:

#include <iostream>
#include "super_lib.h"

void super_init() {
    std::cout << "Hello from super-lib/0.1.0\n";
}

CMakeLists.txt 也非常普通,裡面沒有出現任何 Conan 的字眼:

cmake_minimum_required(VERSION 3.23)
project(super-lib CXX)

add_library(super-lib src/super_lib.cpp)
target_include_directories(super-lib PUBLIC include)

install(TARGETS super-lib)
install(FILES include/super_lib.h DESTINATION include)

好了,到此為止,這個函式庫的檔案就準備好了。

步驟二:conanfile.py,這個套件烹飪食譜

接下來是重點,我們要來寫食譜了!

為什麼叫食譜呢?因為打包套件就像做菜:準備食材、照步驟烹煮、最後裝盤上菜。

Conan 把這份「怎麼做」的說明叫做 Recipe (食譜),而 Recipe 最核心的檔案,就是我們熟悉的 conanfile.py。

from conan import ConanFile
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout


class SuperLibRecipe(ConanFile):
    name = "super-lib"
    version = "0.1.0"

    settings = "os", "compiler", "build_type", "arch"
    exports_sources = "CMakeLists.txt", "src/*", "include/*"

    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 = ["super-lib"]

注意喔,這次的 conanfile.py 是「生產端」,目的是產生套件,跟之前裝套件的「消費端」寫法不太一樣。

這份「食譜」的內容,用比喻來看就很好看懂了:

  • name、version:套件名稱跟版本號碼,合起來就是 super-lib/0.1.0,別人用這個名字來點菜。
  • settings:作業系統、編譯器、Debug/Release、CPU 架構不同,二進位檔就不同,這些會拿來算 Package ID。同一道菜,換個鍋子煮出來味道就不一樣。
  • exports_sources:要一起帶走的原始碼和 CMakeLists.txt,也就是食材。
  • layout()、generate()、build():依序備料、開火、下鍋,實際編譯套件。
  • package():呼叫 cmake --install 把成果放進套件目錄,料理成品裝盤。
  • package_info():告訴使用者要連結的 lib 名單,也就是告訴客人該怎麼吃。

好,食譜寫完了,接下來就開火吧!

步驟三:conan create 打包

開始打包套件,請到 CMake 專案的目錄下執行以下命令:

conan create .

請注意,conan create 指令最後的參數是個路徑,必須是個目錄,裡面要能找到 conanfile.py。

conan create 這個指令其實一口氣做了三件事:匯出、編譯、打包。

第一步「匯出」,就是把 conanfile.py 跟你列的原始碼,全部複製到一個乾淨的目錄下編譯(注意,不是在當前的專案目錄喔),所以 exports_sources 一定要寫全。

匯出這個步會看到類似下面輸出 log:

Exported: super-lib/0.1.0#3be5256d36c2aa67a2662bd503e29eea (2026-10-13 08:08:32 UTC)

第二步「編譯」,Conan 依序呼叫食譜中的 layout()、generate()、build() 這三個方法,分別對應到 CMake 的建置步驟。

你會在終端機看到一堆熟悉的 CMake 輸出,就是在編譯原始碼了。

最後一步「打包」,呼叫食譜中的 package() 方法。這裡其實就是呼叫 cmake --install:打包一個標頭檔,一個靜態庫。

package(): Packaged 1 '.h' file: super_lib.h
package(): Packaged 1 '.a' file: libsuper-lib.a
Full package reference: super-lib/0.1.0#3be5256d36c2aa67a2662bd503e29eea:38b8b2863892fd9462affa45e40edf183b436246#b8ea55c200632fd47bb7c55977b6cea0

仔細看最後一行 Full package reference,這就是我們昨天講解的四段結構:名稱/版本、Recipe Revision、Package ID、Package Revision。

看到了嗎?不過這次的長字串,是我們自己「煮」出來的喔。

步驟四:再打包一個 Debug 版

剛剛打包的是 Conan Profile 指定的 Release 版。如果需要 Debug 版的話怎麼辦呢?很簡單,再編譯一包 Debug 二進位檔就好了。

conan create . -s build_type=Debug
Full package reference: super-lib/0.1.0#3be5256d36c2aa67a2662bd503e29eea:1c144980be8c0fb2eae6beafa245995736ac235d#a0542159742c5b8b1b653ee285a4fcaf

用指令 conan list "super-lib/0.1.0:*" 去查,你就會發現同一個 recipe revision 底下,現在有兩個 package ID:一個是 Release,一個是 Debug。

正好驗證了昨天講的,只要有一項編譯設定不同,就會產生另一份二進位檔,Conan 不會搞混這兩包。

步驟五:在另一個專案使用 super-lib

好啦,現在我們切換到另一個專案,要透過 Conan 導入剛剛打包好的 super-lib 套件。

該怎麼做呢?

第一步就是在另一個專案的 conanfile.txt requires 區塊寫上我們自己的套件:

[requires]
super-lib/0.1.0

[generators]
CMakeDeps
CMakeToolchain

接著就是 CMakeLists.txt 要寫入 find_package() 以及 target_link_libraries():

cmake_minimum_required(VERSION 3.15)
project(app CXX)

find_package(super-lib REQUIRED)

add_executable(app src/main.cpp)
target_link_libraries(app PRIVATE super-lib::super-lib)

接下來的指令就跟之前一模一樣了。

conan install . --output-folder=build --build=missing
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
cmake --build build

吼吼~這次的 super-lib/0.1.0 是從我們自己的本機快取拿的,沒有從 ConanCenter 下載。

所以..打包完的套件在哪裡呢?

這次套件打包從頭到尾都是在本機進行的。打包完的套件會放在使用者家目錄下 ~/.conan2/p/ (Windows平台就是 C:\Users\YOUR_NAME\.conan2\p)

想知道 super-lib 套件確切放在哪,可以跑 conan cache path 命令:

$ conan cache path super-lib/0.1.0
/home/USER_NAME/.conan2/p/superec118a2baba2f/e

$ conan cache path super-lib/0.1.0:38b8b2863892fd9462affa45e40edf183b436246
/home/USER_NAME/.conan2/p/b/super9ca390f972d8d/p

只給套件名稱,印出的是食譜(recipe)的目錄。後面加上 package ID 才是二進位檔目錄。在這個目錄底下就能看到 include/ 和 lib/ 目錄以及實際的 .h 和 .a/.lib。

問題:可以用 CMake 以外的其他方式來編譯套件嗎?

這個範例裡面我們用 CMake 來編譯套件函式庫,那麼一定要用 CMake 嗎?當然不是,你也可以用 Makefile, Autotools, MSBuild, Xcode, SCons 等等,Conan 支援非常多不同的建構系統來編譯套件,這裡我們就不一一細講,你只需要知道這事做得到,然後請 AI 協助你寫。


上一篇
D14:Conan Package ID 與 Revision 是什麼?
下一篇
D16:怎麼確保 Conan 套件能用? 談談 test_package 的用途
系列文
C++ 套件管理器求生指南 Conan vs Vcpkg 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言