Skip to content
On this page

TIP

此文档适用于 1.8.x, 请使用 ll-cli --version 检查您的玲珑程序版本。


玲珑应用应用程序打包规范

本文中的关键词必须禁止必要的应当不应推荐的允许以及可选的[^rfc2119-keywords]的解释见于RFC 2119中的描述。

这些关键词与原文中的英语词汇的对应关系如下表所示:

中文英语
必须MUST
禁止MUST NOT
必要的REQUIRED
应当SHALL
不应SHALL NOT
推荐的RECOMMENDED
允许MAY
可选的OPTIONAL

本文档旨在帮助应用开发者规范应用程序的构建过程中的行为,以迁移到玲珑包管理系统中。

通用

本节主要记录一些通用的规范,几乎所有项目都应当遵守。

应用名称

应用的名称应当使用反向域名表示法,例如org.deepin.demo

该应用名称主要用于desktop文件的命名、DBus服务的命名等场景。

  • 开发者应当使用自己确实拥有的域名的倒置作为应用名称的前缀,并在之后跟上应用程序名称

    注意:若开发者无法证明其确实拥有该域名,有可能导致应用包从仓库中移除。

  • 对于github上开发的第三方应用而言,如果该应用程序所在的组织有额外的域名,则应当优先使用,否则应当采用io.github.<GITHUB_ID>.作为前缀。

    特别的,如果该应用的组织名和应用名称一致,例如https://github.com/neovim/neovim,打包者不应当省略重复的应用名称与组织名,这个应用的ID应当io.github.neovim.neovim

    注意:实际上该组织拥有域名neovim.io,故最合理的的应用名称应当io.neovim.neovim

  • 不推荐使用含有-的应用名称,如果域名/应用名称确实含有-推荐使用_代替

  • 不推荐应用名称以.desktop结尾

以上规范来自Desktop Entry Specification

拓展阅读:https://docs.flatpak.org/en/latest/conventions.html#application-ids

prefix$DESTDIR

在编写应用程序的构建过程时,开发者不应当假设自己安装的位置是固定的。在Makefile/CMakeLists.txt中将可执行文件安装到硬编码的路径,例如/usr/bin是不规范的行为。

开发者编写构建/安装过程时应当尊重构建系统的prefix配置以及$DESTDIR环境变量的值以使得打包者可以方便地在打包时配置该应用程序的具体安装位置。

prefix指的是构建/安装时指定给构建系统的、应用最终会被安装到系统中的具体位置。

当开发者没有指定安装位置时,其默认值应当/usr/local, 通过包管理系统打包时,包管理系统会配置其值。当使用dpkg相关工具进行打包时,其值会被配置为/usr。但编写构建/安装过程时,开发者应当考虑prefix被配置成任意值的情况。

$DESTDIR是指构建系统进行安装时,为了方便发行版打包等过程,约定的一个环境变量。其大致工作逻辑如下:

若构建系统完成了构建工作后,执行安装过程时,被指定了prefix=/usr,且$DESTDIR=./tmp,则其完成安装后,所有的产物文件都应当出现在./tmp/usr目录中。打包工具随后会将./tmp视为根目录将其中的文件进行压缩打包等工作。

这里以常见的构建系统为例,给出几种常见文件安装过程的推荐编写方式,这些编写方式均尊重prefix配置以及$DESTDIR

Makefile

本节主要参考https://www.gnu.org/prep/standards/standards.html以及https://wiki.debian.org/Multiarch/Implementation中的相关内容编写。

这里定义一些变量的默认值以及其他公共部分以便后文编写示例,这些变量默认值的相关说明可以在上方链接中查找。

makefile
DESTDIR ?=

prefix      ?= /usr/local
bindir      ?= $(prefix)/bin
libdir      ?= $(prefix)/lib
libexecdir  ?= $(prefix)/libexec
datarootdir ?= $(prefix)/share

INSTALL         ?= install
INSTALL_PROGRAM ?= $(INSTALL)
INSTALL_DATA    ?= $(INSTALL) -m 644

