傳統的 Linux 軟件包格式不適合現代應用

語言: CN / TW / HK

圖片來源:來自 Unsplash 的 Kelli McClintock

我多次遇到用户抱怨 LTS 和穩定版的應用軟件包有問題,但又聲稱開發版從來沒有發生過這種事情。然而,以我在軟件包技術方面的經驗和知識,我不能不強調,這是不對的。

發行模式不是問題的根源所在,根本的問題是傳統的軟件包格式不適合現代的圖形應用,不管是什麼發行版。那麼像 Nix 和 Flatpak 這樣的格式是如何解決這些基本問題的?有趣的是,大多數服務器確實利用了容器化(即 Docker),因為它提高了可重複性並增強了可維護性。我們可以從中得到啟發,採用一個適用於 Linux 桌面的類似標準。

免責聲明

  1. “傳統軟件包”是指使用包管理器發佈的圖形應用程序,而不使用容器,如​ ​apt​ ​​、​ ​dnf​ ​​、​ ​pacman​ ​ 等。
  2. “發行模式”是指發行過程,如長期支持版(LTS)、穩定版和開發版等。
  3. “類似的應用程序”是指兩個在技術上真正相似的應用程序,如​ ​Visual Studio Code​ ​​ 和​ ​Code - OSS​ ​。
  4. 在這些例子中,我將使用 Arch Linux 作為參考。然而,這些行為與那些大量採用傳統軟件包格式的發行版是一致的。
  5. Nix 不使用容器,它也不是一種容器格式。但為了簡單起見,我暫時把它稱為一種容器格式。

根本問題

圖片來源:來自 Unsplash 的 Jackson Simmer

大多數(或許不是全部)大量採用傳統軟件包格式的發行版都有這個共同的問題:它們都沒有利用容器或其他方便的方法來分離依賴關係。用通俗的話説,容器是一個盒子,我們可以把東西放在裏面,在不影響主系統(主機)的情況下單獨使用它們。

容器通常不會影響“盒子”外的任何東西。並且它們是可移植的,因為它們可以安裝在其他發行版上,同時提供一致的體驗。利用容器的包管理器會將每個軟件包安裝在不同的容器中,這提供了一個額外的安全層。這給了開發者更多的控制權和靈活性,他們可以決定在軟件包內捆綁什麼。

傳統的軟件包格式產生了一些問題,比如依賴性和包的衝突,這些問題通常需要解決,而不同的發行版有不同的解決辦法。

依賴性和軟件包的衝突

如果我們試圖安裝 ​ ​Visual Studio Code​ ​​(​ ​visual-studio-code-bin​ ​​),而 ​ ​Code - OSS​ ​​(​ ​code​ ​) 已經安裝在 Arch Linux 上,我們會遇到這個問題:

$ paru -S visual-studio-code-bin
    [...]
    :: Conflicts found:
        visual-studio-code-bin: code  
    :: Conflicting packages will have to be confirmed manually
    Aur (1)                     Old Version  New Version  Make Only
    aur/visual-studio-code-bin               1.70.1-1     No

這就是所謂的軟件包衝突,即兩個或多個軟件包不能共存。在這種情況下,我們不能同時安裝 Visual Studio Code 和 Code - OSS。

當兩個應用程序或軟件包提供相同的文件,具有相同的名稱,並被放置在同一目錄下,那麼它們實際上是不能共存的,因為這些文件會發生衝突。在這個例子中,Visual Studio Code 和 Code - OSS 都提供了一個名為 ​ ​code​ ​​ 的文件,它們都被放在 ​ ​/usr/bin​ ​​ 中。Visual Studio Code 提供的 ​ ​code​ ​​ 文件用於啟動 Visual Studio Code,而 Code - OSS 的 ​ ​code​ ​ 文件則用於啟動 Code - OSS。 雖然這個例子只展示了 Visual Studio Code 和 Code - OSS,但這種情況經常發生在不同的應用程序、庫和其他軟件中。

無法選擇依賴項

圖片來源:來自 Unsplash 的 Priscilla Du Preez

傳統軟件包格式的最大問題之一是,打包者不能選擇依賴項。

例如,如果一個應用程序最近更新,需要依賴版本 1 的程序 A,但發行版只提供了版本 0.9 的程序 A,那麼對於升級該應用程序來説就不太理想,因為發行版無法滿足要求。這意味着打包者將不得不暫緩打包,直到該發行版發佈新的依賴項,或者採用變通的方法。

同樣,如果一個應用程序需要依賴 0.8.1 版本的程序 A,但發行版卻只提供了 0.9 版本的程序 A,那麼這個應用程序就會表現失常,甚至完全不能運行。

