C++有沒有像python-pip/nodejs-npm/ruby-gem一樣的包管理工具?

RT


此問題相當有價值,我認為我會持續更新。已經將不嚴謹的「二進位」和「源代碼」更換為更為嚴謹的描述"as is"和"source"。

我歡迎各類程序員和我一起探討這個問題。

先說結論:c/c++和其他語言不同,要管理c/c++的包,你需要管理的不是"as is",而是"source"寫程序的人需要的包管理器,和管理系統的人需要的包管理器是不一樣的

npm/apt/yum之類的包管理器的特點主要是"as is",也就是下載下來就可以用。這樣子對於C++來說是非常非常難以做到的,比如:

1. Windows下的MT/MTd/MD/MDd我無法解決。換言之,如果要通用,Windows 32bit就要至少提供四套binary。更加煩的是從Visual Studio 2012開始還需要指定XP兼容性。此外Debug Info指向的cpp文件是絕對路徑,也就是換個電腦你只能手動指定源文件的位置。

2. Linux下的binary也有區別,舉個例子,有RTTI和沒有RTTI的代碼是沒法鏈接在一起的。

如果我需要要做到"as is",我不單單需要為不同的系統、配置提供不同的binary,還需要為一些編譯選項提供不同的binary。於是一個版本,我將提供幾乎數不清的binary,因為不同的配置、系統、編譯選項之間還可以做笛卡爾積。更何況,只有binary並不能調試,Debug Info通常佔用的空間會比binary更加巨大,常常可以做到幾個G,單單是壓縮這些Debug Info就會耗費幾十分鐘的時間,對於包發布者來說,是個巨大的壓力。

此外,C++由於其複雜的歷史原因,造成了複雜的依賴項,有的依賴perl,有的依賴於python,。這些項目的歷史悠久,有無數數不清的坑。想要做到"Modern",不是不想,而是實在是做不到。比如LLVM和Clang,已經算是這些項目中非常優秀的項目了,歷史包袱也不是非常多,代碼非常優秀,模塊化,可是做了不知道多久還沒有徹底從Autotools遷移到CMake。這些複雜的依賴項是沒有辦法說直接"as is"使用的,因為他們的目錄的位置並不是遵循一個統一的標準,如果說有一個統一的標準,那麼C++的包管理器會好做很多。

同樣的問題,出現在同樣歷史悠久的PHP身上。PHP本身有非常多的坑,這個就不細說了,而Composer花費了近10年時間才逐漸將PHP變成了現在這個Modern的樣子(當然還有PHP自己的努力)。

有C++包管理器嘗試說要求每個添加進庫的項目都必須是符合規定的,例如,比如使用CMake。很不幸,目前C++領域最多人用的包管理器是這個思路。CMake非常優秀,然而正如我上面所說。但逐一糾正每個包,幾乎是不可能的。我認為更實際的做法是,為每個包寫一個編譯配置,只需要編譯好的頭文件和二進位符合規範即可。我們必須要兼顧到C/C++悠久的歷史所導致的無數的編譯環境,例如autotools, CMake, gyp, ninjia。

最近很火的Rust的包管理器Cargo,所使用的方法,如我所使用的一樣,是將源代碼包"as is"下載下來,在編譯的時候,優先編譯dependencies。我認為這是比較符合實際的做法,它避免了我所上面列舉的一些問題:

1. Binary的規則太細並不互相兼容:重新編譯可以保證編譯選項是兼容的。

2. 所依賴的包太多歷史包袱,無法兼容新的標準:即時編譯以後將編譯好的二進位和文件按照統一的規範存儲到新的位置。

Rust的Cargo的一個問題是要求必須使用Rust的腳本編譯,而不是Shell。這樣子對於我們來說也許是壞消息。但對於Rust來說,可以避免其倉庫被海量的C++代碼庫湮滅,也許是幸運。

就算是如我上面所說,還會有一些新的問題:

