再見 RPM/DEB/TAR!下一代全平臺安裝程序來了!

AppImage 是一種在 Linux 系統中用於分發便攜式軟件,且不須要超級用戶權限來安裝它們的格式。它還容許 Linux 的上游開發者來分發他們的程序而不用考慮不一樣 Linux 發行版間的區別。AppImage 的核心思想是一個文件即一個應用程序,每一個 AppImage 都包含應用程序以及應用程序運行所需的全部文件。html

圖片圖片

AppImage 工具介紹

像 Linux 自己同樣,AppImageKit 是開源的。java

圖片適用於全部至關現代的 Linux 桌面發行版。node

簡單

AppImage 的核心思想是:一個應用程序 = 一個文件。每一個 AppImage 都包含應用程序以及應用程序運行所需的全部文件。換句話說,除了操做系統自己的基礎組件,Appimage 不須要依賴包便可運行。python

可靠

AppImage 格式是上游應用打包的理想選擇,這意味着你能夠直接從開發者那裏獲取軟件,而不須要任何中間步驟,這徹底符合開發者意圖。很是迅速。linux

快速

AppImage 應用能夠直接下載而且運行,無需安裝,而且不須要 root 權限。git

AppImage 工具對比

對比多種軟件格式的優點和劣勢!github

與 deb 和 rpm 對比

  • 優點
  • AppImage 格式的應用可跨發行版運行,傳統格式不可用或比較難。
  • AppImage 格式不須要安裝便可運行,可在 $HOME 分區運行,節省更分區空間。
  • AppImage 無需 root 權限,告別輸入密碼時代。
  • AppImage 包含應用依賴,可不受軟件倉庫制約,快速分發應用版本且不破壞系統依賴。
  • AppImage 提供多種打包方式,便可手動打包,也可腳本打包。
  • 劣勢
  • AppImage 格式會形成庫的冗餘且體積偏大,戲稱爲「系統安裝了一萬個 libc」。
  • AppImage 不受檢查,若是有來源不明的人打包,可能會帶來安全風險。
  • 運行一箇舊的 AppImage 軟件所帶的依舊是舊版本的依賴庫,可能會帶來風險。

與 snap 和 flatpak 對比

  • 優點
  • AppImage 無需運行時,安裝 snap 和 flatpak 軟件安裝其運行時。
  • AppImage 格式不須要安裝便可運行,可在 $HOME 分區運行,節省更分區空間。
  • AppImage 無需 root 權限,告別輸入密碼時代。
  • AppImage 不須要軟件倉庫,固然也能夠有,易於傳播。
  • AppImage 對華人友好,包括官方網站和官方文檔都已經有對應的中文支持。
  • 劣勢
  • 沒有沙箱機制。
  • 沒有商業公司支持,致使開發了十多年才具備影響力。
  • 對某些定製化安裝的發行版不友好,好比 gentoo、archlinux 等。

AppImage 目錄結構

須要注意 AppImage 所需的文件以及目錄結構!web

使用 AppImage 系列工具的前提就是,你所編寫的程序項目或者工具依賴格式必須符合 AppDir 的目錄要求,大體目錄結構以下所示。shell

AppDir
└── AppRun
└── your_app.desktop
└── your_app.png
└── usr
    ├── bin
    │   └── your_app
    ├── lib
    └── share
        ├── applications
        │   └── your_app.desktop
        └── icons
            └── <theme>
                └── <resolution>
                    └── your_app.png
  • AppRun 文件
  • 必需要有
  • 啓動主負載應用程序
  • 其中 AppRun 文件是程序的啓動入口點文件,須要有可執行權限。
  • 在 AppImageKit 項目中提供了一個 AppRun.c 的實現,但咱們可使用語言,好比 shell 的實現,也能夠僅使用與主要可執行文件的符號連接。
  • your_app.desktop 文件
  • 必需要有
  • 相似於 Windows 系統的快捷方式,即雙擊便可運行。
  • 咱們這裏的 [your_app].desktop 文件將顯示在桌面上,可以使用連接的方式存在。
  • 編寫的格式能夠參考:https://specifications.freede... spec/latest/ar01s06.html 這個網站,最簡單的方法就是找一個改吧改吧。
