Conan:C/C++ 的套件管理工具

開發 C++ 程式時,套件管理會是個困擾開發者的問題,C++ 不像 Python 有 pip;node.js 有 npm;lua 有 rock;C# 有 Nuget。它就只是沒有。沒有套件管理,當不同開發環境的使用者要開發程式時,不僅需要手動將相關的檔案塞進 repository 中,還會遇到相容性的問題,例如小明使用 paho-c 1.3.0 開發,開發到一半時,另一位開發者小華引用了小明放在 repo 中 include 資料夾下的 header file,卻使用了自己的 1.3.1 shared library,這使得兩個人的版本不相容,要花很多時間除錯。

此外,當需要更新 repo 中的第三方套件版本時,需要手動將檔案放到 include 跟 libs 的資料夾,你引用多少套套件,你就要塞多少檔案進去;而跨平台的問題也是,Win32 可能要一份,Win64 要一份,Release 跟 Debug 的 Libs 各要一份,Linux 跟 Mac 再各要一份,最後 x86、arm、mips 再各要一份,自行排列組合一下就知道這個更新的痛苦了。為什麼我知道呢?因為我就是那個被困擾的人。

好在許多開發者都有同樣的問題,於是 Conan 出來了,這是一個 C++ 套件管理工具,用 Python 寫成,目的在於協助開發者解決上述的困擾。本文會簡單介紹 Conan 的用法,希望大家看完後都能如獲新生。

Install conan

首先來安裝 conan 這套工具,由於 conan 是用 python 寫的,也有在 pip 的 remote repo 中,因此只要用 pip 即可安裝