1. 編譯的時間太久:於是可以使用緩存的方法,將一個依賴項的某一個配置緩存起來。這對於其他語言來說可能不是剛需,但對於C++來說,簡直太需要了。

2. 為每個包寫符合規範的配置選項,仍然會是一個很大的工作量。這一點我相信靠我們的努力,未來會做得更好。


有,CPM。

但是應該沒有人用。


C/C++ 的歷史上並沒有出現平台統一的代碼復用管理的需要。因此不會出現類似 npm 一樣一統天下的管理器。

編譯型的語言是平台相關的,做解釋型語言型的包管理, 有些不切實際, 大多數的個人/小組織的庫,都不可能給每個平台編寫一套代碼。 正常的情況是 一般搞 windows 的寫 windows, Linux的寫 Linux。

因此 C/C++ 一般是各個開發環境 持有各自的復用管理。

不僅僅是用於編譯與鏈接階段的 apt-get 或者 vs 的 nuget .

包括動態鏈接階段的 DLL 其實也是一種代碼復用管理,甚至當年微軟有些令人不舒適的activeX方案也算。(其實想想微軟對 dll 的版本管理設計多多少少有些欠考慮)

不過針對 跨平台編譯配置倒是有各種統一的解決方案,較新的類似 gyp 一類。


linux的包管理工具,比如ubuntu 的apt-get , centos的yum, opensuse的zypper, 其實很大意義上就是c/c++的包管理工具。各種lib header dev包可以通過其安裝的


C++ 最靠譜的做法就是自己建一個 deps 目錄把依賴的庫的源代碼直接放裡面。。。


補充一下,用Visual Studio的話,有NuGet。


apt-get install libxxx

yum install libxxx

pip, npm, gem 都是給解釋語言用的. C/C++ 的都是二進位發包.所以直接用 apt-get 來管理了.

頭文件也是這樣管理的, apt-get install libxxx-dev 就可以了.

apt-get 也可以管理 c/c++ 的源代碼


C/C++ 這種太過於平台和編譯器相關的語言其實很難出現語言級別的包管理器這種東西,但是正因為如此在各個平台上都會有相應的二進位包管理器(也有非二進位程序),比如 linux 的 apt-get, deb, yum,windows 10上的package manager等等

像npm, pip這些都是與平台無關的,它們的基礎其實是相應語言的虛擬機/解釋器/運行時等機制,而這些是跨平台的


包管理器是一個具有「偽價值」的工具,不管它管理的是源文件還是二進位文件

對於認真考慮程序可靠性的人來說,所依賴的第三方庫的版本是高度敏感的。版本號稍許不同,就意味著有不同的坑要趟。不問版本任由一個「管理器」來幫你下載和配置簡直就是閉著眼睛寫程序。而且,這種「包管理器」產生了複雜的源代碼依賴也會造成include/lib目錄管理的不清不楚和混亂

一個不能清清楚楚、明明白白管理自己的C/C++項目的依賴,和各種編譯目錄(include/lib)的程序員一定是初級C/C++程序員


最近發現一個c++包管理工具: Conan.

github:GitHub - conan-io/conan: Conan.io

感覺是題主要找的東西。


首先c和c++的編譯器得像python、ruby一樣由同一個組織開發。這樣跨平台就不再是問題了,然後包管理器估計很快就出來了。


c++二進位分發會很麻煩。就算是源代碼,如果不是精心維護的話在不同平台也會有各種問題。

如果只是希望在自己團隊內方便的管理各種輪子,可以考慮:bazel(blaze) / blade


要用庫的源代碼拿過來,放在project directory恰當的位置中。。也有Maven nar package manager, 但是似乎用的人比較少。。


有還是有的,比如CPM,比如biicode。

說到biicode,這貨看起來順風順水,travis CI也靠它來解決c++的依賴關係。貌似是投資斷了,這傢伙的公司很快就要關張了。


推薦閱讀:

TAG:軟體工程 | CC | 包管理器 |