如何看待 Windows 的 C++ 包管理器 vcpkg?

Microsoft/vcpkg


作為vcpkg主要貢獻者之一(Microsoft/vcpkg下面的sdcb就是我),我覺得vcpkg主要貢獻在於解決了c++/vc++很大的短板。

如果要做一個應用程序,我們往往會用到很多第三方庫,這時庫包管理工具就很重要,如js/npm,c#/nuget,php/composer之類,但vc++一直沒一個很舒服的包管理工具。很多c++第三方庫對vc++都非常不友好,誰能輕而易舉地在vc++上編譯一個openssl呢?nuget出現試圖解決這個問題,但出現更大的問題就是直接下載二進位文件,太大,下載了一個vs2012的又不支持vs2013,版本之間很難共用,想去調一下配置又不可能(因為下載的是二進位文件)。我還記得曾經為編譯一個boost看配置、折騰半天。舉個例子,我為mysql做了一個vcpkg包,更是折騰。而這時vcpkg就誕生了,解決了上述所有的問題,比如裝一個mysql客戶端,你只需要:

vcpkg install libmysql

就行了,你不需要知道我當時為了調通這個包在之後做了多少次編譯、重新編譯、修改配置、加入patch、兼容vs2015/vs2017之類的工作,it just works。如果它沒按你想像中那樣工作,你還可以看日誌,稍微改一下配置,如果有bug還可以立馬提PR,幾位MSFT的維護者都非常勤快,基本可以很快就看到就反饋意見或merge。

當然vcpkg還有很多缺點,之前MSFT的維護者就聯繫過我聊過,我覺得vcpkg的問題有:

  1. 有些包或有些包的某些環境,質量太低,之前我經歷過有些包安裝了好幾個小時之後編譯失敗,或者運行時報錯,那是非常非常不爽(所以我提了很多PR)
  2. 包能安裝的環境配置,是通過cmake代碼來完成,這一塊我覺得應該放在配置中(作者也同意,並表示計劃改),這樣就可以儘早的從配置不支持中報錯返回而不是等幾個小時編譯後才失敗
  3. 社區互動。現在知道vcpkg的少,用vcpkg的人更不多,微軟的維護者也跟我說最希望在vcpkg中看到的就是社區互動,希望大家關注vcpkg,試試vcpkg,說說它的好與不好。
  4. CI(持續集成),也是為了提高質量。現在vcpkg後台有一定的CI,但遠遠不夠。現在的CI主要跑了一些安裝之類的流程,但沒有具體與跑每一個包下的每一個配置。這就導致如果包之類有顯式或潛在的依賴,改了一個包就可能讓另一個包炸了,這也是可以提升的地方,微軟的維護者也說在working on it.

然後我也希望大家關注vcpkg,試試vcpkg,說說它的好與不好的地方,一起改進。


誰用誰知道。再配合WSL,從來沒想過寫一個跨平台組件會這樣方便。

反正裂牆推薦。


已用,淚流滿面. 比如想裝gtest直接"vcpkg.exe install gtest"就ok了.

然後工程里直接#include &,然後就可以了! 直接就用上了,連鏈接庫都是自動鏈接,更不用去選什麼包含目錄,超爽!

即使你用cmake也不怕,因為vcpkg裝好想要的庫後會提示你cmake可以通過findpackage來找裝好的庫. 已經支持的庫居然還真不少了,boost之類的自不必說, pcre,freetype,gtest,catch什麼的都有. 強烈建議所有windows程序員試用!

還記得多年前初學C++

我都恐懼的無從下手

只會傻傻的看著一堆makefile

.vcproj在哪邊?

每次下好了網上的各種庫

我的心裡就變得很亂

不懂啥是cmake啥是ninja,

只好點de~le~te哦!

不明白不明白, 構建咋他媽的那麼難.

捨不得這個庫

可我是一生一世錯誤滿眼

我明白我明白Windows不入你們法眼

或許我會有一天實現 可那是用了Homebrew.

還記得多年前楞在窗口前,

看著boost慢慢構建,

一個年輕的碼農見到bjam,

你定能想像那瞬間.

當你編譯的時刻我等著你

你卻說又找不到符號.

這種操蛋的心情讓我每天憂愁

只好就De~le~te哦!

不明白不明白, 編譯咋他媽的那麼難.

你要鏈,這個庫

要選好幾十個靜態庫!

我明白我明白Windows不入你們法眼

或許我會有一天實現 可那是用了RPM.


與大部分答主意見一致:vcpkg解決了Windows下常用依賴包的管理問題。

這幾乎和各大Linux發行版都早已經解決的問題(而且做得更好),但也是不小的進步了。

這篇回答借vcpkg的出現,分析對比一下現有不同平台的C++包管理工具,最後說說vcpkg扮演的角色。

