跳转到内容
新建笔记

嵌入式 Linux:用 systemd 替换 Qt 启动应用

原始记录来自 ATK-MP157 开发板:系统通过 atk-qtapp-start.service 启动厂商 Qt 桌面,目标是替换为 /home/root/install/jpbalance。这是一份嵌入式 Linux 部署案例;服务名、目录和平台插件取自当时环境,不是所有 Linux 桌面的通用配置。

原记录的有效信息如下:

项目当时的配置
厂商单元/lib/systemd/system/atk-qtapp-start.service
原应用/usr/local/QDesktop-fb -platform linuxfb
另一个注释候选/usr/local/QDesktop-egl -platform eglfs
环境文件/etc/default/atk-qtenv
服务类型Type=simple
启动目标WantedBy=multi-user.target
特殊依赖After=systemd-remount-fs.service、DefaultDependencies=no
新应用与工作目录/home/root/install/jpbalance、/home/root/install

linuxfb 与 eglfs 是不同的平台插件,不能只换名字就假定能够运行。前者面向 Linux framebuffer 的软件绘制;后者需要匹配的 EGL/OpenGL ES 和板级支持。是否可用还取决于 Qt 构建、插件、驱动、设备节点和访问权限。Qt 嵌入式 Linux 文档

第一步:查看正在生效的配置

跳转到“第一步:查看正在生效的配置”

在目标开发板上执行:

终端窗口
systemctl status atk-qtapp-start.service --no-pager
systemctl cat atk-qtapp-start.service
systemctl show atk-qtapp-start.service -p FragmentPath -p DropInPaths -p ExecStart
systemctl is-enabled atk-qtapp-start.service
journalctl -u atk-qtapp-start.service -b --no-pager -n 80

list-units --type=service --state=running 只列正在运行的服务,不能用它证明一个停止的服务不存在。原截图式输出中的 inactive (dead)、status=0/SUCCESS 表示当时进程正常退出,并不表示 Qt 程序正在运行。其日志时间也只是开发板当时的系统时钟,不能据此推断版本发布时间。

继续检查可执行文件架构、执行权限、依赖库和平台插件,以及 /etc/default/atk-qtenv 中具体设置了什么。保留当前有效单元、已有覆盖文件、环境文件和应用版本的备份;不要只备份 /lib 下的一个文件就忽略已有的本地覆盖。

第二步:用本地覆盖替换启动命令

跳转到“第二步:用本地覆盖替换启动命令”

对“沿用同一个服务,只替换应用”的需求,可在 /etc/systemd/system/atk-qtapp-start.service.d/ 放置局部覆盖,避免直接修改厂商单元。systemd 会把这些 .conf 文件与基础单元合并;需要留意已有文件的顺序和冲突。systemd 单元覆盖规则

创建或编辑专用于本次应用替换的 50-jpbalance.conf,内容为:

[Service]
# 先清空基础单元中的启动命令,再设置新命令。
ExecStart=
ExecStart=/home/root/install/jpbalance -platform linuxfb
# 注释放在单独一行。
WorkingDirectory=/home/root/install

原稿的 WorkingDirectory=/home/root/install # 设置工作目录 不正确:systemd 的配置不是 shell 脚本,不能在这里依赖 shell 式行尾注释;后面的文字可能成为取值的一部分。工作目录和程序文件都必须真实存在。配置语法、WorkingDirectory 说明

本覆盖保留厂商原有的环境和依赖。DefaultDependencies=no 会关闭常规默认依赖,属于必须结合板级启动流程理解的配置,不能顺手复制到另一台设备的新服务中。

原稿还设置了 LD_LIBRARY_PATH=/home/root/install。只有应用确实需要从那里加载库时才加;先检查可执行文件及插件的依赖,不能用任意扩大搜索路径掩盖 ABI 或 Qt 版本不匹配。

如果需要专门的应用环境文件,可在上述覆盖的 [Service] 中追加:

EnvironmentFile=/etc/default/jpbalance

然后在 /etc/default/jpbalance 中写入经过核对的完整路径,例如该设备确实只需要此额外目录时:

LD_LIBRARY_PATH=/home/root/install

这里追加的环境文件在基础单元的环境文件之后处理,同名变量会覆盖之前的值。如果原来的变量包含必需目录,应把它们明确保留在新值中;不要写 $LD_LIBRARY_PATH 并期待 systemd 像交互 shell 一样展开。环境文件的赋值规则和优先级见 systemd 执行环境文档。

第三步:重新加载并验证

跳转到“第三步:重新加载并验证”

以下操作会停止旧界面,应从独立的终端或远程连接执行。命令用于开发板案例,不是本网站服务器的部署命令。

终端窗口
sudo systemctl stop atk-qtapp-start.service
sudo systemctl daemon-reload
systemctl cat atk-qtapp-start.service
sudo systemctl start atk-qtapp-start.service
systemctl status atk-qtapp-start.service --no-pager
journalctl -u atk-qtapp-start.service -b --no-pager -n 80

确认显示、输入、业务初始化和退出行为都正常,再决定是否让它开机启动:

终端窗口
sudo systemctl enable atk-qtapp-start.service

这几个动作含义不同:stop/start 控制现在的进程,disable/enable 控制开机激活关系,daemon-reload 重新读取单元配置。单独 enable 不会立即启动,单独 disable 也不会立即停止;支持的版本可使用 --now 同时处理现在的运行状态。systemctl 说明

若退出后需要自动恢复,可在理解应用退出码、重试间隔和启动限速后再配置 Restart=on-failure 等策略。原稿注释掉的 Restart=always 不应直接启用来掩盖启动故障。

回退时先停止该服务,撤销本次创建的 50-jpbalance.conf 或恢复它的原备份,保留其他已有覆盖;再 daemon-reload、检查 systemctl cat 并启动原应用。是否启用开机启动,应恢复为第一步记录的状态。

本页完成的是官方配置规则核验和历史记录重写,没有在原 ATK-MP157 硬件上执行替换。最终验收必须包含冷启动、显示和输入、应用异常退出、日志与依赖库检查;“服务进程存在”不足以证明界面和业务可用。

原始案例:关闭正点原子 atk-qtapp-start.service。保留板型、路径、环境和平台选择,修正配置注释、服务动作混淆及直接覆盖厂商单元的操作组织。