fedora 打包 wechat RPM 包

构建流程

预安装

安装必要的工具

sudo dnf install gcc rpm-build rpm-devel rpmlint make python bash coreutils diffutils patch rpmdevtools -y

初始化构建目录

rpmdev-setuptree

在家目录下会生成一个文件夹 rpmbuild

[root@fedora ~]# tree ~/rpmbuild/
/root/rpmbuild/
├── BUILD
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS

创建 spec 文件

前往 ~/rpmbuild/SPECS 下,使用 rpmdev-newspec 可以基于默认模板生成一份 spec 文件

rpmdev-newspec -o pkg-name.spec

构建

使用 rpmbuild 命令可以立即构建rpm包

rpmbuild -b[action] pkg-name.spec

其中 [action] 是构建动作,有以下几个选项

选项 说明
-bp #只执行spec的%pre 段(解开源码包并打补丁,即只做准备)
-bc #执行spec的%pre和%build 段(准备并编译)
-bi #执行spec中%pre,%build与%install(准备,编译并安装)
-bl #检查spec中的%file段(查看文件是否齐全)
-ba #建立源码与二进制包(常用)
-bb #只建立二进制包(常用)
-bs #只建立源码包

构建细节

源包

源包: https://github.com/vufa/deepin-wine-wechat-arch

解包后,目录层级如下:

[x@fedora 下载]$ tree fedora-deepin-wechat-3.4.0.38
fedora-deepin-wechat-3.4.0.38
├── opt
│   └── apps
│       └── com.qq.weixin.deepin
│           └── files
│               ├── dlls
│               │   ├── gdi32.dll.so
│               │   ├── gdi32.so
│               │   ├── gdiplus.dll.so
│               │   ├── imm32.dll.so
│               │   ├── ntdll.dll.so
│               │   ├── ntdll.so
│               │   ├── ole32.dll.so
│               │   ├── qcap.dll.so
│               │   ├── qcap.so
│               │   ├── user32.dll.so
│               │   ├── user32.so
│               │   ├── winex11.drv.so
│               │   └── ws2_32.dll.so
│               ├── files.7z
│               ├── files.md5sum
│               └── run.sh
└── usr
    └── share
        ├── applications
        │   └── com.qq.weixin.deepin.desktop
        └── icons
            └── hicolor
                ├── 16x16
                │   └── apps
                │       └── com.qq.weixin.deepin.svg
                ├── 24x24
                │   └── apps
                │       └── com.qq.weixin.deepin.svg
                ├── 32x32
                │   └── apps
                │       └── com.qq.weixin.deepin.svg
                ├── 48x48
                │   └── apps
                │       └── com.qq.weixin.deepin.svg
                └── 64x64
                    └── apps
                        └── com.qq.weixin.deepin.svg

20 directories, 20 files

查看项目入口

查看起动器: usr/share/applications/com.qq.weixin.deepin.desktop

#!/usr/bin/env xdg-open

[Desktop Entry]
Encoding=UTF-8
Type=Application
X-Created-By=Deepin WINE Team
Categories=chat;Network;
Icon=com.qq.weixin.deepin
Exec="/opt/apps/com.qq.weixin.deepin/files/run.sh"
Name=WeChat
Name[zh_CN]=微信
Comment=Tencent WeChat Client on Deepin Wine
StartupWMClass=wechat.exe
MimeType=

可以知道 程序运行入口是 opt/apps/com.qq.weixin.deepin/files/run.sh

查看 run.sh 文件

#!/bin/sh

#   Copyright (C) 2016 Deepin, Inc.
#
#   Author:     Li LongYu <lilongyu@linuxdeepin.com>
#               Peng Hao <penghao@linuxdeepin.com>

#               Vufa <countstarlight@gmail.com>

version_gt() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"; }