[Desktop Entry]
Name=Hypnos
Exec=hypnos %F
Icon=hypnos
Type=Application
Categories=Audio;AudioVideo;
Comment=Music Player and Library
MimeType=inode/directory;audio/flac;
Name[en]=Hypnos
Terminal=false
StartupNotify=true
NoDisplay=false
  • your_app.png 文件
  • 非必須
  • 提供程序軟件包的桌面顯示圖案。
  • Version 文件
  • 非必須
  • 用於顯示程序軟件包所對應的版本信息。

appimagetool 命令使用

介紹 AppImage 工具的使用格式和經常使用命令參數。ubuntu

打包命令使用

appimagetool 命令用於把現有的 AppDir 目錄生成一個 AppImage 程序。

Usage:
  appimagetool [OPTION...] SOURCE [DESTINATION] - Generate, extract, and inspect AppImages
Help Options:
  -h, --help                  Show help options
Application Options:
  -l, --list                  List files in SOURCE AppImage
  -u, --updateinformation     Embed update information STRING; if zsyncmake is installed, generate zsync file
  -g, --guess                 Guess update information based on Travis CI or GitLab environment variables
  --bintray-user              Bintray user name
  --bintray-repo              Bintray repository
  --version                   Show version number
  -v, --verbose               Produce verbose output
  -s, --sign                  Sign with gpg[2]
  --comp                      Squashfs compression
  -n, --no-appstream          Do not check AppStream metadata
  --exclude-file              Uses given file as exclude file for mksquashfs, in addition to .appimageignore.
  --runtime-file              Runtime file to use
  --sign-key                  Key ID to use for gpg[2] signatures
  --sign-args                 Extra arguments to use when signing with gpg

打包文件使用

若是咱們運行一個由 AppImageKit 工具構建的程序,那麼其會附加如下參數,對應不一樣的參數會提供一些額外的特性和功能。

# usage
./appimagetool-x86_64.AppImage some.AppDir

圖片

pkg2appimage 工具使用

pkg2appimage 工具適用於將 deb 格式的包變成 appimage 的獨立可執行文件!

若是已經有了對應的二進制文件,不論是 zip 歸檔文件、.deb 格式的文件仍是 ppa 源上的文件,咱們只須要編寫一個 .yml 格式的描述文件,而後使用 pkg2appimage 工具來運行它,就會幫助咱們轉換生成一個 AppImage 的獨立文件,是否是很是簡單呢?yml 描述文件告訴 pkg2appimage 從哪裏得到所須要的內容,以及如何將它們轉換爲 AppImage。

# 執行方式
$ bash -ex ./pkg2appimage recipes/XXX.yml

若是你只是看到了簡答,那麼你就太年輕了,你不知道這個 yml 格式的配置文件到底有多糟心。真的,看了官方文檔中的配置文件介紹,以及對於官方倉庫的示例軟件對於 yml,內心有些懵逼。不過,等多看幾回以後,就會發現仍是不難寫的,只是須要咱們再出現錯誤的時候,可以及時調整配置文件,就能夠正常打出咱們須要的獨立文件。

下面咱們就一塊兒看下,yml 文件的編寫內容吧!正如咱們所看到的那樣,.yml 文件由三個部分組成,分別是主體部分、依賴部分和腳本部分。

app: zstd        # 軟件名稱
binpatch: true   # chdir()
overwrite: true  # union file system
ingredients:     # 依賴關係;包的內容從哪裏來
  dist: bionic
  package: zstd
  sources:
    - deb http://archive.ubuntu.com/ubuntu/ bionic main universe
