移植Windows系统下python应用程序到银河麒麟Linux
一、安装python环境
1、我直接用的Miniforge3-Linux-x86_64.sh,下载安装包,也有Miniforge3-Linux-aarch64.sh架构的。
2、执行脚本安装
安装过程中有选项的直接yes,
最后会提示是否执行conda init,默认是no,我直接默认了。然后在命令行手动conda init,提示找不到conda命令,这时需要去Miniforge3的安装目录下找conda命令,在那执行conda init,就自动添加环境变量了
3、然后创建python虚拟环境
conda create -n mypythonenv python==3.8
创建名称为mypythonenv的python虚拟环境,默认安装python版本3.8
conda activate mypythonenv 激活环境
conda install pip 安装pip
然后就可以安装所有需要的依赖库
运行时,遇到一个问题:
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: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, wayland-egl, wayland, wayland-xcomposite-egl, wayland-xcomposite-glx, webgl, xcb.
设置环境变量
export QT_DEBUG_PLUGINS=1
然后再次执行程序,会显示出详细的问题
提示python3.8/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so: (libxkbcommon-x11.so.0: 无法打开共享对象文件: 没有那个文件或目录)
缺少libxkbcommon-x11.so.0
安装
yum install libxkbcommon-x11
二、编译C++库
我移植的程序调用了C++的动态库,有第三方动态库libsdk.so,我又封装了一层libmyhandle.so库。他们的关系是python程序调用libmyhandle.so,libmyhandle.so调用libsdk.so。
在这里我要编译libmyhandle.so,首先要注意编译libmyhandle.so的glibc版本要等于或高于编译libsdk.so的glibc版本,最好是一样否则可能不兼容。
1、编写Makefile,照着改的,重点是把头文件,动态库的路径写对
# Makefile
# 设置编译器
CC=gcc -O2
CXX=c++ -O2
# 编译选项
CFLAGS = -Wall -std=c99 -fPIC
CXXFLAGS = -Wall -std=c++17 -fPIC
LINK_LIB = -L./third_party/linux/ubuntu22 -ldocsm9 -DMIKE_KGC -DSKY_API_EXPORTS -Xlinker "-(" -Wl,-rpath=./dll/linux -ldocsm9 -Xlinker "-)"
# 包含路径
INCLUDES = -Iinclude -Iinclude/kgc -Iinclude/sky_crypto -Iinclude/utils -Ithird_party/linux/ubuntu22
# 源文件目录
SRC_DIRS = src src/kgc src/utils src/sky_crypto
# C 源文件
C_SRC_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c))
# C++ 源文件
CXX_SRC_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.cpp))
# 对象文件
C_OBJ_FILES := $(patsubst src/%.c,.objs/%.o,$(C_SRC_FILES))
CXX_OBJ_FILES := $(patsubst src/%.cpp,.objs/%.o,$(CXX_SRC_FILES))
# 动态库文件
LIB_NAME = libsky_handler.so
LIB_PATH = build/$(LIB_NAME)
# 创建对象文件的目录
OBJ_DIR = .objs
$(shell mkdir -p $(OBJ_DIR)/kgc $(OBJ_DIR)/utils $(OBJ_DIR)/sky_crypto)
all: $(LIB_PATH)
$(LIB_PATH): $(C_OBJ_FILES) $(CXX_OBJ_FILES)
$(CXX) $(CXXFLAGS) -shared -o $@ $^ $(LINK_LIB)
.objs/%.o: src/%.c
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ $(LINK_LIB)
.objs/%.o: src/%.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@ $(LINK_LIB)
clean:
rm -rf .objs build/*.so
.PHONY: all clean
编译很容易成功了,还挺高兴,结果运行报错:
terminate called after throwing an instance of ‘std::runtime_error’
what(): locale::facet::_S_create_c_locale name not valid
Aborted (core dumped)
用人工智障搜了一下,说什么在代码中设置了本地配置locale()之类的,我找了半天也没发现。
最后从网上找到是因为编码不同,我的C++源码时在Windows系统vs下写的默认是GB2312,Linux系统没有安装GB2312编码的支持
用local -a 命令查看当前已经安装的编码
开始是没有zh_CN.gb2312和zh_CN.gbk的,需要安装
修改文件/var/lib/locales/supported.d/zh-hans,有的说是/var/lib/locales/supported.d/local,我的是银河麒麟V10桌面版,文件名是zh-hans
增加
zh_CN.GB2312 GB2312
zh_CN.GBK GBK
然后运行命令
sudo dpkg-reconfigure --force locales
选择zh_CN.GB2312 GB2312和zh_CN.GBK GBK,确定
locale -a 查看是否支持。不用切换当前编码,再次编译C++源码
补充:后来发现分发时如果目标机器上没有支持GB2312字符集也运行不了,又搜了一下,发现是因为代码中包含了include文件,使用了类似下边的代码
std::wstring utf8_to_wstring(const std::string& str) {
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
return converter.from_bytes(str);
}
std::string wstring_to_utf8(const std::wstring& wstr) {
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
return converter.to_bytes(wstr);
}
如果Linux系统下不需要转换直接把这些去掉就行了。
Makefile中-L指定的是编译时链接动态库的路径,当运行时,系统默认从/usr/lib等目录下查找,所以要指定运行时查找动态库的路径 -Xlinker “-(” -Wl,-rpath=./dll/linux -ldocsm9 -Xlinker “-)”
三、打安装包
1、先用pyinstaller打包安卓程序
这里注意一点,使用–paths指定路径或–add-datas添加文件用冒号:分割,windows系统用分号;分割
2、新建一个文件夹package_install,存放打包好的python可执行文件和依赖文件。
假设我们把程序安装在/opt下,并且应用程序名字叫CongCong,在文件夹package_install新建/opt文件
mkdir -p package_install/opt/CongCong
将python可执行文件和依赖文件复制到该目录下,这样安装后就可以在/opt/CongCong目录下找到应用程序。
为了让我们的应用程序在菜单/搜索中显示出来,我们还需要在/usr/share/applications 下安装一个.desktop 文件。
mkdir -p package_install/usr/share/applications
将编辑好的.desktop文件放在该目录下,desktop文件可以按照下边的写,也可以找一个已经安装的应用程序的desktop文件来照人家的样式改,我是按照奇安信安全浏览器的样式改的
fileencryption.desktop
[Desktop Entry]
Version=2.1.0
# begin USE_TDHX_LINUX_PACKAGE
Name=File Safe
Name[zh_CN]=文件保险箱
Name[zh_HK]=文件保险箱
Name[zh_TW]=文件保险箱
# end USE_TDHX_LINUX_PACKAGE
# Only KDE 4 seems to use GenericName, so we reuse the KDE strings.
# From Ubuntu's language-pack-kde-XX-base packages, version 9.04-20090413.
GenericName=File Safe
GenericName[zh_CN]=文件保险箱
GenericName[zh_HK]=文件保险箱
GenericName[zh_TW]=文件保险箱
# Not translated in KDE, from Epiphany 2.26.1-0ubuntu1.
GenericName[fil]=File Safe
# Gnome and KDE 3 uses Comment.
Comment=File Safe
Comment[en_GB]=File Safe
Comment[es]=File Safe
Comment[zh_CN]=文件安全
Comment[zh_HK]=文件安全
Comment[zh_TW]=文件安全
Path=/opt/CongCong
Exec=/opt/CongCong/Cong_Client
StartupNotify=false
Terminal=false
# 当图标文件在/usr/share/icons/目录下可以直接写图标名称,其它目录下需要写绝对路径
Icon=ic_logo.png
Type=Application
# 应用程序类型是实用工具
Categories=Utility;
# MimeType用于指定该应用程序可以处理的 MIME 类型。MIME 类型是一种标准,用于表示文档、文件或字节流的性质和格式,比如文本文件 (text/plain)、HTML 文件 (text/html) 或者图像文件 (image/jpeg) 等
MimeType=application/pdf;image/gif;image/jpeg;image/png;image/webp;text/html;text/xml;text/plain;
我们还要为应用程序设置一个图标,图标文件可以放在/usr/share/icons/hicolor目录下,这样只要在.desktop文件中写清除图片名称就行了,会自动查找应用。当然也可以在.desktop文件中写图片的绝对路径。
在/usr/share/icons/hicolor目录下有各种尺寸的图标文件夹
所以我们需要多准备不同尺寸的图片,以便于自动适应屏幕的分辨率
假设我们将图片放在128x128目录下
mkdir -p package_install/usr/share/icons/hicolor/128x128/apps
将我们想作为程序图标的图片放在package_install/usr/share/icons/hicolor/128x128/apps目录下
如果尺寸不同就多建几个对应的目录
如果是可缩放的svg类型的图片可以直接放在/usr/share/icons/hicolor/scalable/apps目录下
建立软连接(可选)
mkdir -p package_install/usr/bin
ln -s /opt/CongCong/Cong_Client package_install/usr/bin/Cong_Client
ln -s /opt/CongCong/server_feb/Cong_Server package_install/usr/bin/Cong_Server
动态库(可选)
如果程序启动时需要链接自己的动态库,放在当前安装目录可能找不到,可以放在/usr/lib目录
mkdir -p package_install/usr/lib
将动态库放在该目录下,安装时自动放在/usr/lib目录
安装系统服务(可选)
如果想启动一个后台服务,比如监控程序运行等。要新建一个service文件
## 重新加载 systemd 配置
#sudo systemctl daemon-reexec
#sudo systemctl daemon-reload
#
## 启用开机自启
#sudo systemctl enable feb_server.service
#
## 启动服务
#sudo systemctl start feb_server.service
#
## 查看状态
#sudo systemctl status feb_server.service
[Unit]
Description=Feb Server Service
After=network.target
[Service]
ExecStart=Cong_Server # 可执行程序,用绝对路径。如果不用绝对路径,需要建立软连接
WorkingDirectory=/opt/CongCong/server_feb # 工作路径
Restart=always # 不存在进程则一直重启
User=root # 表示root用户权限 如果不需要,可以改成普通用户的用户名
StandardOutput=syslog # 对于新系统 现在推荐 journal
StandardError=syslog # 对于新系统 现在推荐 journal
SyslogIdentifier=FebServerRun
[Install]
WantedBy=multi-user.target
如果用root权限启动该服务,需要将文件放在/etc/systemd/system/目录下
如果是普通用户启动该服务,需要将文件放在~/.config/systemd/user/目录下
安装方式同上
mkdir -p package_install/etc/systemd/system/
将service文件放进去
为自定义文件设置图标(可选)
首先准备一个png图片作为图标,放在package_install/opt/CongCong/目录下,也可以是其它目录。
Linux系统用MIME-Info database管理图标,所以需要准备一个xml文件作为mime的自定义图标配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/x-MyFileType">
<comment>My Custom SKY File Icon</comment>
<glob pattern="*.MyFileType"/>
<icon name="MyFileType_Icon"/>
<generic-icon name="text-x-generic"/>
</mime-type>
</mime-info>
将xml文件中的MyFileType改成自定义的文件类型后缀,将文件中MyFileType_Icon改成作为图标的图片名称,注意不带后缀名。
最后写一个set_icon.sh脚本,用于将图片和xml文件复制到指定的目录下,并且更新mime配置和系统图标缓存
# 安装 MIME 类型定义
sudo mkdir -p "/usr/share/mime/packages"
sudo cp "/opt/CongCong/mime/sky_mime.xml" "/usr/share/mime/packages/"
sudo update-mime-database "/usr/share/mime"
# 安装图标
sudo mkdir -p "/usr/share/icons/hicolor/128x128/mimetypes"
sudo cp "/opt/CongCong/sky.png" "/usr/share/icons/hicolor/128x128/mimetypes/"
sudo gtk-update-icon-cache "/usr/share/icons/hicolor"
sh脚本中的路径用安装后的绝对路径,否则找不到。只要设置打包后自动执行sh脚本就可以了。
文件都准备好了,下边我们用fpm工具打成安装包,fpm工具可以制作Ubuntu和Debian下的.deb安装包 ,Redhat系统下的.rpm安装包 ,在Arch Linux系统下的.pacman安装包
fpm工具是Ruby编写的,先安装Ruby
sudo apt install ruby
安装fpm
gem install fpm
安装完可能找不到fpm命令,手动添加到环境变量.bashrc文件中,安装过程中注意一下安装在哪个路径下了,我的是/root/.gem/ruby/2.7.0/bin/fpm路径下
打安装包之前,再更改一下文件的权限,因为我们的可执行文件可能都是root权限,我们需要让普通用户也可以执行程序,如果某些文件需要读写权限,给成766.
递归修改
find package_install/opt/CongCong -type f -exec chmod 766 -- {} +
find package_install/usr/share -type f -exec chmod 644 -- {} +
# 文件夹改成777权限
find package_install/opt/CongCong -type d -exec chmod 777 -- {} +
# 将sh文件改成777权限
find package_install/opt/CongCong -type f -name "*.sh" -exec chmod 777 -- {} +
#将可执行文件改成777权限
chmod 777 Cong_Client
打安装包命令
fpm -C package_install/ -s dir -t deb -n “CongCong” -v 2.1.0 -p CongCong-install.deb --after-install package_install/opt/CongCong/set_icon.sh
参数:
-C 在搜索文件之前要改变的文件夹:我们的 文件夹package_install
-s 要打包的源的类型::一个文件夹,dir
-t 要建立的包的类型:: deb
-n 应用程序的名称 : “CongCong”
-v 该应用程序的版本: 2.1.0
-p 要输出的软件包名称: CongCong-install.deb
–after-install 安装完成后执行脚本
–deb-user=nobody 设置安装后文件所属用户
–deb-group=nogroup 设置安装后文件所属用户组
安装包中如果有数据库文件,那么当升级等重复安装时,可能希望不替换数据库文件,所以将db文件改个名字比如database.db.template,然后写一个脚本,在安装后执行,判断安装目录是否存在数据库文件,不存在则替换,存在则保留
#!/bin/bash
#替换数据库文件
BACKUP_CONF_RECORD_DB_PATH="/opt/CongCong/backup_conf_record.db"
BACKUP_CONF_RECORD_TEMPLATE_PATH="/opt/CongCong/backup_conf_record.db.template"
if [ ! -f "$BACKUP_CONF_RECORD_DB_PATH" ]; then
cp "$BACKUP_CONF_RECORD_TEMPLATE_PATH" "$BACKUP_CONF_RECORD_DB_PATH"
chown nobody:nogroup "$BACKUP_CONF_RECORD_DB_PATH"
chmod 644 "$BACKUP_CONF_RECORD_DB_PATH"
fi
成功后可以双击执行安装,可以用dpkg -i 命令安装。
更多推荐
所有评论(0)