帶補丁的庫和編譯配置

為了擴展,一些應用程序需要帶補丁的庫或額外的編譯配置才能正常運行。例如,OBS Studio 需要一個 ​ ​打了補丁的 FFmpeg​ ​ 來與 OBS Studio 更好地整合。

在傳統的軟件包格式下,一次只能安裝一個依賴項的變體。如果發行版提供的是未打過補丁的 FFmpeg,那麼就沒有辦法安裝打過補丁的 FFmpeg,除非打包者能解決這個問題。如果安裝了打過補丁的 FFmpeg,但另一個程序高度依賴未打過補丁的 FFmpeg、打過其他補丁的 FFmpeg、內置或刪除了其他功能的 FFmpeg,那麼其他程序就會出現 bug。

現代應用程序本質上是脆弱的。依賴關係樹中的一個小錯誤或不一致,就會導致應用程序的 bug,使用户體驗惡化,甚至會讓人覺得是應用程序的問題,而不是軟件包本身的問題,這就會妨礙應用程序的聲譽。

變通方法

讓我們看看目前開發者用來打包應用程序的變通方法:

  1. 第一種解決方法是在不同的目錄中安裝依賴庫。例如,Electron 是一個巨大的框架,開發者用它來構建應用程序,然後將它們捆綁起來。然而,基於 Electron 的應用程序是不同的,因為它們是建立在不同版本的 Electron 之上的。Discord 捆綁了 Electron 13,而 Element 捆綁了 Electron 19。對於 Arch Linux 上的 Electron 打包,某些目錄需要安裝在​ ​/opt/APPLICATION_NAME​ ​​ 中,所以這些 Electron 版本​ ​不會相互衝突​ ​。
  2. 第二種解決方法是篡改應用程序。例如,給應用程序打上補丁,使其在沒有某些依賴庫或功能的情況下編譯,這可以使應用程序成功編譯,但不能保證該應用程序能夠啟動或按預期工作。
  3. 第三種解決方法是在編譯應用程序時禁用許多編譯選項,這也可能禁用一些功能。例如,在 Arch Linux 上,OBS Studio 在編譯時禁用了許多基本功能,這​ ​導致了不合格的體驗​ ​。

這些解決方法因人而異,有些會限制應用程序的功能,有些會引入穩定性問題等等。

不一致的體驗

圖片來源:來自 Unsplash 的 alevision.co

雖然這些技術限制在整個傳統軟件包格式中是一致的,但用户體驗往往不是這樣。由於軟件包的發佈方式,發行模式與傳統軟件包格式相結合會影響用户體驗。

一些發行版,如 Arch Linux,接近於開發版,因此有最新版本的軟件包。然而 Debian 和 Ubuntu LTS 是 LTS 長期支持版,所以它們的很多軟件包都落後幾個版本。同時,Fedora Linux 和 Ubuntu 穩定版處於 Debian / Ubuntu LTS 和 Arch Linux 之間。

一些軟件包格式喜歡儘可能少地給軟件包打補丁,以保持它們最接近原版;而另一些格式打補丁是為了增加更多的功能,使用舊庫或進行其他類型的更改,以改善用户體驗。一些格式喜歡使軟件更加輕量化;而另一些格式更喜歡儘可能地添加更多內置功能。軟件包有各種各樣的習慣和偏好。

正如我們所看到的,一個應用程序在不同的發行版中的構建方式非常不同。此外,不同的發行版的依賴關係也是不同的。傳統軟件包格式的許多技術限制需要根據發行模式和打包策略採取不同的解決方法。這些微小的變化往往給用户帶來不完整的、不合格的體驗和錯誤的印象。一些應用程序可能在某些發行版上運行得更好,但在其他發行版上運行得很差,而其他一些應用程序則運行得更好。即使一個應用程序在每個發行版上的構建方式不同,但其名稱和品牌卻保持原樣,給用户留下錯誤的印象。

解決方案

圖片來源:來自 Unsplash 的 Riccardo Annandale

如上所述,解決這些問題的方法是使用容器。

容器被設計用來分離系統的幾個方面。通過使用容器,打包者可以挑選依賴項而不受主機上的庫限制。因此,打包者可以發佈最新的、功能完整的軟件包,同時保持發行的穩定性。

這一點非常重要,因為這些容器格式可以將應用程序和發行版發揮出最大的作用,而不會對系統造成破壞性的影響。

Nix 和 Flatpak

​Nix​ ​​ 是一個跨平台的包管理器,可以在類 Unix 操作系統中運行,如 Linux 發行版、BSD 和 macOS。Nix 有幾個 ​ ​通道​ ​(分支)供用户使用。