script:
  - cat > ./zstd.desktop  <<EOF
  - [Desktop Entry]
  - Type=Application
  - Terminal=true
  - Name=zstd
  - Exec=zstd
  - Icon=transmission-tray-icon.png
  - Categories=Development;
  - EOF
  - cat > ./AppRun <<EOF
  - #!/bin/sh
  - HERE=$(dirname $(readlink -f "${0}"))
  - export LD_LIBRARY_PATH="${HERE}"/usr/lib:$PATH
  - "${HERE}"/usr/bin/zstd $@
  - EOF
  - chmod a+x ./AppRun
# 執行以下命令便可生成zstd的獨立程序
$ pkg2appimage ./zstd-appimage.yml
  • The overall section
  • 必須存在
  • 包含應用程序的名稱
  • 該名稱必須與主入口文件的包名稱匹配
app: zstd
  • The ingredients section
  • 必須存在
  • 描述如何獲取進入 AppImage 的二進制內容
  • 可包含 zip 歸檔文件、.deb 格式的文件仍是 ppa 源上的文件
# Using ingredients from a binary archive
ingredients:
  script:
    - DLD=$(wget -q "https://api.github.com/repos/atom/atom/releases/latest" -O - | grep -E "https.*atom-amd64.tar.gz" | cut -d'"' -f4)
    - wget -c $DLD
    - tar zxvf atom*tar.gz
# Using ingredients from a debian repository
ingredients:
  dist: xenial
  sources:
    - deb http://archive.ubuntu.com/ubuntu/ xenial main universe
    - deb http://download.opensuse.org/repositories/isv:/KDAB/xUbuntu_16.04/ /
# Using ingredients from an Ubuntu PPA
ingredients:
  dist: xenial
  sources:
    - deb http://us.archive.ubuntu.com/ubuntu/ xenial main universe
  ppas:
    - geany-dev/ppa