# 以上定义的这些具有默认值的变量均为上述规范中的推荐行为,不建议做任何修改。

PKG_CONFIG ?= pkg-config

.PHONY: install
  • 可执行文件

    makefile
    install:
        $(INSTALL) -d "$(DESTDIR)$(bindir)"
        $(INSTALL_PROGRAM) path/to/your/executable "$(DESTDIR)$(bindir)"/executable
    
  • 内部可执行文件

    指不应当由用户在终端中直接调用的可执行文件,这些可执行文件不应当可以通过$PATH找到

    makefile
    install:
        $(INSTALL) -d "$(DESTDIR)$(libexecdir)"
        $(INSTALL_PROGRAM) path/to/my/internal/executable "$(DESTDIR)$(libexecdir)"/executable
    
  • 静态库

    makefile
    install:
        $(INSTALL) -d "$(DESTDIR)$(libdir)"
        $(INSTALL_DATA) path/to/my/library.a "$(DESTDIR)$(libdir)"/library.a
    
  • pkg-config配置文件

    makefile
    pc_dir ?= $(libdir)/pkgconfig
    ifeq ($(findstring $(pc_dir), $(subst :, , $(shell \
        $(PKG_CONFIG) --variable=pc_path)), )
    $(warning pc_dir="$(pc_dir)" \
        is not in the search path of current pkg-config installation)
    endif
    
    .PHONY: install-pkg-config
    install-pkg-config:
        $(INSTALL) -d "$(DESTDIR)$(pc_dir)"
        $(INSTALL_DATA) path/to/your.pc "$(DESTDIR)$(pc_dir)"/your.pc
    

    若可以确定该文件跨架构可用,则可以使用$(datarootdir)代替$(libdir)

  • systemd系统级单元

    makefile
    systemd_system_unit_dir ?= $(shell \
        $(PKG_CONFIG) --define-variable=prefix=$(prefix) \
        systemd --variable=systemd_system_unit_dir)
    ifeq ($(findstring $(systemd_system_unit_dir), $(subst :, , $(shell \
        $(PKG_CONFIG) systemd --variable=systemd_system_unit_path))), )
    $(warning systemd_system_unit_dir="$(systemd_system_unit_dir)" \
        is not in the system unit search path of current systemd installation)
    endif
    
    .PHONY: install-systemd-system-unit
    install-systemd-system-unit:
        $(INSTALL) -d "$(DESTDIR)$(systemd_system_unit_dir)"
        $(INSTALL_DATA) path/to/your.service "$(DESTDIR)$(systemd_system_unit_dir)"/your.service
    
  • systemd用户级单元

    makefile
    systemd_user_unit_dir ?= $(shell \
        $(PKG_CONFIG) --define-variable=prefix=$(prefix) \
        systemd --variable=systemd_user_unit_dir)
    ifeq ($(findstring $(systemd_user_unit_dir), $(subst :, , $(shell \
        $(PKG_CONFIG) systemd --variable=systemd_user_unit_path))), )
    $(warning systemd_user_unit_dir="$(systemd_user_unit_dir)" \
        is not in the user unit search path of current systemd installation)
    endif
    
    .PHONY: install-systemd-user-unit
    install-systemd-user-unit:
        $(INSTALL) -d "$(DESTDIR)$(systemd_user_unit_dir)"
        $(INSTALL_DATA) path/to/your.service "$(DESTDIR)$(systemd_user_unit_dir)"/your.service
    
  • desktop文件

    makefile
    install:
        $(INSTALL) -d "$(DESTDIR)$(datarootdir)"/applications
        $(INSTALL_PROGRAM) path/to/your.desktop "$(DESTDIR)$(datarootdir)"/applications/your.desktop
    
  • desktop文件对应图标

    参见:https://specifications.freedesktop.org/icon-theme-spec/latest/#install_icons

    • 如果安装的图标为固定大小的版本,那么推荐使用png格式

      至少需要安装一个48x48大小的png才能保证桌面环境中图标相关的基础功能正常

    • 如果安装的图标为矢量版本,那么推荐使用svg格式

    makefile
    install:
        $(INSTALL) -d "$(DESTDIR)$(datarootdir)"/icons/hicolor/48x48/apps
        $(INSTALL_DATA) path/to/your.png "$(DESTDIR)$(datarootdir)"/icons/hicolor/48x48/apps/your.png
        # Add more size of .png icons here...
    
        $(INSTALL) -d "$(DESTDIR)$(datarootdir)"/icons/hicolor/scalable/apps
        $(INSTALL_DATA) path/to/your.svg "$(DESTDIR)$(datarootdir)"/icons/hicolor/scalable/apps/your.svg
    

CMake

本节主要参考https://cmake.org/cmake/help/v3.30/module/GNUInstallDirs.html#module:GNUInstallDirs以及https://wiki.debian.org/Multiarch/Implementation中的相关内容编写。

这里定义一些变量的默认值以及其他公共部分以便后文编写示例,这些变量默认值的相关说明可以在上方链接中查找。

编写逻辑与Makefile一节中的相关内容一致。

cmake
include(GNUInstallDirs)
  • 可执行文件

    参见:https://cmake.org/cmake/help/v3.30/command/install.html#programs

    cmake
    install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/path/to/your/executable TYPE BIN)
    
  • 内部可执行文件

    指不应当在终端中直接调用的可执行文件,这些可执行文件不应当可以通过$PATH找到

    参见:https://cmake.org/cmake/help/v3.30/command/install.html#programs

    cmake
    install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/path/to/your/executable DESTINATION ${CMAKE_INSTALL_LIBEXECDIR})
    

    注意:不使用TYPE是因为TYPE目前不支持LIBEXEC

  • 目标文件/导出文件

    待补充

  • pkg-config配置文件

    待补充

  • systemd系统级单元

    cmake
    find_package(PkgConfig)
    if(NOT SYSTEMD_SYSTEM_UNIT_DIR)
        if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.28")
            pkg_get_variable(SYSTEMD_SYSTEM_UNIT_DIR systemd systemd_system_unit_dir
                             DEFINE_VARIABLES prefix=${CMAKE_INSTALL_PREFIX})
        else()
            pkg_get_variable(SYSTEMD_PREFIX systemd prefix)
            pkg_get_variable(SYSTEMD_SYSTEM_UNIT_DIR systemd systemd_system_unit_dir)
            string(REPLACE "${SYSTEMD_PREFIX}" "${CMAKE_INSTALL_PREFIX}"
                   SYSTEMD_SYSTEM_UNIT_DIR "${SYSTEMD_SYSTEM_UNIT_DIR}")
        endif()
    endif()
    pkg_get_variable(SYSTEMD_SYSTEM_UNIT_PATH systemd systemd_system_unit_path)
    if(NOT SYSTEMD_SYSTEM_UNIT_PATH MATCHES ".*:${SYSTEMD_SYSTEM_UNIT_DIR}:.*")
        message(WARNING SYSTEMD_SYSTEM_UNIT_DIR="${SYSTEMD_SYSTEM_UNIT_DIR}" is not
                        in the system unit search path of
                        current systemd installation)
    endif()
    
    install(FILES path/to/your.service
            DESTINATION ${SYSTEMD_SYSTEM_UNIT_DIR})
    
  • systemd用户级单元

    cmake
    find_package(PkgConfig)
    if(NOT SYSTEMD_USER_UNIT_DIR)
        if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.28")
            pkg_get_variable(SYSTEMD_USER_UNIT_DIR systemd systemd_user_unit_dir
                             DEFINE_VARIABLES prefix=${CMAKE_INSTALL_PREFIX})
        else()
            pkg_get_variable(SYSTEMD_PREFIX systemd prefix)
            pkg_get_variable(SYSTEMD_USER_UNIT_DIR systemd systemd_user_unit_dir)
            string(REPLACE "${SYSTEMD_PREFIX}" "${CMAKE_INSTALL_PREFIX}"
                   SYSTEMD_USER_UNIT_DIR "${SYSTEMD_USER_UNIT_DIR}")
        endif()
    endif()
    pkg_get_variable(SYSTEMD_USER_UNIT_PATH systemd systemd_user_unit_path)
    if(NOT SYSTEMD_USER_UNIT_PATH MATCHES ".*:${SYSTEMD_USER_UNIT_DIR}:.*")
        message(WARNING SYSTEMD_USER_UNIT_DIR="${SYSTEMD_USER_UNIT_DIR}" is not
                        in the user unit search path of
                        current systemd installation)
    endif()
    
    install(FILES path/to/your.service
            DESTINATION ${SYSTEMD_USER_UNIT_DIR})
    
  • desktop文件

    cmake
    install(FILES path/to/your.desktop
            DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
    
  • desktop文件对应图标

    cmake
    install(FILES path/to/your.png
            DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/48x48/apps)
    # Add more size of .png icons here...
    
    install(FILES path/to/your.svg
            DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps)
    

配置文件

desktop文件

desktop文件的文件名中不推荐带有-,去掉.desktop后缀后,应当符合应用名称一节中描述的相关规范。

  • 推荐填写TryExec字段,以确保应用已经卸载后,desktop文件不再有效
  • 推荐填写WMClass字段,以确保任务栏等基于窗口和应用程序匹配的桌面环境基础功能能正常工作
  • 推荐填写Exec字段时仅使用可执行文件名称而不是绝对路径
  • 不推荐填写Icon字段时使用绝对路径

DBus服务

  • 推荐service文件的文件名与文件中的Name字段一致
  • 推荐service文件中的Exec字段中使用绝对路径
  • 推荐填写SystemdService字段
  • 推荐SystemdService字段中的服务名称与Name字段一致
  • 推荐Name字段以数字结尾

Systemd服务

  • 推荐具有BusName的service文件的文件名与BusName一致
  • 推荐ExecStart字段中使用绝对路径

上述配置文件在使用绝对路径时,不推荐硬编码路径。其路径应当与最终安装路径保持一致。推荐在项目中先编写模板文件,使用占位符表示绝对路径,通过构建系统替换占位符后生成最终配置文件。

这里以desktop文件为例,给出几个常见构建系统下生成最终配置文件的例子。 假设最终产物org.deepin.demo.desktop内容如下:

ini
[Desktop Entry]
Name=demo
Exec=/usr/bin/demo
Type=Application
Terminal=false
  • 使用Makefile作为构建系统。

    1、先编写模板文件org.deepin.demo.desktop.in,内容如下:

    ini
    [Desktop Entry]
    Name=demo
    Exec=@BINDIR@/demo
    Type=Application
    Terminal=false
    

    2、编写对应的makefile规则。

    makefile
    DESKTOP_TEMPLATE = org.deepin.demo.desktop.in
    DESKTOP_FILE = org.deepin.demo.desktop
    
    # 替换占位符并生成最终的 .desktop 文件
    desktop: $(DESKTOP_TEMPLATE)
      sed -e "s/@BINDIR@/$(bindir)/g" \
          $(DESKTOP_TEMPLATE) > $(DESKTOP_FILE)
    
    install:
        $(INSTALL) -d "$(DESTDIR)$(datarootdir)"/applications
        $(INSTALL_PROGRAM) $(DESKTOP_FILE) "$(DESTDIR)$(datarootdir)"/applications/$(DESKTOP_FILE)
    
    clean:
      rm -f $(DESKTOP_FILE)
    
    all: desktop
    
  • 如果使用CMake作为构建系统。 1、编写desktop模板文件。

    desktop
    [Desktop Entry]
    Name=demo
    Exec=@CMAKE_INSTALL_BINDIR@/demo
    Type=Application
    Terminal=false
    

    2、编写对应的cmake规则。

    cmake
    set(DESKTOP_FILE "org.deepin.demo.desktop")
    # 使用 configure_file 进行占位符替换
    configure_file(
        ${CMAKE_CURRENT_SOURCE_DIR}/org.deepin.demo.desktop.in
        ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE}
        @ONLY
    )
    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE}
            DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
    

