author: hjjdebug
date: 2024年 09月 28日 星期六 15:49:51 CST
description: 用systemd 来控制 qt 程序的启动,停止
解决 qt.qpa.xcb: could not connect to display 问题
1. 先写一个QT 的测试程序 basic,
让他不断打印数字.
$ cat main.cpp
#include <QApplication>
#include <QThread>
#include <QDebug>class MyThread: public QThread
{void run(){int count=0;while(1){qDebug()<<"running:"<<count++;sleep(1);}}
};
int main(int argc, char *argv[])
{QApplication app(argc,argv);MyThread thread;thread.start();return app.exec();
}
1.1: 运行,正常
$ ./basic
running: 0
running: 1
running: 2
running: 3
2. 再写这个程序的服务配置文件
$ cat basic.service
[Unit]
Description=Basic Test[Service]
Type=simple
ExecStart=/home/hjj/test/qt//basic/basic
Restart=on-failure[Install]
WantedBy=multi-user.target
3. 测试: 启动服务失败:
$ sudo systemctl start basic.service
4. 状态查询
$ sudo systemctl status basic.service
● basic.service - Basic TestLoaded: loaded (/etc/systemd/system/basic.service; disabled; vendor preset: enabled)Active: failed (Result: core-dump) since Fri 2024-09-27 09:18:56 CST; 5s agoProcess: 6062 ExecStart=/home/hjj/test/qt//basic/basic (code=dumped, signal=ABRT)Main PID: 6062 (code=dumped, signal=ABRT)9月 27 09:18:56 hjj-7090 systemd[1]: basic.service: Scheduled restart job, restart counter is at 5.
9月 27 09:18:56 hjj-7090 systemd[1]: Stopped Basic Test.
9月 27 09:18:56 hjj-7090 systemd[1]: basic.service: Start request repeated too quickly.
9月 27 09:18:56 hjj-7090 systemd[1]: basic.service: Failed with result 'core-dump'.
9月 27 09:18:56 hjj-7090 systemd[1]: Failed to start Basic Test.
5. 详细系统日志
$ journalctl -u basic.service
-- Logs begin at Thu 2024-07-25 08:51:30 CST, end at Fri 2024-09-27 09:26:52 CST. --
9月 27 09:18:53 hjj-7090 systemd[1]: Started Basic Test.
9月 27 09:18:53 hjj-7090 basic[6043]: qt.qpa.xcb: could not connect to display
9月 27 09:18:53 hjj-7090 basic[6043]: qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
9月 27 09:18:53 hjj-7090 basic[6043]: This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
9月 27 09:18:53 hjj-7090 basic[6043]: Available platform plugins are: linuxfb, minimal, offscreen, vnc, xcb.
9月 27 09:18:53 hjj-7090 systemd[1]: basic.service: Main process exited, code=dumped, status=6/ABRT
9月 27 09:18:53 hjj-7090 systemd[1]: basic.service: Failed with result 'core-dump'.
9月 27 09:18:54 hjj-7090 systemd[1]: basic.service: Scheduled restart job, restart counter is at 1.
9月 27 09:18:54 hjj-7090 systemd[1]: Stopped Basic Test.
9月 27 09:18:54 hjj-7090 systemd[1]: Started Basic Test.
9月 27 09:18:54 hjj-7090 basic[6054]: qt.qpa.xcb: could not connect to display
9月 27 09:18:54 hjj-7090 basic[6054]: qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
9月 27 09:18:54 hjj-7090 basic[6054]: This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
9月 27 09:18:54 hjj-7090 basic[6054]: Available platform plugins are: linuxfb, minimal, offscreen, vnc, xcb.
9月 27 09:18:54 hjj-7090 systemd[1]: basic.service: Main process exited, code=dumped, status=6/ABRT
9月 27 09:18:54 hjj-7090 systemd[1]: basic.service: Failed with result 'core-dump'.
9月 27 09:18:54 hjj-7090 systemd[1]: basic.service: Scheduled restart job, restart counter is at 2.
9月 27 09:18:54 hjj-7090 systemd[1]: Stopped Basic Test.
9月 27 09:18:54 hjj-7090 systemd[1]: Started Basic Test.
9月 27 09:18:54 hjj-7090 basic[6057]: qt.qpa.xcb: could not connect to display
9月 27 09:18:54 hjj-7090 basic[6057]: qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
9月 27 09:18:54 hjj-7090 basic[6057]: This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
9月 27 09:18:54 hjj-7090 basic[6057]: Available platform plugins are: linuxfb, minimal, offscreen, vnc, xcb.
9月 27 09:18:54 hjj-7090 systemd[1]: basic.service: Main process exited, code=dumped, status=6/ABRT
9月 27 09:18:54 hjj-7090 systemd[1]: basic.service: Failed with result 'core-dump'.
9月 27 09:18:55 hjj-7090 systemd[1]: basic.service: Scheduled restart job, restart counter is at 3.
9月 27 09:18:55 hjj-7090 systemd[1]: Stopped Basic Test.
9月 27 09:18:55 hjj-7090 systemd[1]: Started Basic Test.
9月 27 09:18:55 hjj-7090 basic[6059]: qt.qpa.xcb: could not connect to display
9月 27 09:18:55 hjj-7090 basic[6059]: qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
9月 27 09:18:55 hjj-7090 basic[6059]: This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
9月 27 09:18:55 hjj-7090 basic[6059]: Available platform plugins are: linuxfb, minimal, offscreen, vnc, xcb.
9月 27 09:18:55 hjj-7090 systemd[1]: basic.service: Main process exited, code=dumped, status=6/ABRT
9月 27 09:18:55 hjj-7090 systemd[1]: basic.service: Failed with result 'core-dump'.
9月 27 09:18:55 hjj-7090 systemd[1]: basic.service: Scheduled restart job, restart counter is at 4.
9月 27 09:18:55 hjj-7090 systemd[1]: Stopped Basic Test.
9月 27 09:18:55 hjj-7090 systemd[1]: Started Basic Test.
9月 27 09:18:55 hjj-7090 basic[6062]: qt.qpa.xcb: could not connect to display
9月 27 09:18:55 hjj-7090 basic[6062]: qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
9月 27 09:18:55 hjj-7090 basic[6062]: This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
9月 27 09:18:55 hjj-7090 basic[6062]: Available platform plugins are: linuxfb, minimal, offscreen, vnc, xcb.
9月 27 09:18:55 hjj-7090 systemd[1]: basic.service: Main process exited, code=dumped, status=6/ABRT
9月 27 09:18:55 hjj-7090 systemd[1]: basic.service: Failed with result 'core-dump'.
9月 27 09:18:56 hjj-7090 systemd[1]: basic.service: Scheduled restart job, restart counter is at 5.
9月 27 09:18:56 hjj-7090 systemd[1]: Stopped Basic Test.
9月 27 09:18:56 hjj-7090 systemd[1]: basic.service: Start request repeated too quickly.
9月 27 09:18:56 hjj-7090 systemd[1]: basic.service: Failed with result 'core-dump'.
9月 27 09:18:56 hjj-7090 systemd[1]: Failed to start Basic Test.
6. 错误原因: 环境变量不同所致!
systemd 的环境变量,只有区区17行
$ cat env.log
LANGUAGE=zh_CN
LC_ADDRESS=en_US.UTF-8
LC_NAME=en_US.UTF-8
LC_MONETARY=en_US.UTF-8
PWD=/
LC_PAPER=en_US.UTF-8
LANG=zh_CN.UTF-8
INVOCATION_ID=049b2226a6d74f39a2fb88aa82227756
LC_IDENTIFICATION=en_US.UTF-8
SHLVL=1
LC_TELEPHONE=en_US.UTF-8
LC_MEASUREMENT=en_US.UTF-8
LC_TIME=en_US.UTF-8
JOURNAL_STREAM=8:92364
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
LC_NUMERIC=en_US.UTF-8
_=/usr/bin/env
而我自己command 的环境变量有61行之多.
经过洗礼才有印象, 最后经过反复测试,比较得到2个关键环境变量.
DISPLAY:=0
XAUTHORITY=/run/user/1000/gdm/Xauthority
7. 命令行下复现问题.
你可以如下测试一下.
$ unset DISPLAY
hjj@hjj-7090:~/test/qt/basic$ ./basic
qt.qpa.xcb: could not connect to display
qt.qpa.plugin: Could not load the Qt platform plugin “xcb” in “” even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Available platform plugins are: linuxfb, minimal, offscreen, vnc, xcb.
已放弃 (核心已转储)
8. 错误到底是在什么地方出现的?
错误出处,原来在QApplication app(argc,argv)中有大量的函数调用,而且大量访问环境变量getenv(),
而其中DISPLAY,XAUTHORITY 环境变量是不可缺少的!!
否则就会在下面函数中打印出错信息!!
QApplicationPrivate::createEventDispatcher
"+>in init_platform of kernel/qguiapplication.cpp:1200
21 in QGuiApplicationPrivate::createPlatformIntegration of ../../include/QtCore/../../src/corelib/te
32 in QGuiApplicationPrivate::createEventDispatcher of kernel/qguiapplication.cpp:1472
43 in QApplicationPrivate::createEventDispatcher of kernel/qapplication.cpp:188
54 in QCoreApplicationPrivate::init of kernel/qcoreapplication.cpp:865
65 in QGuiApplicationPrivate::init of kernel/qguiapplication.cpp:1501
76 in QApplicationPrivate::init of kernel/qapplication.cpp:546
87 in QApplication::QApplication of kernel/qapplication.cpp:534
98 in main of main.cpp:19
调试挺不爽的,可能是有-O2 优化吧,算了,不调试了!
9. 解决办法: 补足其所需要的环境变量.
具体实现办法有两种,
一种是: 让服务程序去调用脚本. 脚本内容是先设置环境变量,再调用执行程序.
另一种: 让服务程序先设置环境变量,再调用程序.
我这里给出第一种吧,
$ cat basic.sh
#!/bin/bash
export XAUTHORITY=/run/user/1000/gdm/Xauthority
export DISPLAY=:0
/home/hjj/test/qt/basic/basic &$ cat basic.service
[Unit]
Description=Basic Test[Service]
Type=forking
#EnvironmentFile=/home/hjj/test/qt/basic/basic.env
ExecStart=/home/hjj/test/qt/basic/basic.sh
Restart=on-failure[Install]
WantedBy=multi-user.target
第二种就是把环境变量写到一个文件中例如 basic.env
$ cat basic.env
XAUTHORITY=/run/user/1000/gdm/Xauthority
DISPLAY=:0
并在上述服务配置中打开basic.env , 则basic.sh 中可不用导出环境变量
不管背着还是抱着,都是要把环境变量配上.
10. 最后的结果
$ sudo systemctl status basic.service
● basic.service - Basic TestLoaded: loaded (/etc/systemd/system/basic.service; disabled; vendor preset: enabled)Active: active (running) since Sat 2024-09-28 14:59:52 CST; 1h 1min agoProcess: 109495 ExecStart=/home/hjj/test/qt/basic/basic.sh (code=exited, status=0/SUCCESS)Main PID: 109498 (basic)Tasks: 3 (limit: 9097)Memory: 2.1MCGroup: /system.slice/basic.service└─109498 /home/hjj/test/qt/basic/basic9月 28 16:01:31 hjj-7090 basic.sh[109498]: running: 3698
9月 28 16:01:32 hjj-7090 basic.sh[109498]: running: 3699
9月 28 16:01:33 hjj-7090 basic.sh[109498]: running: 3700
9月 28 16:01:34 hjj-7090 basic.sh[109498]: running: 3701
9月 28 16:01:35 hjj-7090 basic.sh[109498]: running: 3702