常见的社区资源主要是wiki,沟通类的工具主要是mail list,以及IRC。
在做debian port时,主要会用到以下两个列表:
windows建议使用 x-chat2,轻巧灵活,目前我个人是在将就着使用,更多更高级的用法还没有探索。
linux下我知道有一个issri,使用的是terminal。如果有桌面环境系统,最好还是使用发行版中自带的客户端,好处时你的IRC如果因为网络环境等因素的话,图形界面的客户端在某种程度上是可以帮你保留过往的聊天记录。这一点是很多terminal做不到的(也许是我没有设置有效的配置)。
具体的频道为
接下来的内容是介绍如何在Debian 11(bulleyes)下创建schroot并使用sbuild搭建riscv的交叉编译环境,宿主机为amd64(为了叙述方便,下面统一使用host代指,有时在构建具体的deb时会指明 –host=riscv64,这一点尤为注意).
host os环境如下
lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 11 (bullseye)
Release: 11
Codename: bullseye
apt install buildd
这一章节主要参考 Set_up_a_chroot.
正如文章题目所示,这篇文章我们介绍如何使用sbuild-createchroot
命令去创建chroot,尽管还有诸如debootstrap, mksbuild, multistrap, pbuilder create的工具也可以创建(这些工具会在后面逐一解锁)。
sbuild-createchroot
其实也是debootstrap
命令的上层封装,根据前者的help手册:
sbuild-createchroot runs debootstrap(1) to create a chroot suitable for building packages with sbuild. Note that while debootstrap may be used di‐rectly, sbuild-createchroot performs additional setup tasks such as adding additional packages and configuring various files in the chroot. Invok‐ing sbuild-createchroot is functionally equivalent to running debootstrap --variant=buildd --include=fakeroot,build-essential, then editing /etc/apt/sources.list and /etc/hosts by hand
但是,还是建议在使用 sbuild-createchroot
时,使用mmdebstrap
去激活:
命令:
sudo apt install sbuild mmdebstrap
sudo sbuild-createchroot --debootstrap=mmdebstrap --arch=riscv64 \
--include=debian-ports-archive-keyring,ca-certificates \
--make-sbuild-tarball=/srv/sid-riscv64-sbuild.tgz \
sid /tmp/chroots/sid-riscv64-sbuild/ \
https://mirror.iscas.ac.cn/debian/
解释:命令sbuild-createchroot
会根据参数创建一个base chroot。--include=debian-ports-archive-keyring
是指我们后面在做port时,需要使用port的source list, 为了使用这个source list,需要我们安装一个keying,就是这个包(这里不加也没有关系,后面还有补救的办法);tarball
可以认为是一个rootfs(其实我也没有去核对,后面有了新的发现再回来改正), sid
是构建的chroot基于哪一个distributor version,后面的url是指定构建完成后chroot的源。执行完上面的命令,其chroot就是一个base的chroot,其包含sid的源,下面是具体的构建log(下载软件的info被忽略)
log:
...
mkdir /srv/chroots
mkdir /srv/chroots/sid
I: SUITE: sid
I: TARGET: /srv/chroots/sid
I: MIRROR: http://deb.debian.org/debian/
I: Running debootstrap --arch=amd64 --variant=buildd --verbose --include=fakeroot,build-essential --components=main --resolve-deps --no-merged-usr sid /srv/chroots/sid http://deb.debian.org/debian/ # 这里就是具体解析了这个命令
I: Target architecture can be executed
I: Retrieving InRelease
I: Checking Release signature
I: Valid Release signature (key id A7236886F3CCCAAD148A27F80E98404D386FA1D9)
I: Retrieving Packages
I: Validating Packages
I: Resolving dependencies of required packages...
I: Resolving dependencies of base packages...
I: Checking component main on http://deb.debian.org/debian...
I: Retrieving libacl1 2.3.1-1
I: Validating libacl1 2.3.1-1
I: Retrieving adduser 3.118
I: Configuring libc-bin...
I: Base system installed successfully.
I: Configured /etc/hosts:
+------------------------------------------------------------------------
|127.0.0.1 localhost
|::1 localhost ip6-localhost ip6-loopback
|ff02::1 ip6-allnodes
|ff02::2 ip6-allrouters
|
+------------------------------------------------------------------------
I: Configured /usr/sbin/policy-rc.d:
+------------------------------------------------------------------------
|#!/bin/sh
|echo "All runlevel operations denied by policy" >&2
|exit 101
+------------------------------------------------------------------------
I: Configured APT /etc/apt/sources.list:
+------------------------------------------------------------------------
|deb http://deb.debian.org/debian sid main
|deb-src http://deb.debian.org/debian/ sid main
|
+------------------------------------------------------------------------
I: Please add any additional APT sources to /srv/chroots/sid/etc/apt/sources.list # 不知道是不是可以直接修改这里
I: schroot chroot configuration written to /etc/schroot/chroot.d/sid-amd64-sbuild-bFkC6l.
+------------------------------------------------------------------------
|[sid-amd64-sbuild]
|description=Debian sid/amd64 autobuilder
|groups=root,sbuild
|root-groups=root,sbuild
|profile=sbuild
|type=file
|file=/srv/chroots/sid-sbuild.tgz
+------------------------------------------------------------------------
I: Please rename and modify this file as required.
mkdir /etc/sbuild/chroot
I: Setting reference package list.
I: Updating chroot.
Hit:1 http://deb.debian.org/debian sid InRelease
Get:2 http://deb.debian.org/debian sid/main Sources [9550 kB]
Fetched 9550 kB in 2s (5871 kB/s)
Reading package lists... Done
Reading package lists... Done
Building dependency tree... Done
Calculating upgrade... Done
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
I: Creating tarball...
I: Done creating /srv/chroots/sid-sbuild.tgz
I: chroot /srv/chroots/sid has been removed.
I: Successfully set up sid chroot.
I: Run "sbuild-adduser" to add new sbuild users.
-----------------
sudo sbuild-adduser vimer
Adding user `vimer' to group `sbuild' ...
Adding user vimer to group sbuild
Done.
# Setup tasks for sudo users:
# BUILD
# HOME directory in chroot, user:sbuild, 0770 perms, from
# passwd/group copying to chroot, filtered
# Maybe source 50sbuild, or move into common location.
Next, copy the example sbuildrc file to the home directory of each user and
set the variables for your system:
cp /usr/share/doc/sbuild/examples/example.sbuildrc /home/vimer/.sbuildrc
Now try a build:
cd /path/to/source
sbuild-update -ud <distribution>
(or "sbuild-apt <distribution> apt-get -f install"
first if the chroot is broken)
sbuild -d <distribution> <package>_<version>
上面的命令构建完了chroot还不算完整,我们得继续配置:
sudo sbuild-adduser <your-username>
这条命令能够让你当前的用户使用相关的sbuild命令。幸运的话,你就构建完了一个基本的chroot.可以使用以下命令确认下:
~$:sudo schroot -la
[sudo] password for vimer:
chroot:sid-amd64-sbuild
source:sid-amd64-sbuild
有人会奇怪这里为啥会是amd64
,这时构建rootfs时系统自动指定的,也就是所谓的默认。
解释一下这两个输出的区别:
一般情况下通常使用干净的chroot,如果只是默认使用“sid-amd64-sbuild”;这是默认的(注意,sbuild-shell
命令是一个例外,因为它隐式使用源代码:version,也就是使用sbuild-shell
的话,会污染原始的chroot tarball空间)。
这里就是说,比如我想手动hack这个sid,也就是把修改保留在chroot里,可以使用sbuild-shell
命令:
sudo sbuild-shell sid-amd64-sbuild # 这个参数,就是schroot 得来的,千万别混淆
另外,如果使用上述的命令,你会发现bash相当难用、用户主目录也不对。如果这个时候你想使用tab键补全命令也是不可能的。
这时,你可以编辑/etc/schroot/chroot.d/sid-amd64-sbuild-<id>
这个id每个人不一致的,改成以下配置:
profile=default
这个时候你再使用sbuild-shell
命令去login,发现就不一样了。
schroot -c sid-amd64-sbuild
其实,如果这个搞定了,是可以登录进来进行操作,总比qemu要强不少。
schroot -c sid-amd64-sbuild
或者首先使用
sudo schroot -c sid-amd64-sbuild
安装sudo的配置文件,才方便安装一些依赖软件什么的。
默认情况下,构建的apt源是在sbuild-createchroot命令行中给出的。在上面的例子中,我们使用的Debian的sid源。
因为我们现在的目标是port riscv,同时截止到现在(2022/02/),Debian并没有官方移植支持riscv的release版本,如果想要把riscv相关的toolchains安装到chroot里,需要添加Debian ports相应的源:
步骤:
sbuild-createchroot
创建的chroot默认没有太多的tools,可以手动安装你最喜爱的vim或其他:
sudo sbuild-apt sid-amd64-sbuild apt-get install vim.tiny
注: sbuild-apt
: run apt-get or apt-cache in an sbuild chroot
$ sudo sbuild-shell sid-amd64-sbuild
[sudo] password for vimer:
Useless use of a constant ("riscv64") in void context at (eval 16) line 1210.
I: /bin/sh
# cat /etc/apt/sources.list
# sid 源我们从一开始创建时就有,看上面的log
deb http://deb.debian.org/debian sid main
deb-src http://deb.debian.org/debian/ sid main
# 以下的ports sources是这次添加进来的,参看上面的解释或者以下的url:
# https://wiki.debian.org/RISC-V#Package_repository
deb http://ftp.ports.debian.org/debian-ports/ sid main
deb http://ftp.ports.debian.org/debian-ports/ unreleased main
deb-src http://ftp.ports.debian.org/debian-ports/ sid main
# vim添加完成后,在终端下执行 exit
# 退出 chroot
注意
: 不知道因为什么原因,ports的repository没有合法的签名文件,需要以下两种方式去fix这个问题,否则后面的使用apt update
时会遇到诸如下面的error:
E: The repository 'http://ftp.ports.debian.org/debian-ports sid InRelease' is not signed.
1.安装一个debian-ports-archive-keyring的debian package.
这里需要多说一句,通常这个时候,chroot可用的命令实际上很少的,需要我们自己先在host(x86)下载keying的deb包,然后我们使用sbuild-shell命令进入chroot后使用apt install
去安装这个包。具体方法如下:
# A. 绑定当前host的home目录与chroot的默认目录
# 在host上,主要是编辑这个软件: /etc/schroot/chroot.d/sid-amd64-sbuild-xx,然后把profile=subuild改为default 字段就可以。
# B. 进入你存放deb的目录下,然后安装就可以了:
sudo apt install -f ./debian-ports-archive-keyring_2019.11.05~deb10u1_all.deb
2.如果还是报找不到签名文件的错误,还可以使用下面的方式解决:
https://askubuntu.com/questions/732985/force-update-from-unsigned-repository
简单说就是在 sources.list 添加 ` [trusted=yes] ` 字段解决这个问题。但是不建议这么做,这本身是一种workround的方案。
添加完ports的源以后,这里可以执行apt update
也可以不执行。 It is up to you.
这里也很重要,我当时实验时就是因为没有相关的文档,卡在这里很长时间,直到后面在社区的帮助下,才搞定 :( 执行完上面的操作后, ` 退出`chroot,以下修改是host的操作。
编辑etc/sbuild/sbuild.conf
文件 and 把 $crossbuild_core_depends
变量打开(默认是注释掉的),
修改成以下内容:
$crossbuild_core_depends = {
riscv64 => [ "gcc-riscv64-linux-gnu", "g++-riscv64-linux-gnu",
"libstdc++-dev:riscv64", "libc-dev:riscv64" ]
};
由于我本身的理解问题,我这里并不能理解Hemlut的意思,他的原文是这样的:
...
I think you also need to change your
sbuild.conf and change $crossbuild_core_depends to include a mapping
riscv64 => [ "gcc-riscv64-linux-gnu", "g++-riscv64-linux-gnu",
"libstdc++-dev:riscv64", "libc-dev:riscv64" ]
as build-essential does not build a crossbuild-essential-$arch package
for ports.
大体的这个改动的意思是,我个人认为是: 告诉sbuild,如果被告知需要编译的arch为riscv64 (后面有相关的用法),则需要chroot自己使用ports源里面已有的riscv相关的toolchains,而不是 现场编译crossbuild-essential-$arch这个tool。
以上就是sbuild(chroot)相关的操作,如果一切顺利可以执行下面的操作。
tool(载体或者chroot)已经准备好了,我们得找一个合适的packages去做移植。引文聚焦riscv,所以我们以riscv为例。
FTBFS, packages that Fail To Build From Source (in riscv64) 是一个不错的开始,正如作者所说: “So it’s a nice place to start looking at things that need to be fixed” https://udd.debian.org/cgi-bin/ftbfs.cgi?arch=riscv64.
但是这里也不是那么容易找出来,有的是因为他们本身依赖的底层软件没有riscv的构建,形成了“猫吃尾巴”的圈圈。
除此之外,还可以看看 “Bugs (BTS) Usertags for user [email protected] (UDD):riscv64: all bugs related to the Debian riscv64 port”这块,尤其是UDD 中riscv64的标签.
这个issue list也挺好的,可以试一下。
在我看来,UDD的taged的软件其实有一些ports了,但是由于种种原因没有进行下去,我们可以pick一个进行实验。这里我选择是sofia-sip.
下载source code的第一步,首先是确认该软件应该属于那个release版本的源。这里也别考虑了,只要你手动hack的deb包,默认都应该是 sid。好,开搞!
sid就是unstable的别名,可以说就是在开发阶段的、未经大规模测试的deb包release version. 如果我们打算使用的sid的源,这里有两种方式(在host)上:
# ...
# 添加以下内容
deb http://deb.debian.org/debian sid main
deb-src http://deb.debian.org/debian/ sid main
但是这种方式可能会影响host的稳定, pabs不建议这么去做。但是我这么做了,因为他说的第二种方式我不知道如何去操作。
使能上面的其中一个方案后,请使用 apt update
去更新软件源。
添加完sid
源以后,执行以下命令:
mkdir build_test && cd build_test
sudo apt source sofia-sip
[sudo] password for vimer:
Reading package lists... Done
NOTICE: 'sofia-sip' packaging is maintained in the 'Git' version control system at:
git://git.debian.org/users/ron/sofia-sip.git
Please use:
git clone git://git.debian.org/users/ron/sofia-sip.git
to retrieve the latest (possibly unreleased) updates to the package.
Need to get 2,978 kB of source archives.
Get:1 http://deb.debian.org/debian sid/main sofia-sip 1.12.11+20110422.1-2.2 (dsc) [2,374 B]
Get:2 http://deb.debian.org/debian sid/main sofia-sip 1.12.11+20110422.1-2.2 (tar) [2,949 kB]
Get:3 http://deb.debian.org/debian sid/main sofia-sip 1.12.11+20110422.1-2.2 (diff) [27.0 kB]
Fetched 2,978 kB in 1s (3,911 kB/s)
dpkg-source: info: extracting sofia-sip in sofia-sip-1.12.11+20110422.1
dpkg-source: info: unpacking sofia-sip_1.12.11+20110422.1.orig.tar.gz
dpkg-source: info: applying sofia-sip_1.12.11+20110422.1-2.2.diff.gz
dpkg-source: info: upstream files that have been modified:
sofia-sip-1.12.11+20110422.1/libsofia-sip-ua/msg/msg_parser.c
sofia-sip-1.12.11+20110422.1/libsofia-sip-ua/su/sofia-sip/su_tag.h
sofia-sip-1.12.11+20110422.1/libsofia-sip-ua/su/su_port.h
W: Download is performed unsandboxed as root as file 'sofia-sip_1.12.11+20110422.1-2.2.dsc' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)
然后可以查看文件夹内容:
~$ls
sofia-sip-1.12.11+20110422.1 sofia-sip_1.12.11+20110422.1-2.2.diff.gz sofia-sip_1.12.11+20110422.1-2.2.dsc sofia-sip_1.12.11+20110422.1.orig.tar.gz
~$cd sofia-sip-1.12.11+20110422.1/
下载完代码我们就可以进行cross-build了:
这个时候你还需要安装一个必要的软件在host上(x86)(如果没有安装):
sudo apt install debhelper
执行:
sudo sbuild --host=riscv64 -d sid
这个命令是告诉sbuild,要构建riscv arch的deb包,在哪里呢?当然是基于咱们前面设置的chroot.-d
是确定distruation。
不出意外的话(2022/02/18),编译到最后会出现以下log:
...
dh_clean
debian/rules build-arch
dh_testdir
mkdir -p objs
cd objs && ../configure --host=riscv64-linux-gnu \
--build=x86_64-linux-gnu \
--prefix=/usr
checking build system type... x86_64-pc-linux-gnu
checking host system type... Invalid configuration `riscv64-linux-gnu': machine `riscv64' not recognized
configure: error: /bin/bash ../config.sub riscv64-linux-gnu failed
make: *** [debian/rules:35: objs/config.status] Error 1
dpkg-buildpackage: error: debian/rules build-arch subprocess returned exit status 2
其实出现这个才不可怕,这个行为是预期的,因为该软件包目前还不支持riscv64下的编译吗。
可以看一下这个log, tail of log:
fakeroot debian/rules clean
dh_testdir
dh_testroot
rm -f *-stamp
rm -f -r objs doc
dh_clean
debian/rules build-arch
dh_testdir
mkdir -p objs
cd objs && ../configure --host=riscv64-linux-gnu \
--build=riscv64-linux-gnu \
--prefix=/usr
checking build system type... Invalid configuration `riscv64-linux-gnu': machine `riscv64' not recognized
configure: error: /bin/bash ../config.sub riscv64-linux-gnu failed
make: *** [debian/rules:35: objs/config.status] Error 1
下一步就是如何根据这个log去修复它。
其实社区的相关人员已经提醒说,该包已经有相关的patch了 .即便如此,剩下的工作就是如何apply这个patch以及如何follow整个debian packages的workflow。
sudo rm -r /srv/chroot/unstable-amd64-sbuild/
sudo rm /etc/schroot/chroot.d/unstable-amd64-sbuild-* /etc/sbuild/chroot/unstable-amd64-sbuild
sudo schroot --end-session --all-sessions
这里有两种方式:区别是有没有加--foreigh
开关。
sudo debootstrap --arch=riscv64 --keyring /usr/share/keyrings/debian-ports-archive-keyring.gpg --include=debian-ports-archive-keyring unstable /tmp/riscv-chroot https://deb.debian.org/debian-ports/
执行完这个命令,就可以 chroot /tmp/riscv-chroot
进行下面的操作。
sudo debootstrap --foreign --arch=riscv64 --keyring /usr/share/keyrings/debian-ports-archive-keyring.gpg --include=debian-ports-archive-keyring unstable /tmp/riscv-chroot http://deb.debian.org/debian-ports
# 这没有完成,你得执行第二阶段,以下是第二阶段:
sudo mkdir -p /tmp/riscv-chroot/usr/bin/
sudo cp "$(which qemu-riscv64-static)" /tmp/riscv-chroot/usr/bin/
sudo chroot /tmp/riscv-chroot/ /debootstrap/debootstrap --second-stage
关于这个开关的介绍:
--foreign
> Do the initial unpack phase of bootstrapping only, for example if the tar‐
> get architecture does not match the host architecture. A copy of deboot‐
> strap sufficient for completing the bootstrap process will be installed as
> /debootstrap/debootstrap in the target filesystem. You can run it with the
> --second-stage option to complete the bootstrapping process.
sudo debootstrap --arch=riscv64 --keyring /usr/share/keyrings/debian-ports-archive-keyring.gpg --include=debian-ports-archive-keyring unstable /tmp/riscv-chroot https://deb.debian.org/debian-ports/
则这一步即可一步完成。
使用这个 sbuild-createchroot
其实是带了 --foreigh
的参数的:
sudo sbuild-createchroot --arch=riscv64 --foreign --keyring="" --include=debian-ports-archive-keyring --make-sbuild-tarball=/srv/sid-riscv64-sbuild.tgz sid /tmp/chroots/sid-riscv64-sbuild1/ http://ftp.ports.debian.org/debian-ports/
sbuild-createchroot
其实调用的也是debootstrap
,如果上面的想要能够工作起来,还得手动打target 包。
前面可以说是创建的amd64,这个创建的是riscv,解决一些依赖不能安装的问题。
因为我们创建的chroot可能由于某些软件的确实导致某些必须的packages没有安装进去,所以最好使用下面的命令
进行一个update && upgrade
:
sbuild-update -ud sid-riscv64-sbuild
有问题及时解决~
但是这个命令编译时需要特别一点:
sudo sbuild --host=riscv64 --build=riscv64 -d sid-riscv64-sbuild
This is very interesting!
Enjoy it!
1. 安装依赖(推荐在Debian host上):
sudo apt install -y qemu-user-static qemu-system qemu-utils qemu-system-misc binfmt-support 、
mmdebstrap sbuild dget
2. sudo sbuild-createchroot --debootstrap=mmdebstrap --arch=riscv64 \
--include=debian-ports-archive-keyring,ca-certificates \
--make-sbuild-tarball=/srv/sid-riscv64-sbuild.tgz \
sid /tmp/chroots/sid-riscv64-sbuild/ \
https://mirror.iscas.ac.cn/debian-ports
3. 添加用户组
sudo sbuild-adduser <your-username>
4. 新建目录后
dget -x https://deb.debian.org/debian/pool/main/g/golang-1.20/golang-1.20_1.20.1-1.dsc
cd golang-1.20-1.20/
5. 修改 debian/下的文件,也只能修改该目录下的文件,sbuild
sudo sbuild --arch=riscv64 -c sid-riscv64-sbuild --no-clean-source
假设
--source
可以解决这个问题
This happens because sbuild runs the “dh clean” (actually, the “debian/rules clean” target) step outside of the chroot, before the build actually starts. This means that sbuild expects you to have the build deps installed on your host.
This is usually not desirable/required, so you can tell sbuild to not clean the source tree by passing the –no-clean-source option to it, or by adding the line “$clean_source = 0;” to your ~/.sbuildrc.
当使用命令sbuild --arch=riscv64 -c sid-riscv64-sbuild
典型的一个报错类型是:
Failed to execute “/usr/bin/getent”: Exec format error
之所以出现这个错误,可能是由于我之前的一个操作把 qemu user的支持给搞乱了。根据这篇文章: https://askubuntu.com/questions/14280/during-a-chroot-attempt-i-got-this-error-chroot-failed-to-run-command-bin
sudo cp /usr/bin/qemu-arm-static /path/to/mount/usr/bin
#You may have to run
systemctl restart systemd-binfmt.service
才可以.
为了提前了解在 基于Debian的发行版上移植riscv软件的流程,以及为了帮助后面的同学快速融入这个社区,故总结以下信息。risc-v(以下简称riscv,暂时没有区分riscv32和riscv64)。
主要根据[email protected]搜集而来。 2016年11月份,Debian社区负责RISC-V 64移植的maintainer Manuel A. Fernandez Montecelo以及其他几位团队成员对于“riscv”在Debian上的名字还是有点争论的,期初他们叫lowriscv,想想在2016年,出现这样的情况也是合情合理。在讨论中,出现了RV64G, RV32IMA, RVBE64G和riscv64这样的命名争论,甚至还有人考虑到如何区分riscv的大小端,如 “mips64el’,有人也想通过后缀L(小端)或者B(大端)来区分。直到有个Fedora的家伙跑过来说,截止到2016年11月, Fedora已经移植2/3的packages,这时候争论才停止。类似的事情在Debian社区中较为常见,比如著名的Systemd争论。
Debian社区有一个想法值得注意:
In any case, good support for cross-compilation, for packages avoiding dependency cycles, to install packages that are needed only for arch:all(like doc), etc., will benefit RISC-V and other architectures in thefuture. (And I like the goals of rebootstrap, even in the absence ofRISC-V).
根据我自己的经验,debian package 中的arch字段可以控制deb可以安装到什么机器上,比如arm64, x86_64什么的。但是deb包中的app是如何做到跨平台的,这个需要我接下来探究一下。
(update /2022/02/18): 在我认真看了一下相关文档以及自己摸索,Debian目前可以借助 schroot等手段构建众多ISA的编译环境,相当于独立于host的一个container环境。而这个基本的构建环境,是可以在构建包的时候,指明arch的,比如riscv64。在编译过程中,schroot是可以自动下载当面isa的cross-built 的toolchains的。
回到上面这个问题,deb包支持的arch为all,一般是指配置、doc之类的,其他的比如包含binary的deb包这样去做,难度估计不小。
(时间因素,riscv port to Debian的历史演变后面继续更新)
该 wiki 基本上总结了在Debian上移植riscv的最新状态。
目前的Debian社区官方的软件包大约在22k个左右,riscv已经移植了大约95%,剩下的5%可能是因为llvm对riscv的支持不够造成的(2020年),连带着rust相关的软件编译也受到 一定影响。我需要去了解下目前block riscv移植的重要原因是什么。
Debian社区有一个page记录了当前在riscv64”机器”上编译受阻塞的软件,根据上面的wiki去复现编译log,同时向社区report自己的想法,避免做无用功。 除此之外,想要成为一名DD的话,需要从打包者 -> DM -> DD这样rule演进。这就需要自己主动的去维护那些 orphan deb packages。
今年的一个总体目标是:
根据 Debian ports,我们发现Debian官方(2022/02)支持9种arch架构,根据目前riscv64移植的进展,不知道让Debian官方支持应该达到什么条件。肯定的一点是,如果让官方支持,至少进入sid(unstable) release版本,还有多少具体的工作去做还未知。
update: 2022/02/25
这里揭示了如果让Debian关官方支持riscv需要的一些条件:
riscv64 won't become a release architecture for buster. There
are still a lot of things missing that are required for meeting
the release architecture criteria. The first step on a way to
becoming a release architecture would be having all packages in
the unstable suite and getting rid of unreleased, and that will
still take some time. We are also unfortunately missing upstream
support for riscv64 in LLVM which causes us quite a headache as
qt has moved to requiring LLVM for certain components in recent
releases, and qt has an enormous chain of reverse-dependencies.
Besides the software side, DSA has declared that they are only
going to accept architectures as release architecture that have
server-grade hardware with out-of-band management facilities
available on the market for DSA-maintained buildds. There is
no such hardware on the market for riscv64 yet, though.
这个需要与社区的Helmut与实验室的大力支持下一起去构建与维护。
只有经历过deb包的maintain,才有机会成为成为DM,甚至DD。
我们目前的工作是宏伟计划的一小部分,对Debian乃至riscv相关的同学可以私聊我,或者直接访问 plct github.
目前在看一个deb的service时发现,原来之前自己想要的结果可以通过这样的方式来实现,真的叹为惊叹。这里先记录下来,等到时间充分了,再一点一点吸收。
# the config of ROOT, user must modify it when start srs from other directory,
# it's ok to use the script by command ./etc/init.d/ossrs
ROOT="/usr/local/srs"
APP="./objs/srs"
CONFIG="./conf/srs.conf"
DEFAULT_PID_FILE='./objs/srs.pid'
DEFAULT_LOG_FILE='./objs/srs.log'
########################################################################
# utility functions
########################################################################
RED="\\033[31m"
GREEN="\\033[32m"
YELLOW="\\033[33m"
BLACK="\\033[0m"
POS="\\033[60G"
ok_msg() {
echo -e "${1}${POS}${BLACK}[${GREEN} OK ${BLACK}]"
}
failed_msg() {
echo -e "${1}${POS}${BLACK}[${RED}FAILED${BLACK}]"
}
# load process info of srs
# @set variable $srs_pid to the process id in srs.pid file.
# @return 0, if process exists; otherwise:
# 1, for pid file not exists.
# 2, for get proecess info by pid failed.
# @set variable $error_msg if error.
# @set variable $pid_file to pid file.
load_process_info() {
# get pid file
pid_file=`cd ${ROOT} && cat ${CONFIG} |grep ^pid|awk '{print $2}'|awk -F ';' '{print $1}'`
if [[ -z $pid_file ]]; then pid_file=${DEFAULT_PID_FILE}; fi
# get abs path
pid_dir=`dirname $pid_file`
pid_file=`(cd ${ROOT}; cd $pid_dir; pwd)`/`basename $pid_file`
srs_pid=`cat $pid_file 2>/dev/null`
ret=$?; if [[ 0 -ne $ret ]]; then error_msg="No pid file $pid_file"; return 1; fi
ps -p ${srs_pid} >/dev/null 2>/dev/null
ret=$?; if [[ 0 -ne $ret ]]; then error_msg="Process $srs_pid does not exists"; return 2; fi
return 0;
}
start() {
# if exists, exit.
load_process_info
if [[ 0 -eq $? ]]; then failed_msg "SRS started(pid ${srs_pid}), should not start it again."; return 1; fi
# not exists, start server
ok_msg "Starting SRS..."
# get log file
log_file=`cd ${ROOT} && cat ${CONFIG} |grep '^srs_log_file'| awk '{print $2}'| awk -F ';' '{print $1}'`
if [[ -z $log_file ]]; then log_file=${DEFAULT_LOG_FILE}; fi
# get abs path
log_dir=`dirname $log_file`
log_file=`(cd ${ROOT} && cd $log_dir && pwd)`/`basename $log_file`
# TODO: FIXME: set limit by, for instance, "ulimit -HSn 10000"
if [[ -z $log_file ]]; then
(ulimit -c unlimited && cd ${ROOT}; ${APP} -c ${CONFIG} >/dev/null 2>&1)
else
(ulimit -c unlimited && cd ${ROOT}; ${APP} -c ${CONFIG} >> $log_file.sys 2>&1)
fi
# check again after start server
for ((i = 0; i < 5; i++)); do
# sleep a little while, for srs may start then crash.
sleep 0.1
load_process_info
ret=$?; if [[ 0 -ne $ret ]]; then
failed_msg "SRS start failed";
failed_msg "see $log_file";
return $ret;
fi
done
# check whether started.
load_process_info
ret=$?; if [[ 0 -eq $ret ]]; then ok_msg "SRS started(pid ${srs_pid})"; return 0; fi
failed_msg "SRS not started"
return $ret
}
stop() {
# not start, exit
load_process_info
if [[ 0 -ne $? ]]; then failed_msg "SRS not start."; return 0; fi
ok_msg "Stopping SRS(pid ${srs_pid})..."
# process exists, try to kill to stop normally
for((i=0;i<100;i++)); do
load_process_info
if [[ 0 -eq $? ]]; then
kill -s SIGTERM ${srs_pid} 2>/dev/null
ret=$?; if [[ 0 -ne $ret ]]; then failed_msg "send signal SIGTERM failed ret=$ret"; return $ret; fi
sleep 0.3
else
ok_msg "SRS stopped by SIGTERM"
# delete the pid file when stop success.
rm -f ${pid_file}
break;
fi
done
# process exists, use kill -9 to force to exit
load_process_info
if [[ 0 -eq $? ]]; then
kill -s SIGKILL ${srs_pid} 2>/dev/null
ret=$?; if [[ 0 -ne $ret ]]; then failed_msg "send signal SIGKILL failed ret=$ret"; return $ret; fi
ok_msg "SRS stopped by SIGKILL"
else
# delete the pid file when stop success.
rm -f ${pid_file}
fi
sleep 0.1
return 0
}
# get the status of srs process
# @return 0 if srs is running; otherwise, 1 for stopped.
status() {
load_process_info
ret=$?; if [[ 0 -eq $ret ]]; then ok_msg "SRS(pid ${srs_pid}) is running."; return 0; fi
failed_msg "Error: $error_msg"
return 1
}
reload() {
# not start, exit
load_process_info
if [[ 0 -ne $? ]]; then failed_msg "SRS not start."; return 0; fi
ok_msg "Reload SRS(pid ${srs_pid})..."
# process exists, reload it
kill -s SIGHUP ${srs_pid} 2>/dev/null
ret=$?; if [[ 0 -ne $ret ]]; then failed_msg "Reload SRS failed ret=$ret"; return $ret; fi
load_process_info
if [[ 0 -ne $? ]]; then failed_msg "SRS reload failed."; return $ret; fi
ok_msg "SRS reloaded"
return 0
}
logrotate() {
# not start, exit
load_process_info
if [[ 0 -ne $? ]]; then failed_msg "SRS not start."; return 0; fi
ok_msg "Reopen log file of SRS(pid ${srs_pid})..."
kill -s SIGUSR1 ${srs_pid}
ok_msg "Log rotated"
return 0
}
grace() {
# not start, exit
load_process_info
if [[ 0 -ne $? ]]; then failed_msg "SRS not start."; return 0; fi
ok_msg "Gracefully quit for SRS(pid ${srs_pid})..."
kill -s SIGQUIT ${srs_pid}
ok_msg "Gracefully quit"
return 0
}
menu() {
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status
;;
reload)
reload
;;
rotate)
logrotate
;;
grace)
grace
;;
*)
echo "Usage: $0 {start|stop|status|restart|reload|rotate|grace}"
echo " reload Apply log file by not restarting SRS"
echo " rotate For log rotate, to send SIGUSR1 to SRS to reopen the log file."
echo " grace For gracefully quit, to send SIGQUIT to SRS."
return 1
;;
esac
}
menu $1
code=$?
exit ${code}
这是一个可执行的shell,需要在 service启动这个服务。
cat service file
[Unit]
Description=The SRS Media Stream Cluster
After=network.target
[Service]
Type=forking
Restart=always
ExecStart=/etc/init.d/srs start
ExecReload=/etc/init.d/srs reload
ExecStop=/etc/init.d/srs stop
[Install]
WantedBy=multi-user.target
在上周五我们发布了新一版本的full image,到目前为止影响系统启动的crash问题暂时没有复现。下面,将本次调试的过程记录一下,以便后面遇到此类问题提供一些思路。
由于研发需要,我们需要出一版本新的full image,但是,相关同事反馈,full image flash后一直重启,连上debug口发现是kernel crash,内容和 https://forums.developer.nvidia.com/t/kernel-panic-when-starting-a-cuda-application-as-a-service/180724/6 一致(触发的api不同):
···
[ 3.434394] Call trace:
[ 3.436848] [<ffffff800808b9f8>] dump_backtrace+0x0/0x198
[ 3.436854] [<ffffff800808bfbc>] show_stack+0x24/0x30
[ 3.436858] [<ffffff800845abe8>] dump_stack+0xa0/0xc8
[ 3.436863] [<ffffff80081c0a00>] panic+0x12c/0x2a8
[ 3.436869] [<ffffff8008cbe228>] nvhost_scale_emc_debug_init.isra.12+0x128/0x1a0
[ 3.436872] [<ffffff8008cbe5d4>] nvhost_pod_event_handler+0x334/0x400
[ 3.436874] [<ffffff8008cbb4fc>] devfreq_add_device+0x284/0x408
[ 3.436876] [<ffffff8008cbb6e4>] devm_devfreq_add_device+0x64/0xc0
[ 3.437063] [<ffffff8000fc1080>] gk20a_scale_init+0xf0/0x190 [nvgpu]
[ 3.437233] [<ffffff8000fba2f8>] gk20a_pm_finalize_poweron+0x370/0x400 [nvgpu]
[ 3.437393] [<ffffff8000fba540>] gk20a_busy+0x1b8/0x4f0 [nvgpu]
[ 3.437398] [<ffffff800878becc>] pm_generic_runtime_resume+0x3c/0x58
[ 3.437401] [<ffffff800878e214>] __rpm_callback+0x74/0xa0
[ 3.437402] [<ffffff800878e274>] rpm_callback+0x34/0x98
[ 3.437404] [<ffffff800878f710>] rpm_resume+0x470/0x710
[ 3.437405] [<ffffff800878f9fc>] __pm_runtime_resume+0x4c/0x70
[ 3.437570] [<ffffff8000fba45c>] gk20a_busy+0xd4/0x4f0 [nvgpu]
[ 3.437724] [<ffffff8000f9bf1c>] gk20a_ctrl_dev_open+0x8c/0x168 [nvgpu]
[ 3.437727] [<ffffff8008261f6c>] chrdev_open+0x94/0x198
[ 3.437730] [<ffffff8008258918>] do_dentry_open+0x1d8/0x340
[ 3.437732] [<ffffff8008259ed0>] vfs_open+0x58/0x88
[ 3.437735] [<ffffff800826d3b0>] do_last+0x530/0xfd0
[ 3.437737] [<ffffff800826dee0>] path_openat+0x90/0x378
[ 3.437740] [<ffffff800826f450>] do_filp_open+0x70/0xe8
[ 3.437741] [<ffffff800825a394>] do_sys_open+0x174/0x258
[ 3.437744] [<ffffff800825a4fc>] SyS_openat+0x3c/0x50
[ 3.437746] [<ffffff8008083900>] el0_svc_naked+0x34/0x38
[ 3.437751] SMP: stopping secondary CPUs
[ 3.442246] Kernel Offset: disabled
...
在上面链接的后面,reporter提示说,必须将某些服务放到 nvpmodel.service后面才可以。那我们也无法断定是哪个service触发的这个crash。
SX12.001是上一版本的full image,肯定没问题。在xx的帮助下,我们烧录了SX12.002 ok,然后在SX12.003 重现crash,由此断定,该issue在SX12.003引入。然后在SX12.003的基础上,依次把agent 、demo app、lms、ems拿掉(实际拿掉2个),最终定位到是ems触发的crash。其实这个问题应该更早的想到,SX12.003是ems首次集成。
A. 拿掉ems后系统能正常启动就好说了,大概率是ems的service有问题,然后和大佬一起看了下问题,原始的ems是 After=dbus.socket.然后使用命令 systemd-analyze --order plot > boot.svg
可以看见详细的systemd的启动时间序列,dbus.socket明显是在nvpmodel service前面,
但是,现在的问题是,必须找到一个合适的时间让ems service启动。然后记得大佬说过,如果改为了 After=graphical,ems的启动慢的无法忍受,大约10min+,为什么呢?
我们把 ems的service放到 nvpmodel后面或者graphical后面,crash现象没有了! 说明改动是有效的。只是桌面系统起不来,看来还是有其他服务进程影响了桌面系统.
B. 在多次的实验中,偶尔会出现 bootup is not yet finished…以及 Startup finished in 3.515s (kernel) + 10min 4.683s (userspace) = 10min 8.198s 的提示,那么,如果详细的知道每个service启动花费的时间以及没有完成的service是不是好一些? 查了一下systemd的用法,还真有相关的命令。
...
user@linux:~$ systemd-analyze blame
10min 3.354s displaytouch.service
11.693s k3s.service
5.428s rc-local.service
3.185s dev-zram0.device
3.130s dev-zram1.device
3.123s docker.service
3.071s dev-zram2.device
3.039s dev-zram3.device
2.956s dev-zram5.device
2.953s dev-zram4.device
2.484s dev-nvme0n1p1.device
1.930s srs.service
1.353s apt-daily-upgrade.service
1.272s apt-daily.service
999ms udisks2.service
965ms nv-l4t-usb-device-mode.service
...
问题出在 displaytouch上面了,其他都是s级,这个是min级,而且还是如此之大。看一下 displaytouch service的内容:
[Unit]
Description=displaytouch
[Service]
Type=oneshot
PIDFile=/run/displaytouch.pid
#EnvironmentFile=/etc/systemd/displaytouch.conf
ExecStart=/etc/systemd/touch.sh
[Install]
WantedBy=multi-user.target
该service调用的脚本是一个10min的loop查询,结合上面的启动时间,该service应该是等待脚本执行完毕后才返回状态,这样应该不可以。详细了解下 service unit的type,发现oneshot就是阻塞模式,使用forking或者simple都可以。故改为:
[Unit]
Description=displaytouch
[Service]
Type=simple
PIDFile=/run/displaytouch.pid
#EnvironmentFile=/etc/systemd/displaytouch.conf
ExecStart=/etc/systemd/touch.sh
[Install]
WantedBy=graphical.target
这样,再次使用 systemd-analyze blame命令查看,发现系统service的启动时间控制在s级别以下。然后把ems的service该为:
[Unit]
Description=e-Media service
After=multi-user.target
[Service]
Environment=DISPLAY=:0
ExecStart=/bin/bash -c "USERNAME=$(cat /etc/passwd | grep home | grep 1000 | cut -d: -f1); sudo -u $USERNAME /usr/bin/eswin/ems;"
Type=forking
Restart=on-failure
RestartSec=5
StartLimitInterval=0
[Install]
WantedBy=graphical.target
系统的multi-user.target启动时间在graphical.target前,故我们把ems放在multi-user之后,graphical之前;现在的现象是 系统可以正常flash,桌面可以正常启动,但是ems的service没有正常启动;
C. 在大佬的建议下,看了一下 /var/log/ems的log,发现有一个 “fail to get SN”的信息,经过沟通得知,ems需要这个信息。但是,ems是经过deb安装的,如果,通过SUP安装,这是真机安装,在deb的脚本中执行相关命令是可以得到SN并写入到目标文件中去,但是 full image安装ems的deb时是通过chroot的方式安装的deb,这样是得不到系统的SN号的,也就是说,ems经过 full image flash后,第一次
启动后,ems执行程序默认得到SN是不行的,根本就没有那个文件。所以,我们的处理是在 rc.local文件中首先判断下有无ems需要的那个文件,如果没有则立即读取并写入相应的文件,这样才搞定了ems的自启动问题。
综上,就是解决这个问题的大体脉络。目前虽然解决了full image烧录的问题,但还是需要在系统运行中检验。如果总结下来的话,我们认为log真的太重要,尤其ems的log对我们的debug太重要了。
Base Qt 5.9
QT -= gui
CONFIG += c++11 console
CONFIG -= app_bundle
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += main.cpp
main.cpp:
// Qt头文件没有.h, 头文件和类名相同
#include <QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
return a.exec();
}
这个build下,就可以看见一个cmd窗口了。
在构建的第三步时选择 Base class,选择QWidget class。
在选择窗口会有 .pro
文件和Headers Sources Froms(ui文件)文件夹。
看下 .pro
文件:
QT += core gui
# 如果需要sql,则如下
# QT += sql
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = test2
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
剩下的就是看如何操控控件了。我们先放一个 Label和 Push Button到窗体上。
Display Widgets
窗体中拖拽Label 图标放到窗体上,然后在属性编辑器上修改其属性,属性编辑器上面是对象(Object)窗体,可以看出来继承关系。objectName表示组件的对象名称,界面上的每个组件都需要一个唯一的对象名称,以便引用。
Push Button的类名字QPushButton,objectName是btnClose
.
在界面设计时,对程序需要访问的组件修改其objectName,对于其他的则可不必了。
在信号与槽的窗体中(就是窗口下方,带加号、减号的那个窗体), 单击Add
按钮,会出现 sender, Signal, Receiver, Slot
一行输入栏。
单击Sender
选择 btnClose,Signal 选择clicked()
, Receiver选择窗体Widget, Slot选择close()
.
然后编译就可以出现app,点击close就可以关闭窗口了。
new -> project -> 第三步选择 base class QDialog,上面的类名为什么名字,就会生成什么名字的cpp,如QWDialog,则会生成qwdialog.cpp文件等(还有UI文件)。
这个demo的目的是创建一个可以修改字体的窗口。
首先在 input widgets中拖拽Plain Text Editor(类名<-QWDialog),对象名修改为txtEdit,编辑敲入文字: IT is my demo.
在Buttons窗口中取到Check Box, ObjectName为chkBoxUnder,类似拖拽三个check box。文字描述分别为 “Italic”和“BOLD”,同时修改objectName.
设置字体颜色: 在 Buttons窗口中取到 Radio Button,然后red black blue文字,并修改各自的objectName.
设置三个push button,确定 取消 退出。
objectName设置好了轻易不要改动。
A 为了将这些组件排列美观,最好使用组件布局,也就是说需要使用一些容器。如 QGroupBox,使用其把上面的分成2组。这是层次关系。
B 布局管理: 在UI设计中,组件面板有Layouts和Spacers两个组件面板。 比如,可以把三个PushButton的按钮放在Horizontal Layout下面,其会用红色框起来。这样 PushButton就可以完全以水平组合起来,放置在同一位置上。
C: 快速布局: 在2, 3步时使用 Group Box将三个按钮组合起来了,我们可以只点击Grouo Box,然后单击窗口上方的 水平 按钮,三个 组件 就会水平分布,并且改变外部的大小,也会改变组件的大小。
D: 然后选择最外层的窗体,单击 垂直 分布,就可以达到自动平铺的效果了。
伙伴关系设置快捷键的, Tab顺序控制tab的执行顺序。
信号 Signal就是在特定条件下被发射的事件。 如 PushButton最常见的信号就是鼠标单击发射的clicked()信号。 GUI编程的核心就是对界面上各组件的信号响应,只需要知道什么情况下发射哪些信号,合理地去响应和处理这些信号就行了。
Slot 槽就是对信号响应的函数。槽就是一个函数,和C++类似,可以定义在类的任何部分(public private protected等),可以具有任何参数,也可以被直接调用。唯一的区别就是: 槽函数可以与一个信号进行关联,当信号发射时,关联的槽函数被自动执行。
信号与槽关联使用 QObject::connect()函数进行关联的,其基本格式:
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()))
connect()是QObject类的一个静态函数, 而QObject是所有的Qt类的基类,在实际调用时可以忽略前面的QObject限定。
sender是发射信号的对象名称, signal是信号名称, receiver是接受信号的对象名称,slot()是槽函数的名称。
目标:
过程:
单击chkBoxUnder, 右键 go to slot, 第一步是选择信号,在那个方框下,有对象chkBoxUnder的所有信号。我们选择 clicked(bool), 这样会传递一个参数, 在响应代码里是可以直接利用这个参数。也会在qwdialog.h中添加一个private slots的槽函数声明:
class QWDialog : public QDialog
{
Q_OBJECT
public:
explicit QWDialog(QWidget *parent = 0);
~QWDialog();
// 自动添加部分
private slots:
void on_chkBoxUnder_clicked(bool checked);
private:
Ui::QWDialog *ui;
};
这时,代码就会跳转到qwdialog.cpp:生成以下代码:
void QWDialog::on_chkBoxUnder_clicked(bool checked)
{
}
我们完善这个处理函数。
void QWDialog::on_chkBoxUnder_clicked(bool checked)
{
QFont font = ui->txtEdit->font();
font.setUnderline(checked);
ui->txtEdit->setFont(font); // 需要回置
}
这里我们自己的代码没有看到connect在哪里,是有问题吗? 不是的,可以查看编译生成的ui_qwdialog.h文件(在工程文件下,可以find usage去找一下,编辑器里是发现不了的)
在setupUi
里面,有一个函数是这样的:QMetaObject::connectSlotsByName(QWDialog);
, 这条语句将搜索QWDialog界面上的所有组件,将信号与槽函数匹配起来,它假设的槽函数名称是:
void on_<objectName>_<signal name>(<signal parameters>)
将3个RadioButton的clicked()信号关联到一个槽函数, 在 QWDialog类的private slots部分增加一个槽函数:
void setTextFontColor();
然后在qwdialog.cpp中实现具体函数(方法是在.h的slot部分, 右击->refactor->add definition in xx.cpp)就可以了。
具体显示如下:
void QWDialog::setTextFontColor()
{
QPalette plet = ui->txtEdit->palette(); // unknown usgae
if (ui->rBtnBlue->isChecked())
plet.setColor(QPalette::Text, Qt::blue);
else if (ui->rBtnBlack->isChecked())
plet.setColor(QPalette::Text, Qt::black);
else if (ui->rBtnRed->isChecked())
plet.setColor(QPalette::Text, Qt::red);
else
plet.setColor(QPalette::Text, Qt::black);
ui->txtEdit->setPalette(plet);
}
由于是自定义的槽函数,并不会自动与RadioButton进行关联,需要在QWDialog的构造函数中进行手工关联,代码如下:
QWDialog::QWDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::QWDialog)
{
ui->setupUi(this);
// 以下内容为删除部分 :
connect(ui->rBtnBlack, SIGNAL(clicked()), this, SLOT(setTextFontColor()));
connect(ui->rBtnBlue, SIGNAL(clicked()), this, SLOT(setTextFontColor()));
connect(ui->rBtnRed, SIGNAL(clicked()), this, SLOT(setTextFontColor()));
}
此时编译后就可以改变字体颜色了。
还有 确定 取消 退出三个按钮。字如其意,最后的结果都是退出窗体。
过程: QWDialog是从QDialog继承过来的, QDialog提供了accept() reject() close()等槽函数来表示这三种状态,所以只需要将clicked()信号与相应的槽函数进行关联即可。
demo finish。
如果是一个已经存在的qt项目,可以使用open目前的目录就可以。
在 .pro文件中可以定义这些,注意自己的头文件放置位置。
code:
#-------------------------------------------------
#
# Project created by QtCreator 2021-03-02T15:53:39
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = AgoraCall3
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
...
devicestestworker.cpp \
capturedesktopworker.cpp
HEADERS += \
agoracall.h \
playmediaworker.h \
captureaudioworker.h \
capturevideoworker.h \
...
capturedesktopworker.h
FORMS += \
agoracall.ui \
dialogstreamsetting.ui \
localwindow.ui \
dialogdevicestest.ui
INCLUDEPATH = += /usr/include/eswin ../agora_sdk ../agora_sdk/include ../include .
contains(QMAKE_HOST.arch, aarch64) {
LIBS += -L/usr/lib/eswin/aarch64 -leswinsdk -L../agora_sdk/lib/aarch64 -lagora_rtc_sdk
QMAKE_RPATHDIR +=/usr/lib/eswin/aarch64 ../agora_sdk/lib/aarch64
} else {
LIBS += -L/usr/lib/eswin/x86_64 -leswinsdk -L../agora_sdk/lib/x86_64 -lagora_rtc_sdk
QMAKE_RPATHDIR +=/usr/lib/eswin/x86_64 ../agora_sdk/lib/x86_64
}
QMAKE_CXXFLAGS += -DTARGET_OS_LINUX=1 -DLICENSE_CHECK=1 -Wno-sign-compare -Wno-reorder -Wno-unused-variable -Wno-unused-parameter
TRANSLATIONS = AgoraCall_zh_CN.ts
CODECFORSRC = UTF-8
DESTDIR = ../009_QtAgoraCall3 # release 放置的路径
比如我首先尝试一个 QPushButton 的按钮,名为 btnClose,那么,这个事件通知是通过 Sender Slot来进行描述的。
Sender就是这个按钮的名字,是选择的; Signal 是定义用户的行为;Receiver是QT接收到按键之后的行为;Slot()是系统表现出来的。
#include