头文件以及链接库

玲珑的环境最多有三部分组成,以在x86_64架构下编译org.deepin.demo为例,其头文件以及库文件默认搜索路径包含以下部分:

组成包名头文件库文件
baseorg.deepin.base/usr/include/usr/lib
/usr/lib/x86_64-linux-gnu
runtime (可选)org.deepin.runtime.dtk/runtime/include/runtime/lib
/runtime/lib/x86_64-linux-gnu
apporg.deepin.demo/opt/apps/org.deepin.demo/files/include/opt/apps/org.deepin.demo/files/lib
/opt/apps/org.deepin.demo/files/lib/x86_64-linux-gnu

优先级按从上往下的顺序排列。如果一份头文件同时在org.deepin.baseorg.deepin.demo中存在,使用时会优先匹配到org.deepin.base中的文件。库文件同理。

默认搜索路径适用于标准库或者不带配置文件的开发库。在实际构建场景中,开发库通常会提供配置文件以方便使用者编译和链接,开发者应当在自己的构建系统使用该文件而不是依赖默认搜索路径。

常见的配置文件有.pc.cmake等。具体如何使用取决于开发库以及构建系统,这里给出几种常用的构建系统使用配置文件的例子。

Makefile

使用.pc文件
makefile
# 常用变量, 继承环境变量CXXFLAGS并追加内容
CXX = g++
CXXFLAGS = $(CXXFLAGS) -Wall -Wextra -std=c++11
# 通过pkg-config工具获取.pc文件内容
# 返回值一般为 -I/path -lname 类型的内容
PKG_CONFIG = pkg-config
LIBS = $(shell $(PKG_CONFIG) --cflags --libs libname)