# Using local deb files
ingredients:
  dist: xenial
  sources:
    - deb http://us.archive.ubuntu.com/ubuntu/ xenial main universe
  debs:
    - /home/area42/kdenlive.deb
    - /home/area42/kdenlive/*
# Excluding certain packages
ingredients:
  dist: xenial
  packages:
    - multisystem
    - gksu
  sources:
    - deb http://us.archive.ubuntu.com/ubuntu/ xenial main universe
    - deb http://liveusb.info/multisystem/depot all main
  exclude:
    - qemu
    - qemu-kvm
    - cryptsetup
    - libwebkitgtk-3.0-0
    - dmsetup
# Pretending certain versions of dependencies being installed
ingredients:
  dist: xenial
  sources:
    - deb http://archive.ubuntu.com/ubuntu/ xenial main universe
  ppas:
    - otto-kesselgulasch/gimp-edge
  pretend:
    - libcups2 1.7.2-0ubuntu1
# Arbitrary scripts in the ingredients section
ingredients:
  script:
    - URL=$(wget -q https://www.fosshub.com/JabRef.html -O - | grep jar | cut -d '"' -f 10)
    - wget -c "$URL"
    - wget -c --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u66-b17/jre-8u66-linux-x64.tar.gz
  • The script section
  • 必須存在
  • 腳本部分可能包含將二進制內容轉換爲適合於生成 AppImage 的 AppDir 所需的任意 shell 命令
# The script section needs to copy ingredients into place
ingredients:
  dist: xenial
  sources:
    - deb http://archive.ubuntu.com/ubuntu/ xenial main universe
  script:
    - DLD=$(wget -q "https://github.com/feross/webtorrent-desktop/releases/" -O - | grep _amd64.deb | head -n 1 | cut -d '"' -f 2)
    - wget -c "https://github.com/$DLD"
script:
  - mv opt/webtorrent-desktop/* usr/bin/
  - sed -i -e 's|/opt/webtorrent-desktop/||g' webtorrent-desktop.desktop
# The script section needs to copy ingredients into place
ingredients:
  script:
    - wget -c "https://telegram.org/dl/desktop/linux" --trust-server-names
    - tar xf tsetup.*.tar.xz
script:
  - cp ../Telegram/Telegram ./usr/bin/telegram-desktop
# The script section needs to copy icon and .desktop file in place
script:
  - tar xf ../fritzing* -C usr/bin/ --strip 1
  - mv usr/bin/fritzing.desktop .
# The script section needs to copy icon and .desktop file in place
script:
  -  # Workaround for:
  -  # https://bugzilla.mozilla.org/show_bug.cgi?id=296568
  - cat > firefox.desktop <<EOF
  - [Desktop Entry]
  - Type=Application
  - Name=Firefox
  - Icon=firefox
  - Exec=firefox %u
  - Categories=GNOME;GTK;Network;WebBrowser;
  - MimeType=text/html;text/xml;application/xhtml+xml;
  - StartupNotify=true
  - EOF
# The script section needs to copy icon and .desktop file in place
script:
  - cp ./usr/share/applications/FBReader.desktop fbreader.desktop
  - sed -i -e 's|Exec=FBReader|Exec=fbreader|g' fbreader.desktop
  - sed -i -e 's|Name=.*|Name=FBReader|g' fbreader.desktop
  - sed -i -e 's|Icon=.*|Icon=fbreader|g' fbreader.desktop
  - mv usr/bin/FBReader usr/bin/fbreader
  - cp usr/share/pixmaps/FBReader.png fbreader.png

下面示例是 pip 這個工具的官方倉庫中給出的 yml 配置文件。

# Converting Python applications packaged with pip
app: mu.codewith.editor
ingredients:
  dist: xenial
  sources:
    - deb http://us.archive.ubuntu.com/ubuntu/ xenial xenial-updates xenial-security main universe
    - deb http://us.archive.ubuntu.com/ubuntu/ xenial-updates main universe
    - deb http://us.archive.ubuntu.com/ubuntu/ xenial-security main universe
  packages:
    - python3.4-venv
  script:
    - wget -c https://raw.githubusercontent.com/mu-editor/mu/master/conf/mu.codewith.editor.png
    - wget -c https://raw.githubusercontent.com/mu-editor/mu/master/conf/mu.appdata.xml
script:
  - cp ../mu.codewith.editor.png ./usr/share/icons/hicolor/256x256/
  - cp ../mu.codewith.editor.png .
  - mkdir -p usr/share/metainfo/ ; cp ../mu.appdata.xml usr/share/metainfo/
  - virtualenv --python=python3 usr
  - ./usr/bin/pip3 install mu-editor
  - cat > usr/share/applications/mu.codewith.editor.desktop <<EOF
  - [Desktop Entry]
  - Type=Application
  - Name=Mu
  - Comment=A Python editor for beginner programmers
  - Icon=mu.codewith.editor
  - Exec=python3 bin/mu-editor %F
  - Terminal=false
  - Categories=Application;Development;
  - Keywords=Python;Editor;microbit;micro:bit;
  - StartupWMClass=mu
  - MimeType=text/x-python3;text/x-python3;
  - EOF
  - cp usr/share/applications/mu.codewith.editor.desktop .
  - usr/bin/pip3 freeze | grep "mu-editor" | cut -d "=" -f 3 >> ../VERSION

下面示例是 Atom 這個代碼編輯器官方倉庫中給出的 yml 配置文件。

app: Atom
ingredients:
  script:
    - DLD=$(wget -q "https://api.github.com/repos/atom/atom/releases/latest"  -O - | grep -E "https.*atom-amd64.tar.gz" | cut -d'"' -f4)
    - wget -c $DLD
    - echo $DLD | cut -d/ -f8 > VERSION
    - tar zxvf atom*tar.gz
script:
  - cp -r ../atom-*/* usr/bin/
  - find . -name atom.png -exec cp {} atom.png ;
  - cat > atom.desktop <<EOF
  - [Desktop Entry]
  - Type=Application
  - Name=Atom
  - Icon=atom
  - Exec=atom %u
  - Categories=Development;IDE;
  - Comment=The hackable text editor
  - EOF

linuxdeployqt 工具使用

linuxdeployqt 是 Linux 下的 qt 打包工具!

工具安裝

