
敲下第一行命令的时候我其实也没想到后面会有这么多坑。这个项目标题看起来是三件事——系统安装、Qt配置、安装PCIe驱动但真正做下来你会发现它其实是一整条从零搭建Linux开发环境的链路每一环都卡着后面的环节。这篇东西不只是给我自己做个备忘也希望能帮到那些打算在工控机、国产化终端或者普通PC上从头搭一套可用的Linux Qt PCIe外设开发环境的朋友。项目背景先交代清楚我手上有一台小主机板载螃蟹家的2.5G网卡Realtek PCIe 2.5GbE Family系统盘装的是Linux发行版业务上需要跑一个Qt的界面程序还要让板载2.5G网卡以满速跑起来。整个过程拆成三大块先是把系统装干净然后配好Qt开发环境最后解决PCIe网卡的驱动识别问题。每一块单独看都不算难但连在一起做踩坑的密度相当高。1. 系统安装先把地基踩稳1.1 选哪个发行版不是越新越好很多人装Linux第一步就卡在“我到底装哪个”。我这里明确推荐如果是给生产设备、工控机这类要长期跑的环境优先选LTS版本别追最新。Ubuntu 22.04 LTS、麒麟系统、统信UOS这类长期维护的发行版软件源稳定驱动打包相对齐全出了问题查资料也好查。我这次用的是Ubuntu 22.04原因很简单Qt官方对它的兼容性测试最充分PCIe网卡驱动的内核头文件在官方源里就能装到不用自己折腾第三方源。提示如果你是在国产化设备上开发麒麟或统信这类系统在安装思路和Qt配置上和Ubuntu几乎没有区别无非是包管理器命令略有差异。下面讲的操作逻辑通用。1.2 U盘安装的实操流程与分区细节制作启动盘我用的是最直接的dd命令Windows下也可以用Rufus、balenaEtcher这类图形化工具。Linux下执行sudo dd ifubuntu-22.04.3-desktop-amd64.iso of/dev/sdb bs4M statusprogress这一步有两点需要注意第一of后面是U盘设备节点不是分区比如sdb而不是sdb1写错会直接把数据写进硬盘分区第二U盘容量别太小8GB是底线16GB以上更稳妥。进入安装界面之后分区方案我建议手动分区。自动安装默认给的根分区和home分区划分有时候不太符合使用习惯。手动分区的参考方案ESP分区/boot/efi512MBFAT32必须是EFI System Partition类型根分区/至少给50GB我这次给了120GBext4/home剩余空间单独分出来的好处是以后重装系统不会丢用户数据swap物理内存8GB以下就给个4GB内存大的机器其实可以不设但设了也无妨这里有个经常被忽略的细节如果BIOS开了UEFI安全引导Secure Boot有些机器会直接挡住Ubuntu的启动引导卡在grub界面或者直接报错。我的建议是装机时先把Secure Boot临时关掉装完系统、驱动全部搞定之后再考虑要不要打开。对于PCIe驱动编译安装这样的操作Secure Boot会让第三方驱动的签名验证变得很麻烦。1.3 启动与引导排错的经验装完系统重启常见的卡壳点有两个一是卡在黑屏只有一个光标闪烁多半是显卡驱动没起来用nomodeset内核参数启动即可二是grub菜单里看不到Windows引导项优先检查有没有把os-prober启用。执行sudo os-prober sudo update-grub还有一个非常实用的习惯系统装好后马上做一次系统更新把内核和固件都推到最新。我这次就是因为没第一时间更新导致后面编译网卡驱动时遇到一个和旧内核不兼容的编译错误。更新命令sudo apt update sudo apt upgrade -y装完后检查一下内核版本后面编译驱动时要用uname -r说到这里插一句热搜里“wim系统安装工具”是Windows场景下的玩法和咱们这个Linux装机不大搭但如果你的工作流里同时维护Windows和Linux双系统用GRUB做引导管理器就够用了不需要额外工具。2. Qt环境配置装起来容易跑起来全是坑2.1 离线安装包的选择与下载Qt的安装是重头戏。给生产环境配置Qt时我的建议是优先选择离线安装包不要用在线安装器。在线安装器动不动几百MB的下载依赖而且网络波动容易中断导致安装不完整。离线包虽然体积大但一次下载、本地安装干净利落。搜索热词里有很多人问“qt离线安装包下载5.14”之类的问题说明大家的诉求很一致。我的建议是新项目直接用Qt 5.15或更高版本但如果你的开发套件来自上游厂商尤其是工业设备厂商他们给你的工程大概率基于Qt 5.14或5.12这时候老老实实下载对应版本别擅自升级大版本——升级带来的API兼容性问题比版本老旧更头疼。拿到.run安装文件后先加执行权限再运行chmod x qt-opensource-linux-x64-5.15.2.run sudo ./qt-opensource-linux-x64-5.15.2.run安装路径我建议放在/opt/Qt5.15.2不要放默认路径这样管理和权限控制都更方便。组件选择上有个关键点组件不全选而是按需勾选。根据自己的架构选择gcc_64或对应的交叉编译套件。但有两个组件容易被漏选一个是Qt Serial Port一个是Qt Charts这两个模块后面对接工业设备时经常用到。漏选的下场就是编译时报unknown module(s) in qt: serialport后面的排查章节我会细讲。2.2 编译套件与qmake的关系很多初学Qt的朋友会混淆“Qt版本”和“编译套件”。Qt本身是跨平台的同一份代码在Linux下用gcc编译在Windows下用MSVC或者MinGW编译。你需要配置的其实是“Qt版本 编译器 调试器”这个三位一体的组合。在Qt Creator里配置时选择“Kit”时会看到Desktop Qt 5.15.2 GCC 64bit这样的选项。这个Kit的作用是把qmake指向Qt库、把g指向系统编译器再配上gdb作为调试器。很多编译报错其实不是代码问题而是Kit选错了。比如你在Windows下用MSVC的工程文件跑到Linux下用gcc编译链接阶段一堆unresolved symbol第一反应应该是去检查Kit配置。Linux下确认编译套件的方式gcc --version g --version qmake --version看到qmake版本和Qt版本一致说明环境基本就位。2.3 qt_qpa_platform_plugin_path与模块缺失问题详解这里有一类很经典的Qt运行报错很多新人都栽过。我直接复述一下现象程序编译通过但运行时报qt.qpa.plugin: Could not find the Qt platform plugin xcb in 搜索热词里有个“qt_qpa_platform_plugin_pathd:\qt\5.15.2\msvc2019_64”就是这个问题的Windows版本。这个报错的核心原因是Qt在运行时找不到平台插件platform plugin。在Linux下就是找不到libqxcb.so这个文件。解决方法分几种情况第一种安装了Qt但没有设置环境变量需要手动指定插件路径export QT_QPA_PLATFORM_PLUGIN_PATH/opt/Qt5.15.2/5.15.2/gcc_64/plugins/platforms第二种缺少系统依赖库例如xcb相关的库没装全此时安装依赖后重新构建sudo apt install libxcb-xinerama0 libxcb-cursor0 libxkbcommon-x11-0第三种在嵌入式设备上运行用的是linuxfb或eglfs平台这时设置export QT_QPA_PLATFORMlinuxfb再说回unknown module(s) in qt: serialport这个报错。它的出现原因很简单Qt安装时没有勾选Serial Port模块或者勾选了但没有被qmake找到。解决办法是先检查安装目录下有没有QtSerialPort的pri文件find /opt/Qt5.15.2 -name *serialport*没有的话只能用Qt Maintenance Tool或者重跑安装包把Qt Serial Port组件补装上。装完重新打开Qt Creator工程文件里加QT serialport就不会再报错了。另外一个热搜词“qt 槽函数 返回值”也有必要提一下。Qt的信号槽机制里槽函数的返回值其实是会被忽略的QObject::connect返回的是一个QMetaObject::Connection连接对象而不是槽函数的返回值。如果你打算通过信号槽跨线程传递计算结果正确姿势是再发一个信号或者用QFuture/QtConcurrent这种异步方案。我在实际项目里用这个模式做过不少数据采集和界面刷新的解耦。3. PCIe驱动安装以Realtek 2.5G网卡为例3.1 准备工作内核头文件与编译工具系统装好、Qt环境配好之后第三块就是PCIe驱动。先解释一下为什么PCIe设备有时候冷启动后不工作Linux内核自带了很多驱动模块但像Realtek 2.5G这样的新网卡内核自带的模块版本可能较旧或者根本没有对应支持这时候就需要手动编译安装驱动。安装驱动前必须保证内核头文件和编译工具就位。命令sudo apt install build-essential dkms linux-headers-$(uname -r)这个linux-headers-$(uname -r)必须和当前内核完全一致很多编译失败的案例都是因为头文件版本对不上。执行uname -r手动看一眼当前内核版本再和ls /usr/src/里的目录对比就能确认是否匹配。确认网卡型号用lspci命令lspci | grep -i ethernet我这边输出的是Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller这就锁定目标了。3.2 源码编译安装驱动Realtek官方有放出Linux下的网卡驱动源码包也有人在GitHub维护了比较活跃的r8125驱动仓库。下载源码后按下面流程操作git clone https://github.com/awesometic/realtek-r8125-dkms.git cd realtek-r8125-dkms编译方式一直接编译安装模块sudo make -C /lib/modules/$(uname -r)/build M$(pwd) modules sudo make -C /lib/modules/$(uname -r)/build M$(pwd) modules_install编译方式二用dkms管理模块放内核升级后自动重建sudo make dkms_install我个人推荐第二种方式。用过dkms之后内核一旦更新驱动模块会自动重新编译不会再出现“升级内核网卡就没驱动”的尴尬。编译完成后加载模块sudo modprobe r8125然后确认驱动是否加载成功lsmod | grep r8125 lspci -k | grep -i ethernet第二行命令会显示内核驱动名看到Kernel driver in use: r8125就说明驱动接管了网卡。接着用ethtool确认链路速率sudo ethtool enp3s0看Speed字段如果是2500Mb/s说明2.5G速率协商成功。如果显示1000Mb/s多半是网线或者对端交换机不支持2.5G。这里有个经验2.5G网卡必须搭配支持2.5G的交换机或者对端设备否则速率自动协商会降到1Gbps这个不是驱动问题是硬件协商结果。再检查IP地址ip a看看网卡有没有拿到IP如果没有用DHCP客户端获取sudo dhclient enp3s0如果是运行NetworkManager的系统直接在图形界面里点一下连接就行。3.3 Secure Boot与驱动签名的一个大坑这块是我这次实际遇到最头疼的问题。如果BIOS开了Secure Boot即使编译和加载模块时都显示成功重启后驱动会莫名消失。原因在于Secure Boot要求加载到内核里的模块必须有受信任的签名手动编译的模块没有签名直接被拒了。排查步骤进入BIOS看看Secure Boot状态。临时解决办法是关闭Secure Boot正式生产环境不想关的话需要用mokutil对驱动模块进行签名sudo mokutil --import MOK.der然后重启进入MOK管理界面按提示注册密钥签名过的模块才能被信任。这一步操作复杂度稍高我的建议是开发调试阶段直接关Secure Boot等所有驱动都稳定了再考虑签名的事。注意PCIe驱动安装失败的表现往往不是“装不上”而是“装上看不到效果”——insmod正常、lsmod能看到但lspci的驱动字段还是写着driver in use: r8169之类的旧驱动。这就是模块优先级的问题了旧驱动占用了设备新模块没有被绑定。解决办法是重新绑定设备到新驱动或者干脆从/lib/modules里移除旧模块的加载配置。4. 高频问题排查实录与经验速查4.1 常见问题速查表我把这个过程中遇到的所有典型问题和解决方案整理成一个表方便大家直接对照。现象可能原因解决方案Qt程序运行时报qt.qpa.plugin: Could not find the Qt platform plugin xcb环境变量QT_QPA_PLATFORM_PLUGIN_PATH未设置或platforms插件路径不对设置export QT_QPA_PLATFORM_PLUGIN_PATH$QTDIR/plugins/platforms检查libqxcb.so是否存在编译报unknown module(s) in qt: serialport安装Qt时未勾选Serial Port模块重装或补装Qt Serial Port组件检查.pro文件里QT serialport网卡驱动编译时报/lib/modules/.../build: No such file or directory未安装内核头文件版本不匹配执行sudo apt install linux-headers-$(uname -r)模块加载成功但网卡速率只有1Gbps网线/交换机不支持2.5G或协商失败换六类以上网线确认对端设备支持2.5G重启后驱动丢失未使用dkms或者Secure Boot拦截改用dkms安装关闭Secure Boot或签名Windows下安装.net Framework报0x80070002系统更新临时文件损坏或安装缓存问题停止wuauserv服务清理C:\Windows\SoftwareDistribution后重试4.2 几个提升开发效率的习惯整个过程走完我觉得有几个习惯非常值得养成。第一尽量用dkms管理一切第三方内核模块。谁都不想每次升级内核都重来一遍加个dkms也就多一行命令的事儿长期收益很大。第二Qt工程里尽量用CMake而不是qmake组织项目。虽然在老工程里qmake仍然常见但CMake在跨平台、依赖管理和IDE支持上要强得多。新项目直接CMake起步配合Qt 6或者Qt 5.15后面维护会轻松很多。第三什么环境变量都用全局配置导致系统残留一堆奇怪变量。我习惯把Qt相关的配置写进~/.bashrc或/etc/profile.d/qt.sh集中管理方便回滚。第四遇到驱动问题先查内核日志dmesg | grep r8125 dmesg | tail -100日志里往往直接写着失败原因比在网上盲搜快得多。4.3 关于热门搜索里的一些延伸方向顺便提几个和本项目相关的热门方向虽然不是核心内容但很可能和读者的下一步需求相关。“qt国际化”是Qt工程发布必备技能做法是tr()包裹所有UI字符串然后通过lupdate生成ts文件再用linguist翻译最后用lrelease生成qm文件。一套流程不超过半小时但很多人都是要发布海外版本时才后悔没早做。“qt 自定义进度条”和“qt绘图效率比较”则是界面开发里的进阶话题。自定义进度条建议用QPainter重绘控制好重绘区域避免全量刷新绘图效率方面QPainter适合简单场景大数据量可视化用QGraphicsView或者绑定到OpenGL后端会更高效。“vscode配置qt designer”值得单独说一嘴VSCode配Qt插件后可以直接打开ui文件并调起Qt Designer底层其实是调用了designer可执行文件。不方便打开Qt Creator的轻量场景用它很顺手但完整调试还是建议回到Qt Creator。还有“qt 调用halcon”和“qt 调用proj”偏机器视觉和GIS领域。Halcon通过halconcpp库集成一般用OpenCV兼容接口做数据交换proj主要是坐标转换库Qt侧只需封装好.proj库的调用接口通过信号槽把处理结果抛回界面即可。“qt模拟鼠标点击事件”在自动化测试场景里很有用核心是用QTest::mouseClick或者发送QMouseEvent到目标控件。注意一定要在对象的坐标系下发送否则点击位置会偏。“qt获取文件信息”则比较简单用QFileInfo就够了多注意符号链接和权限位的处理。4.4 一点真实的项目体会驱动和Qt都调试通过后我还是保留了一个传统把整个过程写成部署文档。无论是个人的小项目还是团队交付环境搭建这种体力活最怕的其实是反复。哪天系统盘崩了、换了台机器、或者内核升级出问题这份文档能救你一命。再往后如果你的设备要批量交付不妨用Packer或者预置镜像的方式把整个系统、Qt环境、驱动全部固化成一个模板。我这次临时环境搭建是按部就班弄的培训用的虚拟机就准备二三十个节点给每台机器装同样的Qt和驱动我深有体会手工装一遍和写脚本批量装完全是两码事。后面我用脚本做了一键部署流程包括装Qt依赖、放Qt离线包、编译网卡驱动、加载模块、验证网络十几分钟一台。脚本其实不难难的是每个环节的错误处理都考虑到。整个项目走下来我最大的体会是系统安装、Qt配置、PCIe驱动安装这三件事单独拆开来都不是什么高深技术但当你把它们放在一条完整的链路里时任何一个环节的疏漏都会成为下一环节的隐性炸弹。所以别嫌流程繁琐该做的检查一步都不能少。