TARGET = demo

SRCS = main.cpp

all: $(TARGET)

# 构建时将.pc提供的信息提供给编译器
$(TARGET): $(SRCS)
 $(CXX) $(CXXFLAGS) $(LIBS) -o $@ $^

clean:
 rm -f $(TARGET)

CMake

使用.pc文件
cmake
find_package(PkgConfig REQUIRED)
pkg_check_modules(PackageAliasName REQUIRED IMPORTED_TARGET PackageName)

# 添加可执行文件
add_executable(demo main.cpp)

# 设置链接库。头文件搜索路径将自动展开。
target_link_libraries(demo PRIVATE PkgConfig::PackageAliasName)
使用.cmake文件
cmake
find_package(<PackageName> REQUIRED COMPONENTS <Component>)

# 添加可执行文件
add_executable(demo main.cpp)

# 设置链接库。头文件搜索路径将自动展开。
target_link_libraries(demo PRIVATE PackageName::Component)

注意:

不推荐直接在项目构建配置文件中硬编码上述默认搜索路径。 不推荐覆盖CFLAGS/CXXFLAGS等环境量,有额外参数应当向这些变量后追加。

依赖引入

头文件及链接库一节提到,玲珑环境由多个部分组成。如果base甚至runtime中的内容无法满足要求时,开发者应当自行在APP一侧引入缺失的依赖。引入方式为,在linglong.yaml文件中sources字段下声明,并在build字段下编写相应的安装或者编译规则。