# 下載linuxdeployqt工具
$ wget "https://github.com/probonopd/linuxdeployqt/releases/download/7/linuxdeployqt-7-x86_64.AppImage"
# 重命名linuxdeployqt名稱
$ mv linuxdeployqt-continuous-x86_64.AppImage linuxdeployqt
# 變成系統可執行文件
$ sudo mv ./linuxdeployqt /usr/local/bin
$ sudo chmod 755 linuxdeployqt
# 查看linuxdeployqt版本
$ sudo linuxdelpoyqt --version
linuxdeployqt 4 (commit 988d294), build 481 built on 2018-02-02 15:05:23 UTC
# linuxdeployqt命令要用到-appImage選項
$ wget -c "https://github.com/AppImage/AppImageKit/releases/download/12/appimagetool-x86_64.AppImage" -O /usr/local/bin/appimagetool
# 變成系統可執行文件
$ sudo chmod a+x /usr/local/bin/appimagetool

打包程序

# 不能定會成功
$ linuxdeployqt <本身的工程名稱> -appimage

官方文章中的示例演示

打包軟件程序的簡單演示流程 - cmake

生成 AppDir 打包目錄

# fetch sources (you could as well use a tarball etc.)
> git clone https://github.com/linuxdeploy/QtQuickApp.git
> cd QtQuickApp
# build out of source
> mkdir build
> cd build
# configure build system
# the flags below are the bare minimum that is needed, the app might define additional variables that might have to be set
> cmake .. -DCMAKE_INSTALL_PREFIX=/usr
# build the application on all CPU cores
> make -j$(nproc)
# now "install" resources into future AppDir
> make install DESTDIR=AppDir
AppDir
└── AppRun
└── your_app.desktop
└── your_app.png
└── usr
    ├── bin
    │   └── your_app
    ├── lib
    └── share
        ├── applications
        │   └── your_app.desktop
        └── icons
            └── <theme>
                └── <resolution>
                    └── your_app.png

使用 linuxdeploy 打包成 AppImages

# get linuxdeploy's AppImage
> wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
> chmod +x linuxdeploy-x86_64.AppImage
# run linuxdeploy and generate an AppDir
> ./linuxdeploy-x86_64.AppImage --appdir AppDir

官方的 cmake 工具打包示例

#! /bin/bash
set -x
set -e
# building in temporary directory to keep system clean
# use RAM disk if possible (as in: not building on CI system like Travis, and RAM disk is available)
if [ "$CI" == "" ] && [ -d /dev/shm ]; then
    TEMP_BASE=/dev/shm
else
    TEMP_BASE=/tmp
fi
BUILD_DIR=$(mktemp -d -p "$TEMP_BASE" appimage-build-XXXXXX)
# make sure to clean up build dir, even if errors occur
cleanup () {
    if [ -d "$BUILD_DIR" ]; then
        rm -rf "$BUILD_DIR"
    fi
}
trap cleanup EXIT
# store repo root as variable
REPO_ROOT=$(readlink -f $(dirname $(dirname $0)))
OLD_CWD=$(readlink -f .)
# switch to build dir
pushd "$BUILD_DIR"
# configure build files with CMake
# we need to explicitly set the install prefix, as CMake's default is /usr/local for some reason...
cmake "$REPO_ROOT" -DCMAKE_INSTALL_PREFIX=/usr
# build project and install files into AppDir
make -j$(nproc)
make install DESTDIR=AppDir
# now, build AppImage using linuxdeploy and linuxdeploy-plugin-qt
# download linuxdeploy and its Qt plugin
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
# make them executable
chmod +x linuxdeploy*.AppImage
# make sure Qt plugin finds QML sources so it can deploy the imported files
export QML_SOURCES_PATHS="$REPO_ROOT"/src
# initialize AppDir, bundle shared libraries for QtQuickApp, use Qt plugin to bundle additional resources, and build AppImage, all in one single command
./linuxdeploy-x86_64.AppImage --appdir AppDir --plugin qt --output appimage
# move built AppImage back into original CWD
mv QtQuickApp*.AppImage "$OLD_CWD"
做者: Escape
連接: https://www.escapelife.site/p...

image