BOTTLENAME="Deepin-WeChat"
APPVER="3.2.1.154deepin14"
WINEPREFIX="$HOME/.deepinwine/$BOTTLENAME"
WECHAT_VER="3.4.0.38"
EXEC_PATH="c:/Program Files/Tencent/WeChat/WeChat.exe"
START_SHELL_PATH="/opt/deepinwine/tools/run_v4.sh"
WECHAT_INSTALLER="WeChatSetup"
WECHAT_INSTALLER_PATH="c:/Program Files/Tencent/$WECHAT_INSTALLER-$WECHAT_VER.exe"
export MIME_TYPE=""
export DEB_PACKAGE_NAME="com.qq.weixin.deepin"
export APPRUN_CMD="deepin-wine5"
DISABLE_ATTACH_FILE_DIALOG=""

export SPECIFY_SHELL_DIR=`dirname $START_SHELL_PATH`

ARCHIVE_FILE_DIR="/opt/apps/$DEB_PACKAGE_NAME/files"

export WINEDLLPATH=/opt/$APPRUN_CMD/lib:/opt/$APPRUN_CMD/lib64

export WINEPREDLL="$ARCHIVE_FILE_DIR/dlls"

OpenWinecfg()
{
    env WINEPREFIX=$WINEPREFIX $APPRUN_CMD winecfg
}

Run()
{
    if [ -z "$DISABLE_ATTACH_FILE_DIALOG" ];then
        export ATTACH_FILE_DIALOG=1
    fi

    if [ -n "$EXEC_PATH" ];then
        if [ ! -f "$WINEPREFIX/reinstalled" ];then
            # run installer
            env WINEDLLOVERRIDES="winemenubuilder.exe=d" $START_SHELL_PATH $BOTTLENAME $APPVER "$WECHAT_INSTALLER_PATH" "$@"
            touch $WINEPREFIX/reinstalled
        else
            if [ -z "${EXEC_PATH##*.lnk*}" ];then
                $START_SHELL_PATH $BOTTLENAME $APPVER "C:/windows/command/start.exe" "/Unix" "$EXEC_PATH" "$@"
            else
                $START_SHELL_PATH $BOTTLENAME $APPVER "$EXEC_PATH" "$@"
            fi
        fi
    else
        $START_SHELL_PATH $BOTTLENAME $APPVER "uninstaller.exe" "$@"
    fi
}

HelpApp()
{
    echo " Extra Commands:"
    echo " winecfg        Open winecfg"
    echo " -h/--help      Show program help info"
}

if [ -z $1 ]; then
    Run "$@"
    exit 0
fi
case $1 in
    "winecfg")
        OpenWinecfg
        ;;
    "-h" | "--help")
        HelpApp
        ;;
    *)
        Run "$@"
        ;;
esac
exit 0

依赖解决

从上面的 run.sh 可以知道 启动依赖 START_SHELL_PATH, 他依赖到了一个shell /opt/deepinwine/tools/run_v4.sh

明显,我们的系统没有,需要解决一下这个依赖。他由deb包 link 提供。我们需要先单独对他打包。

打包 deepin-wine-helper

下载 deepin-wine-helper 的deb包 点击这里下载

解包deb后 得到 data.tar.xz 目录如下:

[x@fedora 下载]$ tree fedora-deepin-wine-helper
fedora-deepin-wine-helper
├── opt
│   └── deepinwine
│       └── tools
│           ├── add_hotkeys
│           ├── fontconfig
│           ├── get_tray_window
│           ├── kill.sh
│           ├── log.sh
│           ├── map_device.sh
│           ├── QQGameRunner
│           ├── register_font.sh
│           ├── run.sh
│           ├── run_v2.sh
│           ├── run_v3.sh
│           ├── run_v4.sh
│           ├── sendkeys.exe
│           ├── sendkeys.sh
│           ├── SetDpi.sh
│           └── updater
└── usr
    └── share
        └── doc
            └── deepin-wine-helper
                ├── changelog.Debian.gz
                └── copyright

查看 opt/deepinwine/tools/run_v4.sh 这是 wechat 启动shell所依赖的

发现第十三行 WINE_CMDdeepin-wine 有问题 修正一下

WINE_CMD="deepin-wine5"

看到脚本末尾 是执行该脚本的入口