sources支持多种文件类型,允许引入源码或者编译好的二进制文件,甚至一个deb。但对于引入编译好的二进制文件,开发者必须考虑其是否与当前base或runtime兼容。

使用源码引入

通过源码引入依赖是一个推荐的做法,它能极大的保证构建流程的稳定以及可维护性。缺点是这可能会花费开发者不少时间编写yaml文件,因为依赖也许也会有自身的依赖。

如果开发者发现依赖复杂且重复被其他应用使用,那么应当考虑将依赖整合做成一个runtime类型的包。

当依赖是在玲珑环境下编译产生时,其配置文件通常是“可靠的”。编译安装后开发者可以直接在项目中使用。

yaml
sources:
  - kind: git
    url: # app source url
    commit: # commit hash
  - kind: git
    url: # dependency source url
    commit: # commit hash
build:
  # 编译依赖
  cd /project/your_dependency_name/
  cmake -Bbuild -DCMAKE_INSTALL_PREFIX=$PREFIX
  make install

  # 编译、安装APP
  cd /project/your_app_name
  cmake -Bbuild -DCMAKE_INSTALL_PREFIX=$PREFIX
  make install

使用deb引入

这是一条“捷径”。如果开发者不考虑应用的后续更新可使用此方式。开发者可以借助辅助工具分析依赖关系,将涉及到的依赖批量在sources中导入。