ken@DESKTOP-2R08VK6:~/git/conan/build$ pip3 install conan
Collecting conan
    Downloading [https://files.pythonhosted.org/packages/2e/b7/560406ecd9d20e308498ce378dc8c1e0bc932f44d5377bc0ca62ec8dd75b/conan-1.21.1.tar.gz](https://files.pythonhosted.org/packages/2e/b7/560406ecd9d20e308498ce378dc8c1e0bc932f44d5377bc0ca62ec8dd75b/conan-1.21.1.tar.gz) (552kB)
    100% |████████████████████████████████| 552kB 761kB/s 
Collecting Jinja2<3,>=2.3 (from conan)
...

安裝完記得重新讀取 .profile,引入 conan 指令

source ~/.profile

Prepare Environment

來看一下專案環境,假設我們參照前篇,用 cmake 來進行編譯,工作目錄會長

project/
├── build/
├── src/
|   ├── CMakeLists.txt
|   └── hello.cpp
├── CMakeLists.txt
├── conanfile.txt
└── README

其中 src 放原始碼,hello.cpp 內容為經典的 hello, world

#include "Poco/Thread.h"
#include "Poco/Runnable.h"
#include <iostream>

class HelloRunnable: public Poco::Runnable
{
    virtual void run()
    {
        std::cout << "Hello, world!" << std::endl;
    }
};

int main()
{
    HelloRunnable runnable;
    Poco::Thread thread;
    thread.start(runnable);
    thread.join();
    return 0;
}

這邊使用 Poco 的 Lib 來創建 thread,並呼叫一個印出 Hello, world 的 Runnable。之所以用 Poco 是因為 conan 官方也用 Poco 當範例,而且方便進行跨平台。Lib 本身不是重點,重點是有使用了一個第三方套件。

關於 CMakeLists.txt 的使用請參照前篇,不再多述,兩個 CMakeLists.txt 分別是

# .CmakeLists.txt

CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(HELLOLIB)
ADD_SUBDIRECTORY(src)

以及

# .src/CmakeLists.txt

ADD_EXECUTABLE(hello hello.cpp)

Edit conanfile

conan 使用 conanfile.txt 來管理套件,conanfile 的格式有點像 TOML,但我找不到官方說法,對使用者來說也許不用想太多,只要知道是某種配置文件就行,它的內容是

[requires]
Poco/1.9.4@pocoproject/stable

[generators]
cmake

這段內容表示依賴套件是 Poco,版本 1.9.4,來源 pocoproject/stable,產生cmake 模組。

接著進到 build 目錄,使用 conan

ken@DESKTOP-2R08VK6:~/git/conan/build$ conan install ..
Configuration:
[settings]
arch=x86_64
arch_build=x86_64
build_type=Release
compiler=gcc
compiler.libcxx=libstdc++
compiler.version=7
os=Linux
os_build=Linux
[options]
[build_requires]
[env]

conanfile.txt: Installing package
Requirements
    OpenSSL/1.0.2o@conan/stable from 'conan-center' - Cache
    Poco/1.9.4@pocoproject/stable from 'conan-center' - Cache
    zlib/1.2.11@conan/stable from 'conan-center' - Cache
Packages
    OpenSSL/1.0.2o@conan/stable:b781af3f476d0aa5070a0a35b544db7a3c193cc8 - Cache
    Poco/1.9.4@pocoproject/stable:57e3039664a87aab5ccabd995efae6da01c1ff17 - Cache
    zlib/1.2.11@conan/stable:d50a0d523d98c15bb147b18fa7d203887c38be8b - Cache

zlib/1.2.11@conan/stable: Already installed!
OpenSSL/1.0.2o@conan/stable: Already installed!
Poco/1.9.4@pocoproject/stable: Already installed!
conanfile.txt: Generator cmake created conanbuildinfo.cmake
conanfile.txt: Generator txt created conanbuildinfo.txt
conanfile.txt: Generated conaninfo.txt
conanfile.txt: Generated graphinfo

然後工作目錄就變成

project/
├── build/
|   ├── ...
|   ├── conanbuildinfo.cmake
|   └── ...
├── src/
|   ├── CMakeLists.txt
|   └── hello.cpp
├── CMakeLists.txt
├── conanfile.txt
└── README

跟之前對照,多出了 cmake 模組 conanbuildinfo.cmake

Modify CMakeLists

之所以要有 cmake 模組,就是為了讓 cmake 引用,因此要回頭改 CMakeLists.txt,將 conan 相關的指令加進去

# .CMakeLists.txt

CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(HELLOLIB)

INCLUDE(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
CONAN_BASIC_SETUP()

INCLUDE_DIRECTORIES(${CONAN_INCLUDE_DIRS})
MESSAGE(STATUS ${CONAN_INCLUDE_DIRS})
ADD_SUBDIRECTORY(src)

其中 INCLUDE 是引用 conan 產生的 cmake 模組;CONAN_BASIC_SETUP 會設定 conan 需要的變數;INCLUDE_DIRECTORIES 是引用 conan 相關的 header file,免去手動搬運 header file 的麻煩。MESSAGE 可加可不加,這邊是用來印出 conan header file 的所在目錄,讓開發者心底踏實一點。

而另一個 CMakeLists.txt 則改成

# .src/CMakeLists.txt

ADD_EXECUTABLE(hello hello.cpp)
TARGET_LINK_LIBRARIES(hello ${CONAN_LIBS})

非常單純,就是鏈結 conan 相關的 lib。

Build

關鍵的時候到了,用 cmake 配置並編譯

ken@DESKTOP-2R08VK6:~/git/conan/build$ cmake ..
-- The C compiler identification is GNU 7.4.0
...
-- /home/ken/.conan/data/Poco/1.9.4/pocoproject/stable/package/57e3039664a87aab5ccabd995efae6da01c1ff17/include/home/ken/.conan/data/OpenSSL/1.0.2o/conan/stable/package/b781af3f476d0aa5070a0a35b544db7a3c193cc8/include/home/ken/.conan/data/zlib/1.2.11/conan/stable/package/d50a0d523d98c15bb147b18fa7d203887c38be8b/include
...

可以看到 conan 抓下來的檔案會放在 user 家目錄的 .conan。

ken@DESKTOP-2R08VK6:~/git/conan/build$ cmake --build .
Scanning dependencies of target hello
[ 50%] Building CXX object src/CMakeFiles/hello.dir/hello.cpp.o
[100%] Linking CXX executable ../bin/hello
[100%] Built target hello

編譯完成,來執行看看

ken@DESKTOP-2R08VK6:~/git/conan/build$ ./bin/hello 
Hello, world!

結束!conan 自動抓完 header file 跟 library,開發者不要再煩惱套件跟庫管理了,專心來享受寫程式的快樂吧。

小結

看到 conan 能自動管理套件,真的不是個「爽」字能形容,套句強者我同事的話:「我不常寫 C++,因為它的套件管理太可怕了」。有使用開源程式碼開發的人,應該非常能了解這種感受。

在使用 conan 開發途中,難免踩到一些坑,直接上 GitHub 發問後,沒想到 conan 的 Contributor 在短短幾小時內就快速回覆,還 involve 相關專案的 Contributor 一起來確認,現在開源社群的活躍度已經這麼厲害了嗎?

要說 conan 的問題,可能是普及度還不夠,有時需要的 library 不一定會有,但我覺得這沒有關係,只要會 python,就可以捲起袖子,把自己要用的 library 打包後回饋,讓其他人也能快速利用同樣的資源。畢竟人生苦短,不要重複造輪子,我們可以面朝大海。

Reference

Read more

Weekly Issue 第 9 期:Ghost 發布 6.0 版本

Ghost Release 新版了!距離上次大版號更新,已經過了 3 年多,這幾年來,創作者經濟變化得很快,Ghost 也嘗試讓創作者更容易經營自己的內容。 我會等 6.0 發布一陣子,穩定下來後才會更新。很期待他們下一步會是什麼。 🗞️ 熱門新聞 Ghost 6.0 Ghost Release 6.0。 兩個重量級更新:支援 ActivityPub,讓 Ghost 可以 Leverage 社群媒體分發渠道;以及內建 Analytics,支援流量分析。這剛好就是兩個我最想要的功能,Great Work。 常說經營內容的痛點在,不知道如何發佈內容,不知道訪客從哪來。當然這都可以用工具協助,例如設定 GA、或者使用 Postiz 等來經營社群,可是我覺得一個好的平台應該要替創作者處理掉這些事,Ghost

By Ken Chen

Weekly Issue 第 8 期:數位時代的遷徙自由

以前在開發內容平台產品時,常常想,如果有天我們的使用者要離開平台,他們擁有自由嗎?在現代,數位創作者有點像是佃農,替平台生產內容,可是因為數位落差,他們沒有移動的能力。 隨著時代進步,法規應該要與時俱進,這期選了數位部的公告草案,告訴我們科技與制度可以如何相輔相成。 另外,從本期開始,加入了目錄大綱,希望讓讀者閱讀時能更容易在不同議題間切換。 🗞️ 熱門新聞 社交資料可攜權與互通性 在唐鳳那看到這則消息,最近衛城出版編輯的帳號被無預警停權,引發討論,我自己也常常焦慮,當使用這些便利的平台服務時,我們是不是交出一些沒意識到的權利? 身為個人,可行的策略是,在發布內容到平台前,先保留一份在自己手中,但這其中的不平等顯而易見。《數位選擇法案》讓我理解到,創作者有機會在一個更好更平等的環境下創作。 我希望台灣也能有這樣的一天。 I gave the AI arms and legs – then it rejected me 在 HN 上看到的新聞,有名開發者發現自己的函式庫被用在 Claude

By Ken Chen

Weekly Issue 第 7 期:從 GitHub Spark 看 Prompt 工程

近期開始有人建議用 Context Engineering 來取代 Prompt Engineering,的確相較於 Prompt,Context 是更精確的用詞。前一期也提到,當 Duolingo 的 CEO 被問到 AI 是否只是模型套皮時,他也說模型一定有影響,但更多是關乎你的 Context。 那麼,業界現在是如何看待 Prompt 的呢?Github Spark 跟 V0 的例子或許能提供一些參考。 🗞️ 熱門新聞 Using GitHub Spark to reverse engineer GitHub Spark GitHub Spark 最近推出公開預覽,讓你可以用 prompt 直接開發應用。 作者用逆向工程,找出 Spark 的 system

By Ken Chen

Weekly Issue 第 6 期:Duolingo CEO 看 AI 與遊戲化

現在是 AI 時代,大家都在想怎麼讓自己的產品跟 AI 掛勾,但具體要怎麼做呢?背後的思考有哪些?Duolingo 給出他們自己的觀點。 例如,現在的產品是否只是 AI 套皮,你接收使用者的問題,套上自己的提詞後,拿去給 OpenAI,要它回答你?在現在百家爭鳴的情況下,選擇哪個模型會有差嗎?AI 能帶來新用戶與新營收嗎?等等。 另外本週也選了一篇少數派的文章,談 AI 對 RSS 的影響,對 RSS 未來方向有興趣的人不妨看看。 🗞️ 熱門新聞 Duolingo CEO Luis von Ahn wants you addicted to learning Duolingo CEO 專訪,相當紮實,推薦閱讀。 「對我們來說,

By Ken Chen