解讀C/C++應用包管理的Why和How-Github架構師

一、背景
本文整理自Johannes Nicolai在JFrog 2019用戶大會上的講演《DevOps for Non-Hipsters(aka C/C++ programmers)》。

Johannes Nicolai是Github的解決方案架構師,主要負責德語區的用戶。他和很多製造業的用戶(多數使用C/C++)交流,詢問他們在DevOps或持續交付方面的挑戰,通常會得到如下的描述:
解讀C/C++應用包管理的Why和How-Github架構師
在嵌入式C/C++領域,花費幾十個小時完成一個完整的DevOps流水線並不少見。爲某一個提交運行單獨的構建和測試幾乎是不可能的,通常每次構建都包含了幾百個同事所有的提交。而構建時間長的主要原因在於交付包包含了大量的依賴包,而每次構建這些依賴包都需要從頭開始重新構建。上述的描述並不限於德語區,Johannes詢問了美國製造業的用戶,也得到了類似的反饋。
從業界的發展來看,聲明式包管理能夠很好的解決上述的問題。在交付包中通過聲明描述所需的依賴包,在構建時根據聲明從包管理系統中獲取相應的依賴包,這樣能夠大大縮短構建時間。Java或JavaScript的開發者很熟悉這樣的方式。

對於像Java或JavaScript這樣的開發語言,包管理的實現相對簡單,包的每一個版本只對應一個二進制文件。而在C/C++中,由於操作系統、架構、編譯器等的不同,包的每一個版本會對應多個不同的二進制文件,彼此之間還並不兼容。這也就導致了C/C++的包管理一直是業界公認的難題。
當然,針對C/C++的開發,現在也出現了像Conan這樣比較成熟的包管理解決方案。Johannes在本次講演中首先分析了爲什麼要在DevOps中引入包管理,然後通過演示介紹了Conan如何通過方便的包管理和開發方式,幫助C/C++程序員實現簡潔、高效的DevOps流水線。

二、爲什麼要在DevOps中引入包管理

現在業界大都在推行敏捷,而在敏捷提出的12條原則中,其中一條就是:通過早期和持續型的高價值工作交付滿足“客戶”。
通過持續性的交付,首先能夠快速發現問題,從而儘早解決問題,而不是每次發佈前都要積累大量的問題,從而導致過長的修復時間和交付質量的下降。

其次,用戶可能一開始並不是特別清楚自己的需求。通過持續性的交付,用戶可以不斷的試用來漸進明晰地明確自己的實際需求,從而保證了交付的有效性。

要實現敏捷原則所要求的持續性的交付,我們必須實現持續性、可重複的DevOps流水線。而爲了實現這樣的DevOps,一個基本原則是要做到“只構建一次二進制文件”。

也就是說,每一個版本的交付包,我們只構建一次。獲得其對應的二進制文件後,在DevOps的後續階段、不同環境中,都應該用且只用這同一個二進制文件。

然而,針對C/C++的應用來說,各種不同的目標環境導致同一個版本的交付包,必然會對應多個互不兼容的二進制文件。在這種情況,要做到僅一次構建,無疑需要藉助於良好的包管理解決方案。

通過引入包管理系統,可以爲C/C++包的每一個版本預編譯好多個與之對應的面向不同目標環境的二進制包,再通過語義化版本及兼容環境的描述,在構建過程中直接獲取對應的二進制包,從而能夠大大節省構建的時間,保證DevOps流水線的一致性和可重複性。同時,當發現某些問題,如安全漏洞或開源許可證錯誤時,也可以通過對依賴關係的管理,迅速定位問題的影響範圍,提升問題的解決效率。

對於C/C++開發常用的子模塊的方式,並不能滿足上述DevOps的要求。子模塊的方式不能解決構建時間長的問題,不能保證所依賴的庫的不可變性,對版本的依賴關係缺乏靈活的定義和管理,對兼容性的分析和處理也缺乏內置的解決方案。

類似的,通過Git LFS來管理C/C++的包也不是一個好的方式。Git LFS缺乏對版本依賴關係的靈活定義和管理,缺乏對兼容性分析和處理的內置解決方案,同樣不能解決構建時間長的問題。
因此,要提升C/C++應用的DevOps效率和質量,我們需要引入與Java、JavaScript等類似的包管理解決方案。而目前這一領域發展最快、最受業界關注的就是Conan。

三、Conan——C/C++的包管理方案