使用vscode linglong扩展
  1. 安装 aptly 命令行工具
  2. 在 vscode 扩展商店搜索 linglong 安装相关插件。
  3. 将 sources 字段放在 linglong.yaml 的最后
  4. 在 sources 最后添加 gen_deb_source 注释
  5. 按 Ctrl+Shift+P 搜索执行 linglong: Gen deb sources 命令

执行后的yaml文件将自动写入如下内容:

yaml
build:
  # 解压导入deb,install_dep文件由插件自动下载
  bash ./install_dep linglong/sources "$PREFIX"

  # 编译、安装APP
sources:
  # 源码
  - kind: git
    url: # app source url
    commit: # commit hash
  # 以下注释由插件生成并使用,从仓库中检索 libical-dev 分析其依赖,自动生成sources到注释的下面
  # linglong:gen_deb_source sources amd64 https://ci.deepin.com/repo/deepin/deepin-community/backup/rc2 beige main
  # linglong:gen_deb_source install libical-dev

注意: deb的编译产物,安装前缀是/usrinstall_dep脚本会自动处理其中的.pc文件,将/usr替换成$PREFIXxxx.cmake类型文件无法批量处理,如果有硬编码路径行为,可能无法正常工作。

玲珑

本节主要描述一些玲珑包管理系统对应用程序的特殊要求。

限制

  • 需要通过玲珑包管理系统打包的应用程序必须以启动玲珑容器的用户身份(通常为普通用户)运行。任何形式的权限提升机制在玲珑包管理系统运行应用时均不可用,包括但不限于文件系统中记录的SUID位以及capabilities等基于文件系统拓展属性的权限提升机制。
  • 玲珑目前不支持打包含有系统级systemd单元的应用程序。
  • 不推荐打包桌面环境(Desktop Environment)组件,如启动器、文件管理器、资源管理器、状态栏等。

规范

应用包名

玲珑应用的包名必须完全符合上文“应用名称”一节中的相关规定,除此之外:

  • 应用名称不区分大小写

应用版本号

玲珑包的应用版本号必须.分割的四组十进制数字,例如1.0.0.0

如果指定的版本号不足四组,则会向后补充0直至满足条件,例如1.90会被自动补充为1.90.0.0

自动补足至四组后的版本号总体长度在字符串意义上禁止超过256字节。

运行环境

玲珑应用必须选择一个base作为基础运行环境。可使用的base:

基础库包名/版本
glibc(2.38)org.deepin.base/23.1.0.0

如果需要额外使用基础环境以外的框架,应当使用合适的runtime。可使用的runtime:

框架包名/版本
QT(5.15) + DTK(5.6)org.deepin.runtime.dtk/23.1.0.0

在使用base或runtime时,版本号推荐填写前三位,如 '23.1.0',便于后续接收更新。全量填写4位版本表示禁止base或runtime更新。

安装位置

在构建以及安装过程中过程中,玲珑的构建工具会设置$PREFIX环境变量。该环境变量的值应当/opt/apps/${APPID}/files,但并不建议在编写构建以及安装过程中直接使用其常见值,推荐总是读取$PREFIX环境变量。

对应用程序的构建以及安装过程而言,可写的目录仅有

  1. 放置构建所需源码的/source目录
  2. 安装的位置,即$PREFIX指定的位置

向构建过程中的其他位置安装文件是禁止的,通常会导致写失败或应用在运行时无法找到这些文件。

以下是在调用部分常见构建系统时使用$PREFIX环境变量控制应用安装位置的例子:

cmake
bash
cd path/to/build && cmake path/to/source -DCMAKE_INSTALL_PREFIX="$PREFIX"
make
bash
cd path/to/source && make prefix="$PREFIX"
meson
bash
cd path/to/source && meson configure --prefix="$PREFIX" path/to/build

