QEMU下的qt开发环境构建

构建与运行

环境准备

首先,安装必要的宿主机依赖包:

sudo apt update
sudo apt install build-essential libncurses5-dev rsync git bc qemu-system-arm qemu-utils

获取并配置 Buildroot

建议使用官方预设的 qemu_arm_vexpress_defconfig,它是最稳定的 ARM 模拟器配置。

# 下载 Buildroot (我们使用2019.11.x分支)
git clone -b 2019.11.x --single-branch https://github.com/buildroot/buildroot.git
cd buildroot

# 使用 ARM VExpress 配置
make qemu_arm_vexpress_defconfig

配置 QT 和 图形支持

为了能跑 QT 并支持 Framebuffer,需要进入菜单进行微调:

make menuconfig

在菜单中勾选以下关键项:

  • Target options -> Target Architecture Variant: 选 Cortex-A7
  • Toolchain -> Custom kernel headers series: 选 5.3.x
  • Toolchain -> C library: 选 glibc
  • Toolchain -> Enable C++ support: 选中。
  • Kernel -> Kernel version: 选 Latest version (5.3)
  • Target packages -> Graphic libraries and applications:
  • 勾选 Qt5
  • 勾选 qt5base -> 勾选 gui module -> 勾选 widgets module
  • 勾选 qt5base -> 勾选 linuxfb support
  • 勾选 qt5base -> 勾选 PNG support / JPEG support

  • System configuration -> Root password: 设置一个密码(如 123),方便登录。

4. 编译

编译过程会下载交叉编译器并构建整个系统。

# 使用多核编译(例如 8 核)
make -j$(nproc)


在 QEMU 中运行

编译完成后,在 output/images/ 目录下会生成:

  • zImage (内核)
  • vexpress-v2p-ca9.dtb (设备树)
  • rootfs.ext2 (根文件系统)

使用以下脚本启动 QEMU:

qemu-system-arm -M vexpress-a9 \
    -cpu cortex-a15 \
    -m 512M \
    -kernel output/images/zImage \
    -dtb output/images/vexpress-v2p-ca9.dtb \
    -drive file=output/images/rootfs.ext2,if=sd,format=raw \
    -append "console=ttyAMA0 root=/dev/mmcblk0 rw video=VGA-1:800x480-16" \
    -net nic -net user,hostfwd=tcp::2222-:22 \
    -vga std \
    -serial mon:stdio

注:如果你是在纯终端(无桌面)的 Ubuntu 下运行,请移除 -display gtk 并使用 -vnc :0


在模拟器中运行 QT 程序

进入系统后(用户名 root),你可以直接运行自带的 QT 示例程序:

# 运行并指定使用 linuxfb 驱动
/usr/lib/qt/examples/widgets/widgets/calculator/calculator -platform linuxfb

空间大小

在 Buildroot 的默认配置中,SD 卡镜像(rootfs.ext2)的大小通常是自动生成的,它会根据你勾选的包多少,自动计算出一个刚好能装下所有文件的最小容量。

但在实际开发(尤其是配合 QtCreator 和 QEMU 调试)时,有几个关于“大小”的关键点你需要注意:

1. 默认大小可能不够用

Buildroot 默认生成的 rootfs.ext2 往往只有几十 MB,剩下的空余空间极小。 如果你想通过 QtCreator 远程部署(Deploy)一个几十 MB 的 Qt 程序,或者在运行过程中产生日志,可能会报 "No space left on device"

2. 如何手动指定大小

如果你需要给 SD 卡预留一些空间存放调试程序,建议在 make menuconfig 中手动指定一个固定大小(例如 512MB):

  • 路径: Filesystem images --->
  • 找到 exact size (或者 Size of the generated image)
  • 输入:512M (或者根据你的需求输入,比如 1G)

这样生成的 rootfs.ext2 就会有足够的空余空间让你折腾。


3. QEMU 挂载时的注意事项

在 QEMU 命令中,你使用的是 -drive file=output/images/rootfs.ext2,if=sd,format=raw

  • 物理模拟: QEMU 会把这个文件当成一张物理 SD 卡。
  • 动态扩容: 如果你不想重新编译 Buildroot 改变大小,也可以直接在 Ubuntu 宿主机上用命令给这个镜像文件“扩容”:
# 在镜像末尾增加 512MB 空间
qemu-img resize output/images/rootfs.ext2 +512M

注意:扩容后你可能需要在 QEMU 虚拟机里运行 resize2fs /dev/mmcblk0 来让文件系统识别新空间。


建议

为了调试方便,建议在 make menuconfig 里把 Filesystem images 的大小固定设置为 256M 或 512M

这样你在 QtCreator 里配置远程路径 /root/ 时,可以反复部署、替换二进制文件,而不用担心虚拟磁盘爆满导致的奇怪崩溃。