Conan(https://conan.io)是一個開源的解決方案,爲C/C++應用提供了跨平臺的包管理方式。而JFrog收購Conan後,通過結合其在製品管理方面產品和技術的優勢,更提升了Conan對C/C++應用的支持能力

Conan具有良好的兼容性,能夠與當前C/C++領域應用的各種構建系統和編譯器配合使用。

Conan提供了完整的C/C++應用依賴關係管理能力,能夠支持語義化版本描述、傳遞依賴的解析、依賴衝突的分析與解決,以及靈活的範圍化版本描述等。

Conan還爲C/C++應用的DevOps建設提供了豐富的工具支持:
針對包倉庫,提供了原生、開源的Conan Server,同時JFrog的Artifactory、Bintray也提供了功能更爲豐富、全面的商業化產品支持;
Conan的客戶端,與各種構建系統對接,實現基於Conan的C/C++構建;
Conan提供與Jenkins、Travis CI等工具的對接,實現C/C++應用自動化的、可重複的DevOps流水線。

在Conan的解決方案中,包的每一個版本都根據目標環境的不同,如架構、操作系統、編譯器等,預編譯好與之對應的二進制包。構建時,Conan客戶端只下載與當前目標環境兼容的二進制包,從而在保證一致性的同時,提升了構建的效率。
對於特殊環境,還沒有對應的預編譯二進制包的情況,Conan通過定義包的Recipe,描述瞭如何構建該包的二進制包的過程,Conan客戶端可以即時構建出一個新的,匹配與當前特殊環境的新二進制包,供應用構建使用。同時,這個新二進制包也可以存回包倉庫當中,供後續的構建直接引用。

綜上所述,與Java、JavaScript等使用的類似,Conan爲C/C++開發者提供了一個成熟的、功能完整、工具完備的包管理解決方案,能夠輔助C/C++的開發者創建穩定、高效、一致、可重複的DevOps流水線。

四、如何在C/C++應用中使用Conan

Johannes在演講中還通過演示,展示瞭如何基於Conan,實現便捷、高效的C/C++應用的構建。
Johannes所用的例子不是簡單的“Hello World”,而是github上一個真實項目:

要使用Conan,我們只需爲每一個C/C++應用增加一個conanfile.txt,用以描述其依賴關係:

利用“conan remote add”命令,可以將Conan客戶端和Conan的包倉庫建立關聯,再執行“conan install”,就可以將符合目標環境需求的所有依賴二進制包下載在本地。

在編輯構建參數,如使用CMake構建,就修改CMakeLists.txt,加入conan的配置,就可以集成下載的依賴二進制包,完成C/C++應用的構建。

除了直接引用Conan倉庫中已有的包及其二進制文件,利用Conan也可以創建自己開發的Conan包作爲庫,供其他C/C++應用依賴。Johannes還以github上的另一個項目演示瞭如何創建自己的Conan包:

要創建Conan的庫包,需要爲項目增加conanfile.py文件,如上圖中的右半部分,改py文件就對應了之前提到的Conan包的Recipe,它除了描述了該包的基本信息之外,還通過函數定義瞭如何構建該庫包得到二進制文件的過程。

通過執行“conan create”命令,我們就可以生成自定義的Conan包作爲內部庫,再執行“conan upload”將其上傳到Conan包倉庫,就可以被其他C/C++應用引用、依賴了。
此外,Conan還可以與Jenkins等工具集成,通過自動化、並行的方式,一次性構建出同一版本包,針對不同目標環境的所有二進制文件:

基於Conan的包管理方案,通過與GitHub、Jenkins、Artifactory、Bintray等工具對接,可以實現完整的C/C++應用的DevOps流水線:
解讀C/C++應用包管理的Why和How-Github架構師
通過演示可以看出,在C/C++應用中引入Conan的包管理,方式是直觀、簡便的,附加的工作負載並不多。而通過與各種工具的集成,可以基於Conan方便地創建C/C++應用的DevOps流水線,滿足敏捷的需求。

五、總結

敏捷化是目前業界應用研發的發展方向。通過實施敏捷化,我們可以實現迅速的、持續的產品交付,從而儘早發現問題,儘早解決問題。而且,通過快速、持續的交付,我們也可以獲得用戶持續的反饋,漸進明細地挖掘和實現用戶的真正需求。

對於C/C++應用及開發者來說,基於Conan的包管理方案,以及與DevOps領域工具的集成使用,可以創建便捷、高效、一致性、可重複的DevOps流水線,從而滿足敏捷化的需求。

注:本文圖片因平臺原因不能上傳,可關注“JFrog傑蛙DevOps”公衆號,每週二在線課堂,乾貨分享~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章