构建产物

本节主要描述应用构建成功后的产物组成及相关功能。

目录结构

玲珑的构建工具在应用构建成功后,会将产物提交到本地的缓存中。在进行离线分发时,应该导出成.layer.uab类型文件。

通过解压构建产物layer文件:

bash
ll-builder extract org.deepin.demo_0.0.0.1_x86_64_binary.layer ./tmp

可以得到以下目录结构:

plain
  ./tmp
  ├── entries
  │   └── share -> ../files/share
  ├── files
  │   ├── bin
  │   │   └── demo
  │   ├── share
  │   │   ├── applications
  │   │   │   └── org.deepin.demo.desktop
  │   │   ├── icons
  │   │   │   └── hicolor
  │   │   │       └── scalable
  │   │   │           └── apps
  │   │   │               └── org.deepin.demo.svg
  │   │   ├── doc
  │   │   │   ├── changelog.gz
  │   │   │   └── copyright
  │   │   ├── mime
  │   │   │   └── packages
  │   │   │        └── org.deepin.demo.xml
  │   │   ├── locale
  │   │   │   └── zh_CN
  │   │   │       └── info.json
  │   │   └── services
  │   │       └── org.deepin.demo.xml
  │   └── libs
  │       └── libdemo.so.5.2.1
  ├── info.json
  └── org.deepin.demo.install

应用运行时,这些文件或目录将被映射到容器中如下路径:

plain
/
├── bin
├── ...
├── opt
│   └── apps
│       └── org.deepin.demo
│            ├── files
│            ├── entries
│            ├── info.json
│            └── org.deepin.demo.install
└── var

info.json文件

info.json是玲珑定义的应用描述文件。该文件由构建工具自动生成,它不应被手动修改。其内容如下:

json
{
  "id": "org.deepin.demo",
  "arch": [
    "x86_64"
  ],
  "base": "main:org.deepin.foundation/23.0.0/x86_64",
  "channel": "main",
  "command": [
    "/opt/apps/org.deepin.demo/files/bin/demo"
  ],
  "description": "simple Qt demo.\n",
  "kind": "app",
  "module": "runtime",
  "name": "demo",
  "runtime": "main:org.deepin.Runtime/23.0.1/x86_64",
  "size": 118763,
  "version": "0.0.0.1"
}

下面对info.json中各个字段的依次说明:

id:软件包标识,即应用包名。

arch:软件包支持架构,当前支持如下 CPU 架构。

  • amd64:适用 x86_64 架构 CPU
  • loongarch64:适用新版龙芯系列 CPU
  • arm64:适用 ARM64CPU

base: 软件包运行时使用的基础环境。

channel:软件包分发渠道。

command: 软件包默认启动命令。

description:软件包的描述信息。

kind:软件包类别。

module:软件包模块。

name:软件包常用名。

runtime:软件包运行时使用的环境。

size:软件包大小。

version:应用版本,其格式应满足应用版本号一节所述要求。

entries 目录

该目录用于共享应用配置文件给宿主机(桌面环境),该目录下通常有如下子目录:

  • entries/share/applications
  • entries/share/dbus-1/services
  • entries/share/systemd/user
  • entries/share/icons
  • entries/share/mime
  • entries/share/fonts

entries目录由构建工具自动生成,目录下只存放了一个名为share的软链接,该链接文件指向上层目录的files/share。

当应用被安装到宿主机上时,玲珑包管理器会通过该链接文件将其中的所有文件链接到玲珑添加到$XDG_DATA_DIRS变量中的路径下。即/var/lib/linglong/entries/share/

bash
$ ls /var/lib/linglong/entries/share/applications/ -l
lrwxrwxrwx 1 deepin-linglong deepin-linglong 101 7月30日 11:13 org.deepin.demo.desktop -> ../../../layers/main/org.deepin.demo/0.0.0.1/x86_64/runtime/entries/share/applications/org.deepin.demo.desktop
applications目录

放置应用启动配置文件,即.desktop文件。