BOTTLENAME="$1"
WINEPREFIX="$HOME/.deepinwine/$1"
APPDIR="/opt/apps/${DEB_PACKAGE_NAME}/files"
if [ -f "$APPDIR/files.md5sum" ];then
    APPVER="$(cat $APPDIR/files.md5sum)"
else
    APPVER="$2"
fi

debug_log "Run $*"

#执行lnk文件通过判断第5个参数是否是“/Unix”来判断
if [ "$4" == "/Unix" ];then
    RunApp "$3" "$4" "$5"
    exit 0
fi

if [ $# -lt 4 ]; then
    RunApp "$3"
    exit 0
fi
case $4 in
    "-r" | "--reset")
        ResetApp
        ;;
    "-c" | "--create")
        CreateBottle
        ;;
    "-e" | "--remove")
        RemoveApp
        ;;
    "-u" | "--uri")
        ParseArgs "$@"
        ;;
    "-f" | "--file")
        ParseArgs "$@"
        ;;
    "-h" | "--help")
        HelpApp
        ;;
    *)
        echo "Invalid option: $4"
        echo "Use -h|--help to get help"
        exit 1
        ;;
esac
exit 0

我们从上面的 opt/apps/com.qq.weixin.deepin/files/run.sh 可以知道执行时, 运行的命令为:

if [ -n "$EXEC_PATH" ];then
        if [ ! -f "$WINEPREFIX/reinstalled" ];then
            # run installer
            env WINEDLLOVERRIDES="winemenubuilder.exe=d" $START_SHELL_PATH $BOTTLENAME $APPVER "$WECHAT_INSTALLER_PATH" "$@"
            touch $WINEPREFIX/reinstalled
        else
            if [ -z "${EXEC_PATH##*.lnk*}" ];then
                $START_SHELL_PATH $BOTTLENAME $APPVER "C:/windows/command/start.exe" "/Unix" "$EXEC_PATH" "$@"
            else
                $START_SHELL_PATH $BOTTLENAME $APPVER "$EXEC_PATH" "$@"
            fi
        fi
    else
        $START_SHELL_PATH $BOTTLENAME $APPVER "uninstaller.exe" "$@"
    fi

所以我们最终会执行到

$START_SHELL_PATH $BOTTLENAME $APPVER "$EXEC_PATH" "$@"

对应的 opt/deepinwine/tools/run_v4.sh 脚本是

if [ $# -lt 4 ]; then
    RunApp "$3"
    exit 0
fi

接着,我们分析 RunApp 函数。看如下代码

RunApp()
{
    progpid=$(ps -ef | grep "zenity --progress --title=${BOTTLENAME}" | grep -v grep)
    debug_log "run ${BOTTLENAME} progress pid $progpid"
    if [ -n "$progpid" ]; then
        debug_log "$BOTTLENAME is running"
        exit 0
    fi
     if [ -d "$WINEPREFIX" ]; then
        UpdateApp | progressbar "$BOTTLENAME" "更新$BOTTLENAME中..."
     else
        DeployApp | progressbar $BOTTLENAME "初始化$BOTTLENAME中..."
     fi
    CallApp "$@"
}

由于我们 $WINEPREFIX~/.deepinwine/Deepin-WeChat 当文件夹存在的时候, 会执行一次 UpdateApp 不存在就会执行一次 DeployApp 最后执行 CallApp "$@" 调用起程序。

我们看 CallApp 函数[下面做了简化],通过 $BOTTLENAME 走到了 CallWeChat "$@" 我们继续跟踪 CallWeChat

CallApp()
{
    FixLink
    debug_log "CallApp $BOTTLENAME arg count $#: $*"

    case $BOTTLENAME in
        "Deepin-WeChat")
            CallWeChat "$@"
            ;;
        *)
            CallProcess "$@"
            ;;
    esac
}

跟踪一下 CallWeChat 代码如下:

CallWeChat()
{
    debug_log "Disable auto update"
    _DeleteRegistry "HKCU\\Software\\Tencent\\WeChat" "UpdateFailCnt"
    _DeleteRegistry "HKCU\\Software\\Tencent\\WeChat" "NeedUpdateType"
    rm "${WINEPREFIX}/drive_c/users/${USER}/Application Data/Tencent/WeChat/All Users/config/configEx.ini"

    export DISABLE_RENDER_CLIPBOARD=1
    export ATTACH_FILE_DIALOG=1
    CallProcess "$@"
}