我們團隊主要使用Conan作為跨平台的包管理工具(對Linux下也用,因為它對私有包更加友好),但在Win下,也借用了不少vcpkg編好的庫打到conan包中(repo)

先簡介一下vcpkg的功能,它使用CMake腳本定義了一系列包下載、patch、構建規則,原則上在框架內可以編寫任意C++源碼,最後將include/lib/dll收集起來,修改vs工程,達到引用依賴的目的。

對於一般開發(只引用現成依賴、開發上層程序),非常友好方便,只不過團隊開發需要每個人都來一份,似乎都要在本地編出來二進位,才可以繼續?這個有點花時間,略蛋疼一點(而conan解決了它。。)

在這裡我更想談談我對C++包管理流派的理解,可以幫助大家更好地理解vcpkg的特徵和定位。

二進位包管理有哪些辦法?

C++中庫依賴無非是頭文件、靜態庫和動態庫的引用,但這些東西從哪裡來,不同平台、系統都有不同的解決方案,甚至根據公司技術棧、產品形態(是否需要分發、是否跨平台),有各種各樣的變化。

首先二進位包管理的難題在於需求的多樣性:編譯選項多種多樣,runtime、編譯器版本各有所需而且互不兼容,說不定還要搞個版本管理。。。

上述問題對於跨平台語言不成問題,比如JavaScript的NPM,Java的Maven等,人家沒那麼多麻煩事,真正做到了一次編寫,到處使用。

而C++呢,一次編寫,到處編譯,還編譯不過。。

(捂臉流淚.gif)

那麼二進位包管理有什麼方式呢?我總結下來有以下四種(粗體字標識)

1. Linux自帶的包管理工具

Linux系統下往往使用發行版提供的軟體/包管理系統 (apt, yum之類),好處是已經預編譯好,有依賴樹,提供了大部分公共庫。這對於90%的用戶足矣,畢竟都是庫的使用者。

但這樣只能有啥用啥的包的最大的問題是:

  • 沒有自定義/私有包(改源代碼再編譯),要做還得搞一個apt源之類的,還沒版本管理
  • 如果一個包不在系統中,那編譯、安裝流程將很難做到統一和可重複。

沒有私有包管理,那麼就沒法做到公司內部共享公共庫和解耦合的目的了。

2. 顯式手工引用

這方法看起來好土,但理論上可以解決所有問題——不就是二進位庫引用嘛!

這種方式在windows下更加常見一些,因為不少庫是可以下載到win32平台的二進位的,但你怎麼用,庫沒有規定,我們只好手動引用了(在VS里配置各種include dir和lib dir,再把DLL拷貝過去。。。)

這些二進位庫往往放到SCM中,和代碼一起checkout下來,基本做到了無需額外配置的效果(雖然第一次配置起來實在麻煩)。

如果把這種方式再整理、抽象一下,就成了下面一種方式。

3. 代碼庫內帶二進位依賴

和上面手工引用不同的是,代碼庫在設計之初就考慮了二進位依賴的問題。這常見於公司級別的源碼管理。

比如公司有一個統一的SVN或Perforce repo(為什麼沒有git?下面會說到), 可以有一個目錄放所有第三依賴的源碼和編譯好的二進位文件。同樣的repo下會有不同項目的代碼,說明引用目錄,就可以共享依賴二進位啦。

開發一個項目時,只需要checkout項目源代碼和它指定的依賴的二進位即可。如果這個項目也是個庫,更新之後再編譯一遍,覆蓋約定的二進位文件即可,可以做到同步更新,依賴共享。

但以目錄文件方式存放依賴,繞不開編譯平台和選項的問題。如果你想保存二進位,就會出現這樣的目錄結構:

Library

+ Boost

+ Windows

+ VS2015

+ x86

- Release

- Debug

+ win64

- Release

- Debug

如果再跨平台呢?不同平台的不同CPU呢(arm什麼的)?有個項目想要不同的編譯選項呢?排列組合有一萬種(我選擇死亡!)

這種統一代碼庫實在強勢,會抹殺依賴包個性化要求,有時候會降低開發效率的。

至於為什麼git不常見,是因為 git 設計目標是一個分散式代碼庫,要求解耦合,不能一個repo里放一堆小項目(請用submodule或者其他依賴管理去),更別說git需要把整個repo checkout下來,而svn/p4都可以按文件夾操作。

所以git和github誕生了npm這樣與repo深度結合的包管理系統,更加深入地影響了docker, conan之類的命名系統(都是將 用戶名/包名 作為索引)。

其實對於不同平台和不同編譯選項的二進位依賴問題,Google的統一代碼庫帶來了另外一種更巧妙的解決思路:

我還是不同目錄存放不同依賴的源碼,但不顯式地保存它們的二進位文件。

這樣源碼管理就得相當簡單,只有代碼了。那二進位怎麼辦?把它緩存起來!

因為Google的依賴和編譯系統 (依賴管理Blaze, 其開源版是Bazel,編譯系統Forge)是中心化和雲計算化的(雲端編譯,不在本地),就帶來了緩存編譯好的target的可能。緩存系統只要記下有一個用戶曾經在某一個Changlist/commit用某編譯選項編譯過某target,就會把它的編譯結果緩存起來,如果其他人再用,那直接用好了。

再加上Blaze有很好的增量編譯和檢測改動的機制,一個庫如果不經常變化,即使有很多用戶引用,也不會多次編譯。這就相當於用一個額外的系統解決了目錄管理編譯項目的頭疼問題。(計算機的任何問題都可以通過增加一個抽象層來解決

但只有Google這樣的公司,才有動力和精力去管理編譯緩存,做一個屏蔽一切細節的依賴管理系統。

但對於小公司呢?就沒個簡單辦法么?

確實沒有,跨平台語言玩爛的東西,對於native語言,真是沒撤(連go依賴都要源碼依賴,然後一起編譯呢,好在go編譯得快啊)。不過現在仍然有一些創新性做法,比如下面這個。

4. 分散式源碼管理+集中式依賴管理

現在使用 git 的團隊越來越多,一個項目一個repo的設計在靈活性和性能上有了本質提升。

但git對大文件管理的弱勢也導致其依賴管理十分痛苦。

曾經我們設計了這樣的方式,把二進位包使用submodule的方式進行引用,用啥引啥。但submodule也要下載歷史記錄的啊!我只想要現在版本的二進位,結果你還要下載一堆歷史版本?像git這種無法只下載特定目錄和特定版本的系統,必然不能套用統一代碼庫的思路。(別說--depth,你看歷史不還得全弄下來?)

git這種分散式SCM還是適合將二進位放在另外的地方,那就是集中式依賴管理系統。

類似於增加一層抽象的方式, 如果可以把二進位按(包名,平台,版本,編譯選項)這樣的方式,在伺服器上傳並索引,使用時各取所需,豈不完美?

嗯,http://Conan.io就是這樣設計思想下的產物,只是包構建過程有些複雜,把C++/CMake和包管理混在一起,難度也是有一些的。

當然任何人都可以寫出這樣的小腳本,自動從自己的伺服器下載需要的包,然後放到約定的地方。這樣的方式可以解決任意規模團隊對依賴的需求——既可以共享公共庫,又可以定製二進位包。

那VCPKG是什麼樣的?

我認為vcpkg是基礎是實現Linux包管理,提供最基礎的公共庫依賴。

但它已經預留了編譯選項,比如現在的x86-windows-static之類的(還有windows?野心不小啊!),已經在平台和鏈接類型上提供了自由度,理論上可以再增加配置選項,實現編譯的定製化,再加上可以自己開發庫的編譯腳本和patch,就可以實現自定義二進位包啦。

當然最後就缺一個二進位包伺服器,實現共享二進位,大大提升開發效率!

我覺得微軟還沒利用起來的是VS,如果VS工程實現了和VCPKG的深度結合,比如從指定伺服器下載指定的二進位(可以弄一個配置文件,聲明式地指定,像npm的package.json一樣),自動配置到項目中,豈不是完美?(感覺這都是conan帶給我的思想)

當然,一個功能強大的系統未必會有人用,畢竟沒多少人都需要這些特性。也許做一個滿足80%用戶需求的產品,性價比更高呢?

水平有限,歡迎指正!!


如果沒有理解錯的話那應該是好事吧,至少不需要為安裝庫煩神了?我參與的一個項目中,有這樣的需求:在VS中將項目中所有文件上傳至伺服器,之後在別的地方下載下來要能用。由於這部分不是我做的,所以問題都是聽別人說的,據說第三方庫在下載下來的時候會遇到一些問題,需要重新配置。可能需要研究一段時間來看看微軟這個項目。。。


挺好用的,因為整套東西是註冊給msbuild的,所以會在build的時候自動查找相關的包來添加編譯依賴項,同時vs也能通過讀取msbuild的target來識別到已經安裝的包,提供智能提示


在五六年前,我大一第一次用 Ogre 引擎的時候,是這麼寫 C++ 的。

一. 先下載 Ogre 引擎的依賴包 vcproject,編譯一遍得到一堆 dll。

二. 把第一步 dll 和 依賴包頭文件扔到 Ogre 代碼目錄里,用 Cmake 生成 vs 項目,再跑一次編譯,得到 ogre 的 dll 庫。

三. 然後你就得到了一堆 dll 和一堆頭文件,新建一個 vs 項目引入他們,然後你就可以用他們寫 3D 遊戲啦。

四. 如果你需要整合 cegui 的話,以上步驟再來一次。

當然,官網也有幾個特定版本的已經打包好的 Ogre vs 項目可以下,但是版本落後很多,就沒用了。

真不知道當時我是怎麼找到正確方法的……

現在都是在 linux 下寫 C++,舒心很多。都很久沒玩 Windows 了,當然 VS 是個好東西,如果有 vcpkg 可以用的話,還是可以試試,在編程中,有一個靠譜的包管理真的是一個無比重要的部分。


好用到炸。


先吐槽一下:終於開始做Linux各個發行版自古以來就有的東西了。

不過比起大部分的Linux包管理器,vcpkg據說能比較容易地安裝同一個包的不同版本,這算是個很大的優勢。我用過的的Linux包管理器都不能做到這個,除非源管理者將不同版本的軟體視作不同的軟體,比如libpng12和libpng16、Gtk2和Gtk3。


約的妹子是開情趣用品店的,差不多是這個感覺


想法挺好的,VC專用包管理器。還沒來得及體驗,只是簡單讀了一下文檔,但是就目前來說,比起來Nuget和Paket還有差距。Windows下的C++包/庫管理一直都很麻煩,但是說到底也就是頭文件+Static Library/Dynamic Modules+CRT運行時庫+Platform+Debug/Release 幾個維度的混合矩陣。

目前很流行的就是Nuget/Paket打包native代碼。

NuGet Gallery | Home社區完善,package也很豐富。

比如: SQLite.Native 3.12.3

比如我自己打的一個:potto.v141.dynamic 1.0.0.28

nueget也自帶缺點,所以paket作為基於nugget包的一個新工具更受歡迎。

What is Paket?

應該說目前國內在C++工程項目中很少有人使用paket吧,畢竟比較新。但是國內人的優勢就是,什麼問題都能吃的很透,雖然我不用包管理,但是我能把一個第三方庫擼的有條不紊。這也是老程序員和新一代程序員的差別,包管理用的很l6,但是對靜態庫/動態庫一無所知,對鏈接和CRT運行時庫也一無所知,也無法給別人提供一個可用的自己的庫/包,缺乏這種知識的人在項目架構,模塊劃分方面將會很難有所進步。


當然是重新安裝VS2017了ヽ(??ω??)?

自從重裝系統後就只裝了個2013日常湊合用→_→

現在正在安裝→_→

上次我不是問了個有關oracle oci/occi驅動的問題嘛,被輪子哥翻牌子了ヽ(??ω??)?

當然是要支持一波微軟了。

emmmm裝一個cpprestsdk花了三個小時,中間好像還迷之裝了個boost。大概意味著我電腦不用再裝(編譯)boost了

然後就有了boost的庫

再上一個lua的

(缺點:VS2013果然不能支持23333)


我就說一件事情,OSX和Linux一百年前就有了軟體包管理。

應該算是個進步吧。


一直關注 看源碼的意思可能有計劃跨平台 cmake 系的勝利


你們這是在降低C++的門檻啊。。。。

雖然我很喜歡


如果C++再把modules搞進來,終於就可以接近Javascript(Node)和TypeScript了。然而現在還是有些笨重,必須要和cmake一起搞。

希望將來有一天,C++程序員能忘記平台和編譯器配置,一個build自動解決所有問題。


可惜很多時候都用不了,能用的包很久以前就解壓到MSVC包含目錄和庫目錄下了,希望能讓大家都能上傳自己的庫,方便尋找小眾庫。

此外這玩意有個BUG(可能不算是BUG),更新VS有時候會更新編譯器,更新完編譯器之前安裝的包可能就要重新安裝了


我覺得吧,cmake的hash演算法可能有問題 我反饋了一個issue我也無視了。

有一個明顯的bug是,有些庫沒有x86版本,裝一半才報失敗……

潔癖似的要求cmake git最新……

其餘的還好,早期版本只支持2015我就不提了,過去式了。


還在為include找不到頭文件而煩惱嗎?還在為LINK找不到符號而憂愁嗎?vcpkg,你值得擁有。

windows開發者歡天喜地,終於擁有了一個十多年前的Linux的標配。

擁抱開源的微軟不是能隨便罵的好微軟…


具有Anaconda的既視感,方便!


推薦閱讀:

你見過哪些令人瞠目結舌的php代碼技巧?
如何評價《Windows 10 development for beginners》的翻譯工作?
有沒有用漢字設計的編程語言,或者漢化一種常見的編程語言?
MATLAB 到底有多厲害?

TAG:互聯網 | 編程 | CC | vcpkg |