另一方面,​ ​Flatpak​ ​ 是一個用於 Linux 桌面的通用軟件包格式,它也利用容器,但另外還有沙盒來隔離它們。它旨在以後可以供普通人使用,並被設計為與軟件商店(如 GNOME “軟件Software” 和 KDE “發現Discover)集成。換句話説,Flatpak 更像是發行版的一個擴展,而不是一個軟件包格式的替代品,因為它的設計初衷不是為了取代系統包管理器。

如果使用 NixOS 等發行版,Nix 也可以作為一種擴展或單獨使用。

類似的應用

Nix 和 Flatpak 解決了傳統軟件包格式的許多基本問題。由於應用程序的分離,這些格式可以安裝類似的應用程序,如 Visual Studio Code 和 Code - OSS,而不會衝突。

多個版本

Nix 和 Flatpak 可以安裝同一個應用程序的多個版本。使用 Nix,我可以從 ​ ​nixpkgs-stable​ ​​(LTS)安裝應用程序,同時也可以從 ​ ​nixpkgs-unstable​ ​(開發版)安裝同一個應用程序。

同樣地,使用 Flatpak,我可以同時從 ​ ​stable​ ​​ 和 ​ ​beta​ ​ 分支安裝應用程序。我可以從更多的途徑和分支繼續安裝同一個應用程序,而不會遇到衝突。

挑剔的依賴項

圖片來源:來自 Unsplash 的 Ish de loyola

此外,打包者可以將應用程序與不同變體的庫捆綁在一起,從而有機會啟用更多的構建選項,並使用打過補丁或特定版本的庫,從而為用户提供完整的體驗。

這意味着打包者可以將打了補丁的 FFmpeg 與 OBS Studio 捆綁在一起,只為了用在 OBS Studio

中。如果我在主機上安裝了普通的 FFmpeg,那麼 OBS Studio 的補丁 FFmpeg 就不會與主機的 FFmpeg 發生干擾或衝突。

各個發行版的環境都是一致的

如上所述,各發行版使用不同的補丁、構建選項和環境構建應用程序。這導致了應用程序的碎片化,每個應用程序的構建方式和工作方式往往不盡相同。由於

Nix 和 Flatpak 是為跨發行版運行而設計的,它們在每個發行版中為應用程序提供一致的環境,前提是發行版提供了 Nix 或

Flatpak 的支持版本。

缺點

就像所有事物一樣,Nix 和 Flatpak 不是完美的。由於最近在 Linux 桌面上容器技術得到了推崇,它們可能為許多應用程序提供了不尋常的環境。

Flatpak 不僅包含了應用程序,還對它們進行沙盒處理。Flatpak 的開發者已經實施了一個短期的變通方案,“在沙盒上打洞”,即所謂的靜態權限。他們正在開發適當的長期解決方案,稱為 ​ ​XDG 門户​ ​,以解決有關沙盒的許多問題,並使其像 Android 的安全模型一樣。

唯一的短期問題是,工具包、框架和應用程序必須採用這些標準。GTK 和 Qt 這樣的工具包集成了其中一些門户portal,但它們也需要時間來集成其他的門户。同時,許多其他的工具箱還沒有真正集成任何門户。

工具包、框架和應用程序採用這些新標準是一個時間問題,因為在 XDG 門户之前沒有任何適當的標準。應用程序可以直接訪問文件系統和 API,所以靜態權限保持這種 “標準”。

結論

傳統軟件包格式的根本問題是它沒有利用容器。許多圖形化的應用程序本質上是複雜的,需要非常具體的依賴關係才能按預期運行。許多發行版通過使用變通的方法在不同的環境中構建同一個應用程序,例如給應用程序打補丁或禁用某些構建選項。這導致了一個應用程序的不同變體、不一致的行為和不合格的用户體驗。

當然,發行版的維護者不可能在幾天內現實地重寫他們的包管理器並使用容器。這些重寫會破壞許多腳本、功能等,而且還需要很長時間才能投入生產環境。

我個人的建議是使用和推廣 Flatpak,因為它只是為了擴展現有的發行版,而不是取代它。打包者不必擔心打包應用程序,以及訴諸變通的問題,因為 Flatpak 已經在處理這些問題了。

作者 Hari Rana ​ ​最初發表於此博客​ ​。

Hari 是 Fedora 雜誌的 Fedora 編輯委員會的成員。他也是 Fedoea 質量保證(QA)的一員。Hari 希望通過推廣各種技術和幫助需要幫助的人,為 Linux 桌面的採用作出貢獻。

本文所表達的觀點和意見是作者本人的,並不代表我們的觀點。