由于项目执行目录未被创建,所以我们需要手动修正一下shell,追加如下内容到函数的顶部:

 if [ ! -f "$WINEPREFIX/drive_c/Program Files/Tencent/WeChat/Wechat.exe" ]; then
        echo "deploy wechat app."
        DeployApp | progressbar $BOTTLENAME "初始化$BOTTLENAME中..."
        mkdir $WINEPREFIX/drive_c/Program\ Files/Tencent/WeChat
        cp $WINEPREFIX/drive_c/Program\ Files/Tencent/WeChatSetup-* $WINEPREFIX/drive_c/Program\ Files/Tencent/WeChat/Wechat.exe
    fi

所以最终的 CallWeChat 修正后应该长这个样子

CallWeChat()
{
    if [ ! -f "$WINEPREFIX/drive_c/Program Files/Tencent/WeChat/Wechat.exe" ]; then
        echo "deploy wechat app."
        DeployApp | progressbar $BOTTLENAME "初始化$BOTTLENAME中..."
        mkdir $WINEPREFIX/drive_c/Program\ Files/Tencent/WeChat
        cp $WINEPREFIX/drive_c/Program\ Files/Tencent/WeChatSetup-* $WINEPREFIX/drive_c/Program\ Files/Tencent/WeChat/Wechat.exe
    fi
    debug_log "Disable auto update"
    _DeleteRegistry "HKCU\\Software\\Tencent\\WeChat" "UpdateFailCnt"
    _DeleteRegistry "HKCU\\Software\\Tencent\\WeChat" "NeedUpdateType"
    rm "${WINEPREFIX}/drive_c/users/${USER}/Application Data/Tencent/WeChat/All Users/config/configEx.ini"

    export DISABLE_RENDER_CLIPBOARD=1
    export ATTACH_FILE_DIALOG=1
    CallProcess "$@"
}

deepin-wine-helper 构建

修正好上面的代码后,我们开始构建 deepin-wine-helper 编辑一份 rpm package spec:

Name:           fedora-deepin-wine-helper
Version:        5.1.27
Release:        1%{?dist}
Summary:        Deepin Wine Helper

License:        extra
URL:            http://www.linuxdeepin.com/
Source0:        fedora-deepin-wine-helper-%{version}.tar.gz

# BuildRequires:  
# Requires:       

%description
Deepin Wine Helper


%prep
%setup -q


%build
%global debug_package %{nil}


%install
cd %_builddir/fedora-deepin-wine-helper-%{version}/
cp -r ./ %{buildroot}/


%files
%defattr (-,root,root)
%{_prefix}/share/*
/opt/deepinwine/tools/*


%changelog
* Mon, 19 Jul 2021 09:51:32 +0800 Cui Jiajin <cuijiajin@uniontech.com>  
- update
* Fri, 05 Jun 2020 15:39:03 +0800 Cui Jiajin <cuijiajin@uniontech.com>  
- Initial release 

wechat的构建中

编辑构建 wechat 包的 rpm package spec:

Name:           fedora-deepin-wechat
Version:        3.4.0.38
Release:        1%{?dist}
Summary:        Deepin Wechat

License:        proprietary
URL:            https://weixin.qq.com
Source0:        fedora-deepin-wechat-%{version}.tar.gz

# BuildRequires:  fedora-deepin-wine5
Requires:       fedora-deepin-wine5 wine

%description
Deepin打包的微信容器(com.qq.weixin.deepin)移植到Fedora

%prep
%setup -q


%build
%global debug_package %{nil}


%install
rm -rf $RPM_BUILD_ROOT
cd %_builddir/fedora-deepin-wechat-%{version}/
cp -r ./ %{buildroot}/


%files
%defattr (-,root,root)
%{_prefix}/share/*
/opt/apps/com.qq.weixin.deepin/files



%changelog
* Thu Nov 04 2021 root
- 

打包既可。

参考

RPM Packaging Guide