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 第 26 期:AI 批評指南

最近在讀《高效槓桿力》,書中提出一套變革管理框架:「尋找關鍵支點,重新配置資源。」當然,書裡給出很多案例,說明如何找到支點,只是我同時在想,如何將他們帶到我面對的情境呢? ✨ 科技觀點 Pluralistic: The Reverse-Centaur’s Guide to Criticizing AI 看到有人非常認真討論事情,即使是批評 AI,都會讓我有興趣。 附上一些我的觀點: 1) 成長型公司聽起來很美好,每個人都會想待在那,但當它變成前提時就是另一回事了。很多決策都會以成長為基礎,最後就是投資人跟企業都沒辦法接受不成長的代價。 2) 常常在爭論 AI 是否會取代工作,看的是 AI 的兩個面向,賦能與自動化,哪個會更符合當前情境。贊同賦能的人會認為 AI 帶來生產力的解放,並創造價值,可是實際上呢? 3) 很多人提過 AI 的解壓縮 / 壓縮特性,特別是在履歷或信件應用。

By Ken Chen

Weekly Issue 第 25 期:Slack 基礎設施爭議

因為地緣政治議題,我們會關心資料存放的地點是否足夠安全,即使當使用者被盯上,他仍然可以放心資料足夠隱密。這也是為什麼當網路上傳出 Slack 台灣的資料轉移到阿里雲時,會引起爭議的原因。 Slack 已經出面澄清並無此事,這也讓我們反思,當軟體業面臨這類公關危機時,應該要揭露到什麼程度。 🗞️ 熱門新聞 Slack 在臺服務將移轉至中國? Salesforce:臺灣用戶使用全球基礎設施,與阿里巴巴無關 前幾天 Salesforce 傳出要將 Slack 台灣資料轉移到阿里雲,立刻引起一陣討論,有 Salesforce 的人出來澄清,說沒有這回事。 「台灣市場一直以來都是採用 Global Infrastructure 全球基礎設施。簡單說,台灣用戶的資料是儲存在美洲或亞太區(如日本),跟中國的阿里雲在物理和邏輯上都是完全切開的。 」 讓我有興趣的是,Salesforce 沒有說他們是用哪個雲平台。我們以前有次遇到類似情況,也討論到是否揭露使用平台。當時我持反對意見,認為只需要揭露「使用全球基礎設施」已經夠了,頂多說非中國廠商的服務就好,不需要也不應該說明具體是哪個。

By Ken Chen

Weekly Issue 第 24 期:網路的精神高地

前陣子去了雪梨一趟,跟布里斯本或台北都形成有趣的對比,旅行中也不斷在想,一座城市如何發展出自己的文化?這有點像是網路平台如何形成聚落,而又如何消亡。 很喜歡本期談知乎的一篇文章,理想主義的光輝是最吸引人的,我常在想,有沒有辦法將那座「看不見的城市」帶到真實世界中。 🗞️ 熱門新聞 A ChatGPT prompt equals about 5.1 seconds of Netflix 看到 Simon Willison 提到,如果 Sam Altman 的資訊是對的,每個 LLM 提問相當於 5.1s 的 Netflix 影片耗能。 計算的需求讓輝達跟台積電挖到金礦,那電力需求又會讓誰挖到金礦呢? ✨ 科技觀點 我们失去的不只是知乎,而是中文互联网的精神高地 「那时的知乎,更像“思想沙龙”,而非“内容平台”。」 昨天跟朋友聊天,

By Ken Chen

Weekly Issue 第 23 期:Mastodon CEO 離職感言

電子報本質是種自媒體,儘管我發文前都會確認,還因為能力所限,偶爾還是有沒做好的地方。每次遇到時我都會想,不知道其他自媒體是如何查證的呢? 現代的訊息越來越快,不只是自媒體,很多專業媒體也不見得有完備的查證能力,我猜當內容氾濫,「真實」會變得越來越有價值,最終變成一門生意。 🗞️ 熱門新聞 Explore the independent web Ghost 最新一期的電子報談到他們如何處理「內容發現」的問題。 簡單來說,他們有個內容發現工具 Ghost Explore,如果創作者願意提交自己的網站數據,他們能依照這些網站數據來推薦。再來,他們還會參考 ahrefs 的資料,判斷該網域是否具有高品質。 這比 Substack 發展社群工具,更貼近我對產品的想像。現代內容網站基本都需要演算法,這已經不是要不要,是怎麼設計的問題。 My next chapter with Mastodon Mastodon 的 CEO 即將卸任,他發了篇談談這段時間的心路歷程。

By Ken Chen