字体

在嵌入式 Linux 中,Qt 不会自带字体。如果没有字体,你的qt界面可能会显示,但上面的数字和文字会变成一个个空白方块或者完全不显示

为了让系统自适应字体并支持中文,建议在 Buildroot 中勾选字体包:

  1. 进入 make menuconfig
  2. 找到 Target packages -> Fonts, images and graphics
  3. 勾选 DejaVu fonts(最通用的开源字体)。
  4. 关键一步:回到 Target packages -> Graphic libraries and applications -> Qt5 -> qt5base
  5. 勾选 fontconfig support(这样 Qt 就会自动寻找系统中安装的所有字体,而不需要你指定目录)。

  6. 重新编译:make


qt例程运行

所有例程都在 /usr/lib/qt/examples/ 比如运行calculator

export QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0:size=800x480:offset=0x0
export QT_QPA_FONTDIR=/usr/share/fonts/dejavu
/usr/lib/qt/examples/widgets/widgets/calculator/calculator

增加ssh远程登陆

1. 配置 Buildroot 开启 OpenSSH

  1. 在 Buildroot 根目录下运行: make menuconfig
  2. 进入以下路径: Target packages ---> Networking applications ---> [*] openssh
  3. (可选)如果你希望系统启动时自动运行 SSH,请确保勾选了 openssh 后,Buildroot 会默认在 /etc/init.d/ 下生成 S50sshd 脚本。

2. 关键:允许 Root 直接登录

出于安全考虑,OpenSSH 默认禁止 root 用户通过密码登录。但在开发阶段(尤其是 QEMU 模拟),我们需要开启它,否则 Qt Creator 连接时会报 Permission denied

make menuconfig 中:

  • System configuration --->
  • [*] Root password (设置一个密码,比如 root 或留空)
  • 然后在 Target packages -> Networking applications -> openssh 下面,通常没有直接的“允许 root”勾选项,我们需要通过 Rootfs Overlay 或者手动修改。

手动修改 QEMU 中的配置文件** 可以在 QEMU 启动后直接修改:

  1. 执行 vi /etc/ssh/sshd_config
  2. 找到 #PermitRootLogin ... 这一行。
  3. 修改为:PermitRootLogin yes(注意去掉前面的 #)。
  4. 找到 #PasswordAuthentication yes,确保它是 yes
  5. 保存退出后,重启服务:/etc/init.d/S50sshd restart

3. 保存配置并编译

make

编译完成后,output/images/rootfs.ext2 会更新。


4. 在 QEMU 中映射端口

之前的启动参数里已经包含了端口映射: -net nic -net user,hostfwd=tcp::2222-:22

这代表:访问宿主机(Ubuntu)的 2222 端口,等于访问虚拟机的 22 端口。

5. 验证连接

在 Ubuntu 宿主机打开一个新终端,输入:

ssh root@localhost -p 2222

  • 提示:如果报错 Host key verification failed,是因为你之前可能运行过别的虚拟机占用了 2222 端口,执行 ssh-keygen -f "/home/zqboard/.ssh/known_hosts" -R "[localhost]:2222" 清除一下即可。

defconfig 文件

使用 buildroot 2019.11.x分支

BR2_arm=y
BR2_cortex_a7=y
BR2_ARM_FPU_VFPV3D16=y
BR2_TOOLCHAIN_BUILDROOT_GLIBC=y
BR2_TOOLCHAIN_BUILDROOT_CXX=y
BR2_TARGET_GENERIC_ROOT_PASSWD="123"
BR2_TARGET_GENERIC_GETTY_PORT="ttyAMA0"
BR2_SYSTEM_DHCP="eth0"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_DEFCONFIG="vexpress"
BR2_LINUX_KERNEL_DTS_SUPPORT=y
BR2_LINUX_KERNEL_INTREE_DTS_NAME="vexpress-v2p-ca9"
BR2_PACKAGE_DEJAVU=y
BR2_PACKAGE_QT5=y
BR2_PACKAGE_QT5BASE_EXAMPLES=y
BR2_PACKAGE_QT5BASE_GUI=y
BR2_PACKAGE_QT5BASE_WIDGETS=y
BR2_PACKAGE_QT5BASE_FONTCONFIG=y
BR2_PACKAGE_QT5BASE_JPEG=y
BR2_PACKAGE_QT5BASE_PNG=y
BR2_PACKAGE_OPENSSH=y
BR2_TARGET_ROOTFS_EXT2=y
BR2_TARGET_ROOTFS_EXT2_SIZE="256M"
# BR2_TARGET_ROOTFS_TAR is not set
BR2_PACKAGE_HOST_QEMU=y
BR2_PACKAGE_HOST_QEMU_SYSTEM_MODE=y