iT邦幫忙

2026 iThome 鐵人賽

DAY 16
0
Software Development

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

D16:怎麼確保 Conan 套件能用? 談談 test_package 的用途

  • 分享至 

  • xImage
  •  

昨天我們親手打包了 super-lib 套件,從頭到尾跑完,到最後印出一長串套件ID,看起來很有成就感。

那問題來了:conan create 成功,套件就一定能完全沒問題嗎?

答案是:不一定喔。

今天的目標:

  1. 看看為什麼一個壞掉的套件可以順利「打包成功」。
  2. 寫一個 test_package,讓 Conan 自動幫我們驗收

一、打包成功,不代表套件完全沒問題喔

拿昨天的 super-lib 來說吧。假如 package_info() 裡面有拼錯字:

    def package_info(self):
        self.cpp_info.libs = ["super_lib"]

lib 檔名是連字號 super-lib,但是你手滑不小心寫成底線了。這樣子到時候 Linker 一定會有問題的。

但是這時你去跑 conan create 指令:

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

咦,結果一樣成功了耶,連警告都沒有。

怎麼會這樣啊?

原來啊,conan create 指令只負責編譯跟打包套件,但是卻不會真的去「試用套件」。

package_info() 裡面的資訊是寫給「套件消費者」看的,要等到有人真的導入了這個套件,內容才會被讀取到。也就是說,這個錯會一路直到另一個專案安裝了 super-lib 時才會被發現。

這時候同事就會跑來問你:「欸,你的套件怎麼發生連結錯誤?」

有點尷尬呀。

二、寫個 test_package 替套件做驗收

怎麼辦呢?解法很簡單:套件打包完,自己先當第一個使用者囉!

這就是 Conan 的標準做法: 寫一個 test_package 幫套件驗收。

test_package 就是個迷你 Conan/CMake 消費端專案。

我們會利用這個迷你專案,實際安裝套件並且編譯出一個叫做 example 的執行檔,並且跑看看。

只要這個流程可以跑通,你至少就可以確定這個套件可以通過編譯,並且編譯後跑起來沒有錯誤。

請到專案目錄底下創建一個子目錄 test_package :

super-lib/
├── conanfile.py
├── CMakeLists.txt
├── include/
├── src/
└── test_package/
    ├── conanfile.py
    ├── CMakeLists.txt
    └── src/
        └── example.cpp

目錄名字 test_package 是約定的慣例,裡面是個迷你 Conan/CMake 專案。

example.cpp 裡就隨便呼叫一下套件內的函數,確實測試一下套件:

#include <super_lib.h>

int main() {
    super_init();
}

CMakeLists.txt 記得加 super-lib,除此之外就是個一般專案:

cmake_minimum_required(VERSION 3.15)
project(PackageTest CXX)

find_package(super-lib REQUIRED)

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

接下來重點來了 test_package/conanfile.py:

import os

from conan import ConanFile
from conan.tools.build import can_run
from conan.tools.cmake import CMake, cmake_layout

class SuperLibTestConan(ConanFile):
    settings = "os", "compiler", "build_type", "arch"
    generators = "CMakeDeps", "CMakeToolchain"

    def requirements(self):
        self.requires(self.tested_reference_str)

    def layout(self):
        cmake_layout(self)

    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()

    def test(self):
        if can_run(self):
            cmd = os.path.join(self.cpp.build.bindir, "example")
            self.run(cmd, env="conanrun")

這份檔案看起來有點長,但其實跟昨天的食譜差不多。

兩個地方要注意:

一、self.tested_reference_str:這個變數會指向「剛剛打包好的那個套件」,所以不用寫死 super-lib/0.1.0。
二、最後的 test() 方法會實際跑一次編譯出來的執行檔。

三、再跑一次 conan create

這一切都準備好之後,我們就來重新跑一次套件打包。

test_package 這個目錄名稱是約定好的,Conan 看到就會自動用。

我們直接跑一次打包指令,看看能不能抓到拼錯字:

conan create .

看到錯誤訊息了嗎?Library 'super_lib' not found in package。

CMake Error at build/gcc-14-x86_64-gnu17-release/generators/cmakedeps_macros.cmake:81 (message):
  Library 'super_lib' not found in package.  If 'super_lib' is a system
  library, declare it with 'cpp_info.system_libs' property
...
ERROR: super-lib/0.1.0 (test package): Error in build() method, line 20
	cmake.configure()
	ConanException: Error 1 while executing

剛剛沒人發現的錯,現在打包的過程中就被攔下來囉。

把 libs 改回 ["super-lib"],再跑一次:

======== Launching test_package ========
...
super-lib/0.1.0 (test package): Running test()
Hello from super-lib/0.1.0

這次打包就成功了,看到 Hello from super-lib/0.1.0 了!

所以完整來說,conan create 其實做了四件事:匯出、編譯、打包,最後用 test_package 驗收。

順帶一提,test_package 只是驗收用的,不會被打包進套件裡,所以不用擔心它跟著套件跑到同事那邊。

以後打包自己的套件,記得順手寫一個 test_package,同事會很感謝你的。


上一篇
D15:自己打包第一個 Conan 套件
下一篇
D17:Conan options 自定義套件選配
系列文
C++ 套件管理器求生指南 Conan vs Vcpkg 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言