ini
[Desktop Entry]
Exec=demo
Name=demo
TryExec=demo
Type=Application

该文件在构建时,将会被自动修改为 :

ini
[Desktop Entry]
Exec=/usr/bin/ll-cli run org.deepin.demo -- demo
Name=demo
TryExec=/usr/bin/ll-cli
Type=Application

应用可以有多个desktop文件。

路径对应关系:

打包路径安装路径
$PREFIX/share/applications/org.deepin.demo.desktop$XDG_DATA_DIRS/share/applications/org.deepin.demo.desktop
dbus services 目录

程序注册的 dbus 服务目录,例如:

ini
[D-BUS Service]
Name=org.deepin.demo
Exec=/opt/apps/org.deepin.demo/files/bin/demo --dbus

该文件在构建时,将会被自动修改为 :

ini
[D-BUS Service]
Name=org.deepin.demo
Exec=/usr/bin/ll-cli run org.deepin.demo -- /opt/apps/org.deepin.demo/files/bin/demo --dbus

一个应用允许配置多个 service,服务名必须是子域名。

路径对应关系:

打包路径安装路径
$PREFIX/share/services/org.deepin.demo.service$XDG_DATA_DIRS/dbus-1/service/org.deepin.demo.service
$PREFIX/share/services/org.deepin.demo.hello.service$XDG_DATA_DIRS/dbus-1/service/org.deepin.demo.hello.service
用户级systemd服务

程序注册的用户级服务目录,例如:

ini
[Unit]
Description = demo service
After=user-session.target

[Service]
Type = simple
ExecStart = demo

[Install]
WantedBy=user-session.target

该文件在构建时,将会被自动修改为 :

ini
[Unit]
Description = demo service
After=user-session.target

[Service]
Type = simple
ExecStart = ll-cli run org.deepin.demo -- demo

[Install]
WantedBy=user-session.target

与dbus service不同的是,安装到$PREFIX/lib/systemd/user下的文件会被自动拷贝到$PREFIX/share/systemd/user

路径对应关系:

打包路径安装路径
$PREFIX/lib/systemd/user/org.deepin.demo.service$XDG_DATA_DIRS/systemd/user/org.deepin.demo.service
icons 目录

应用图标存放目录,结构与系统 icons 目录结构保持一致即可。

路径对应关系:

打包路径安装路径
$PREFIX/share/icons/hicolor/scalable/apps/org.deepin.demo.svg$XDG_DATA_DIRS/icons/hicolor/scalable/apps/org.deepin.demo.svg
$PREFIX/share/icons/hicolor/24x24/apps/org.deepin.demo.png$XDG_DATA_DIRS/icons/hicolor/24x24/apps/org.deepin.demo.png
$PREFIX/share/icons/hicolor/16x16/apps/org.deepin.demo.png$XDG_DATA_DIRS/icons/hicolor/16x16/apps/org.deepin.demo.png
mime 目录

MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。该目录用于存放 mime 配置文件,文件是 XML 格式,以.xml 结尾。

路径对应关系:

打包路径安装路径
$PREFIX/share/mime/packages/org.deepin.demo.xml$XDG_DATA_DIRS/mime/packages/org.deepin.demo.xml
fonts 目录

字体存放路径。

files 目录

存放应用程序需要的各种文件,对于该目录放置文件并无限制,但是建议将可执行程序放置到 bin 子目录。应用程序或者插件依赖的第三方库推荐放置在/opt/apps/${id}/files/lib 目录。

.install文件

上述示例org.deepin.demo中的org.deepin.demo.install文件是构建过程中自动生成的文件。该文件用于定义binary模块中应该安装哪些文件,可用于软件包最终产物体积裁剪。

未在linglong.yaml同级目录下定义该文件时,所有内容均按linglong.yaml中build下的规则安装到binary模块。

使用方法:

第一次构建成功后,会在产物中生成.install文件并记录所有安装至binary模块的文件。将该文件拷贝到linglong.yaml同级的目录下,修改.install文件中的内容后再次构建,只有.install内注明的内容会被提交到binary模块。

参考资料

桌面应用打包规范