ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

工控机Linux环境搭建:Ubuntu系统、Qt配置与PCIe驱动安装实战

工控机Linux环境搭建:Ubuntu系统、Qt配置与PCIe驱动安装实战 最近帮客户装一台工控机来来回回跑了好几趟核心就三个环节系统安装、Qt配置、PCIe驱动安装。听起来都不难但实际做下来每个环节都藏着至少一个能让进度卡半天的坑——启动盘选错模式导致装机失败Qt跑起来缺平台插件驱动编译通过了但insmod报verification failed。这篇文章把这次从裸机到PCIe设备可用的完整过程整理出来包括我在BIOS、内核、驱动签名上踩过的坑和最终的解决路径。不管你是要给新机器装Linux工作站还是给采集卡、运动控制卡、PCIe网卡这类设备配驱动这套流程都适用照着走能少走很多弯路。1. 开工前的准备系统选型、UEFI模式与启动盘1.1 系统选型工控环境为什么优先选Ubuntu LTS很多人装机之前纠结发行版我直接说结论如果设备上没有特殊限制新工控机我基本都装Ubuntu 22.04 LTS。原因很朴素——PCIe设备的驱动厂商在编译示例代码和驱动时最常验证的就是Ubuntu LTS和RHEL系。你去采集卡、运动控制卡、网卡厂商的官网下载Linux驱动解压出来看README大概率写着“Tested on Ubuntu 20.04/22.04”之类的字样。Ubuntu的LTS版本支持周期有五年到2027年之前都能持续收到更新对工控这种“装完就不想再动系统”的场景非常合适。为什么不追最新版我之前在一台机器上试过从24.04装某厂家的采集卡驱动SDK编译时直接提示一个头文件路径变了翻了一下源码原来是新内核移除了某个旧接口。第三方驱动跟不上新内核的情况在工控领域太太太常见了。反过来如果你的机器是那种刚出的新款主板集成网卡、NVMe控制器特别新Ubuntu 22.04的默认内核可能不识别那就另说得上HWE内核或者换新一点的发行版。如果客户明确要求用麒麟、统信这类国产发行版流程也不用推翻重来它们大多基于Debian系后面说的换源、装编译工具、装内核头文件这些操作路径非常接近区别主要在包名和软件源地址上。我建议拿到机器后先问清楚驱动厂商有没有针对该发行版编译验证过没有的话还是以Ubuntu为基准环境再考虑迁移。1.2 UEFI、Secure Boot和CSM这三个BIOS选项必须先搞明白新主板默认基本都是UEFI启动装系统时U盘也必须是UEFI模式启动否则会出现“U盘能引导但安装程序进不去”或者“装完了开机提示找不到引导设备”的尴尬。更关键的是Secure Boot。这个安全功能在Windows 8之后默认开启它会让系统只加载经过签名认证的引导程序和内核模块。问题在于我们后手要自己编译PCIe驱动模块手动编译出来的.ko模块基本都没有有效签名Secure Boot开启时内核会拒绝加载报module verification failed: signature and/or required key missing。针对开发调试用的工控机我的建议是在BIOS里直接关闭Secure Boot把引导模式设置为纯UEFI。CSMCompatibility Support Module这个兼容模块如果开启理论上能支持Legacy模式启动但会带来不少不确定性纯UEFI反而更干净。具体路径因主板而异一般在Boot或者Security选项卡下面找Secure Boot并设为DisabledCSM设为Disabled或UEFI Only。可能有朋友问“关掉Secure Boot安不安全”工控机通常部署在内网或专用环境面对的威胁模型和裸奔上网的民用电脑不同。安全性和可维护性之间总得做个取舍你每次驱动加载失败都要去搞签名生产的连续性受影响成本更高。后面我会讲用MOK签名来保留Secure Boot的方案适合那些对安全要求确实严格的项目。1.3 制作U盘启动盘的几种方式对比启动盘我试过不少工具简单做个对比工具适用平台优点注意点RufusWindows成熟稳定GPT/UEFI配置直观写U盘时会格式化别选错盘VentoyWindows/Linux一个U盘可以放多个ISO启动时选个别主板对Ventoy支持不好balenaEtcherWindows/macOS/Linux界面简单一键写盘写完后看不到U盘原分区适合一次性工具dd命令Linux不依赖图形界面服务器上也能做命令错误会毁掉其他磁盘务必核对盘符我个人的主力是Ventoy——先装好一份Ventoy到U盘后面在工地上想换系统版本直接拷一个ISO进U盘就行不用反复写盘。不过如果你的客户主板特别老Ventoy识别不了那就老老实实用Rufus写。用Rufus写盘时记住几个关键选择分区类型选GPT目标系统选UEFI非CSM文件系统FAT32。Ventoy默认已经处理好这些直接在BIOS里选UEFI开头的U盘启动项即可。如果你手头只有Linux环境用dd命令也完全没问题sudo dd ifubuntu-22.04.3-desktop-amd64.iso of/dev/sdb bs4M statusprogress sync这里特别注意of后面跟的是磁盘设备比如/dev/sdb不是分区/dev/sdb1而且一定要确认/dev/sdb确实是你的U盘。写盘完成后如果系统提示无法挂载某个分区别紧张那是U盘上原有的ISO分区被覆盖了正常现象。2. 系统安装全流程分区策略、换源与内核头文件2.1 安装过程中的分区策略安装Ubuntu时我几乎不用默认的“清除整个磁盘并安装Ubuntu”方案。不是说它不好而是手动分区能让你清楚知道每个分区的用途后续扩容、备份、识别问题都更有底气。推荐的分区方案如下分区大小文件系统挂载点说明sda1512MB~1GBFAT32/boot/efiEFI系统分区UEFI引导必需sda2100GB~200GBext4/根分区系统、/usr、/opt都在这里sda3内存大小或16GBswap/swap交换分区内存紧张时兜底sda4剩余全部ext4/home用户数据、工程代码、SDK都放这里如果机器内存有32GB甚至更多swap可以不分或者只给8GB。分swap我一般在“可用空间”的位置建一个逻辑分区类型选交换空间即可不用单独搞swap文件。根分区给多少合适如果要把Qt整个装在/opt目录下加上系统本体、编译中间文件100GB是起步水平。SDK和驱动源码我喜欢放在/home下理由很朴素——重装系统时/home的数据基本不受影响驱动源码和编译好的产物还能留着。有客户机器需要保留原有的Windows系统那就更不能用整盘自动方案了。手动分区时EFI分区可以沿用Windows已有的那一个FAT32就能被GRUB识别再在空闲空间里划分根分区和/home分区。2.2 系统装完后的第一件事换源、更新、装SSH和编译工具链刚装完的Ubuntu系统默认软件源指向国外服务器apt update经常慢到怀疑人生。我上机第一步永远是先把源切成国内镜像这一步不做好后面安装Qt依赖、编译工具时会等得头疼。Ubuntu 22.04的软件源文件在/etc/apt/sources.list可以用sed一把替换成阿里云镜像sudo sed -i s//.*archive.ubuntu.com//mirrors.aliyun.comg; s//security.ubuntu.com//mirrors.aliyun.comg /etc/apt/sources.list sudo apt update注意如果你装的是Ubuntu 24.04源配置文件路径变成了/etc/apt/sources.list.d/ubuntu.sources内容格式也换成了deb822格式别拿老方案硬套打开文件看一眼再改。切换完源之后立刻执行全量更新然后安装一套开发必备工具sudo apt update sudo apt upgrade -y sudo apt install -y build-essential gcc g make git cmake \ linux-headers-$(uname -r) ssh net-tools这一条命令里有几个关键包值得说一下。build-essential会拉取gcc、g、make等编译基础组件linux-headers-$(uname -r)是编译内核模块的必需品它的版本必须和当前运行的内核完全一致否则编译出来的.ko在加载时会报版本校验错误。SSH服务建议顺手装上很多工控机放在机柜或者现场没有配显示器装了SSH之后远程维护会方便很多。这也算是我这几年调试设备的一个习惯任何Linux机器只要允许先开SSH再接网线。2.3 内核版本管理的两个坑不要随意升级别忘锁版本装完系统、驱动也跑通之后接下来最大的不确定性就来自内核自动升级。ubuntu的apt upgrade会连内核一起升级。内核一升级原本编译好的PCIe驱动模块就废了——模块文件还在但加载时会提示版本不匹配因为里面的vermagic和当前内核不一致。这时候如果你人在现场机器重启后采集卡或网卡突然不工作了排查起来真的会让人抓狂。我的处理策略是生产机器装完系统、装好驱动之后用下面命令把内核锁住sudo apt-mark hold linux-image-$(uname -r) sudo apt-mark hold linux-headers-$(uname -r)这样即使后面执行apt upgrade内核也不会被替换。当然锁住内核意味着无法获得安全补丁如果对安全有严格要求那更推荐用DKMS方案来管理驱动模块这个我在第5章详细展开。至少要知道“跑得好好的重启后驱动不对了”这个经典故障八成和内核升级有关。3. Qt环境配置版本选型、离线安装与编译器匹配3.1 先定Qt版本5.15.2还是6.5 LTSQt环境配置这个环节最核心的决策就是版本选择。工控上位机开发这一块目前最稳的组合依然是Qt 5.15.2 LTS。原因是很多PCIe设备的厂商SDK尤其是采集卡、运动控制卡厂商提供的示例程序和动态库都是基于Qt5编译的直接拿Qt6跑可能会遇到第三方库ABI不兼容、插件加载失败等问题。5.15.2是Qt5时代最后一个社区开源版本稳定性经过多年检验资料也多遇到问题网上基本都有答案。如果你是新项目、新团队没有历史包袱直接上Qt 6.5 LTS问题也不大。但前提是确认清楚你依赖的第三方库有Qt6版本。有读者可能会问“项目里写的就是Qt 5.9能装吗”Qt 5.9的年代比较久在Ubuntu 22.04默认gcc 11的环境下编译偶尔会有源码级的不兼容问题。如果厂商SDK明确基于Qt 5.9我建议要么用Docker把编译环境固定成老版本要么干脆把项目迁移到5.15.2后者通常难度不大。3.2 离线安装包比在线安装器更省心Qt的在线安装器online installer需要注册登录账号才能下载组件在服务器或者内网环境下特别不方便。我推荐直接用离线安装包从国内镜像站把qt-opensource-linux-x64-5.15.2.run下载下来体积大概3GB多拷到U盘上就能装。下载完成后chmod x qt-opensource-linux-x64-5.15.2.run ./qt-opensource-linux-x64-5.15.2.run安装过程中会让你选择组件这里别全选磁盘空间占用很大且用不上。最小方案是勾选以下内容Qt 5.15.2下的“Desktop gcc 64-bit”如果需要图表、串口等模块勾上Qt Charts、Qt Serial Port、Qt Serial Bus等底部的Qt Creator我建议勾上虽然不是必须但调试起来方便如果安装过程中提示缺xcb库多半是系统缺少图形依赖。先补齐基础库再重试安装sudo apt install -y libxcb-xinerama0 libxcb-cursor0 libgl1-mesa-dev这个坑在无桌面环境或者精简安装的系统上经常出现提前装好能省一轮来回。3.3 环境变量与编译器qmake能找到、库能链接才叫配好安装完Qt不配环境变量就跟买了一台新电视机不插电源一样——硬件都在就是用不了。把下面几行加到~/.bashrc末尾export QTDIR$HOME/Qt5.15.2/5.15.2/gcc_64 export PATH$QTDIR/bin:$PATH export LD_LIBRARY_PATH$QTDIR/lib:$LD_LIBRARY_PATH export QT_QPA_PLATFORM_PLUGIN_PATH$QTDIR/plugins/platforms然后执行source ~/.bashrc qmake -v如果能看到qmake的版本信息基本就配置成功了。QT_QPA_PLATFORM_PLUGIN_PATH这个变量很多人会忘记设置结果程序编译通过、一运行却报“could not find or load the Qt platform plugin xcb”头大半天。只要库路径和插件路径都指过去这个问题基本不会再出现。编译器和Qt版本的匹配也要留意。Qt 5.15.2的官方二进制包用的还是比较常规的gcc ABIUbuntu 22.04自带的gcc 11可以直接用不需要额外安装老版本gcc。但如果你的系统是Ubuntu 24.04默认gcc 13某些老Qt程序编译时会因为C ABI变化导致链接失败这就是另一个层面的问题解决办法是装gcc-12再配合CMake的CMAKE_CXX_COMPILER指定。3.4 配合VSCode开发时的几个关键配置不少同行现在喜欢用VSCode写Qt而不是Qt Creator。我的经验是VSCode看代码、做Git操作确实爽但要先用命令行确认qmake能运行CMake构建也没问题再回编辑器写代码。CMake项目里最关键的是让CMake能找到Qt库。千万别只依赖find_package(Qt5)它会从系统路径找Qt而你装在自己目录下的Qt它根本不知道。正确做法是指定前缀cmake -B build -DCMAKE_PREFIX_PATH$QTDIR cmake --build buildVSCode的C/C插件默认也不认识Qt的头文件目录需要在c_cpp_properties.json中手动添加include路径{ configurations: [ { name: Linux, includePath: [ ${workspaceFolder}/**, /home/yourname/Qt5.15.2/5.15.2/gcc_64/include, /home/yourname/Qt5.15.2/5.15.2/gcc_64/include/QtWidgets, /home/yourname/Qt5.15.2/5.15.2/gcc_64/include/QtCore ] } ] }配置好之后代码补全、跳转定义、查找引用这些功能就正常了。至于可视化界面设计我习惯还是用Qt Designer单独编辑.ui文件VSCode里通过任务命令调用designer也可以但没必要太过折腾编辑器只是工具能提高效率就好。4. PCIe驱动安装从识别设备到模块加载全链路4.1 lspci是驱动工作的第一站安装PCIe驱动之前先搞清楚系统到底认不认这块设备。我见过不少同行上来就编译驱动结果编译了半天发现设备根本没被系统枚举到白白浪费时间。用lspci查看lspci -nnk输出里找设备名称比如一块PCIe 2.5G网卡会显示类似05:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller [10ec:8125] (rev 05) Subsystem: ... Kernel driver in use: r8169这里[10ec:8125]就是设备ID厂商ID:设备ID这个信息后面找驱动、核对驱动版本都很有用。Kernel driver in use: r8169说明当前内核已经带了一个驱动。很多时候“设备没网”是因为系统自动加载的通用驱动和厂商驱动冲突而不是驱动没装。如果lspci里根本没有你的设备先别急着编译驱动回去检查设备是否插紧PCIe插槽是否和工作BIOS里PCIe设备是否被禁用主板PCIe插槽的兼容模式设置。设备都没枚举出来后面一切操作归零。4.2 驱动源码编译Makefile、内核头文件和一个经典错误拿到厂商驱动源码包解压后一般长这样有src目录、Makefile文件、autorun.sh脚本还有README。最省事的方式是跑厂商提供的脚本sudo ./autorun.sh这个脚本内部通常会自己编译、拷贝模块到系统目录、执行depmod和modprobe适合大多数场景。但如果autorun.sh运行报错或者你想自己掌控安装过程手动编译也是几分钟的事tar -xf r8125-9.012.02.tar.bz2 cd r8125-9.012.02 make sudo make install sudo modprobe r8125编译过程中出现“找不到内核头文件”或者“Makefile: ... linux/version.h: No such file or directory”这类错误原因几乎都是第2章那句linux-headers-$(uname -r)没装或者系统升级内核后没重新装对应头文件。回到字符界面重新确认uname -r ls /usr/src/linux-headers-$(uname -r)如果/usr/src下没有对应目录说明头文件确实缺失用apt补上再回去编译。编译好的模块是.ko文件可以用modinfo查看信息modinfo r8125.ko filename: ...r8125.ko vermagic: 5.15.0-91-generic SMP mod_unload modversions看到vermagic里的内核版本和uname -r一致才能放心加载。4.3 加载、卸载与开机自启动的正确姿势模块加载有两个命令insmod和modprobe。我的建议是能用modprobe就用modprobe它会自动处理模块依赖关系insmod只是“硬塞进去”不检查依赖很容易出现模块加载了但它依赖的其他模块没加载功能异常。加载模块后最好验证一下是否真的生效。以r8125网卡为例lsmod | grep r8125 ethtool -i enp5s0ethtool输出的driver字段如果显示r8125说明驱动已经接管了这块网卡。如果发现系统里还有另一个驱动在抢设备比如内核自带的r8169需要把旧驱动禁止掉echo blacklist r8169 | sudo tee /etc/modprobe.d/blacklist-r8169.conf sudo update-initramfs -u禁止旧驱动这一步经常被忽略结果就是新驱动“装上了”但设备还是被老驱动占用着一切像没发生一样。设置开机自动加载驱动可以在/etc/modules-load.d/下建一个conf文件把模块名写进去echo r8125 | sudo tee /etc/modules-load.d/r8125.conf这样重启后模块会被自动加载不用每次手动modprobe。5. 驱动不工作的排查链路dmesg、模块签名与DKMS5.1 排查第一步永远是dmesg驱动加载失败时大多数人第一反应是搜“xxx驱动加载不出来”但不如先看内核日志。内核把每一个模块加载过程、PCIe总线枚举、设备驱动绑定都记录在dmesg里这是最直接、信息量最大的线索。dmesg | tail -50 dmesg | grep -Ei error|fail|pcie我遇到的几次典型情况dmesg日志关键片段含义处理方向module verification failed: signature and/or required key missing模块没有有效签名关闭Secure Boot或做MOK签名Unknown symbol in module, or unknown parameter内核API版本不匹配确认头文件版本与uname -r一致重新编译could not insert: Device or resource busy设备被别的驱动占用查lsmod停用冲突驱动Direct firmware load for ... failed缺少固件文件把固件拷贝到/lib/firmware下这几个错误看着吓人原因其实都挺明确按表格里的方向排查基本都能解决。5.2 模块签名问题关Secure Boot还是用MOK如果你装完驱动dmesg里出现required key not available或者module verification failed那铁定是Secure Boot挡路。最快捷的解决办法是进BIOS把Secure Boot关闭这个过程我在第1章已经讲过适用于开发调试和绝大多数内网部署场景。但有些客户的IT安全策略强制要求开启Secure Boot那就要走MOK签名流程# 安装签名工具 sudo apt install -y mokutil # 生成签名密钥如果厂商驱动包内置了签名脚本可跳过 openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -nodes -days 36500 -subj /CNMy Module Sign Key/ # 导入密钥会让设置一个一次性密码 sudo mokutil --import MOK.der # 重启进入蓝色MOK管理界面选Enroll MOK输入刚才的密码 sudo reboot重启后再用/usr/src/linux-headers-$(uname -r)/scripts/sign-file工具给编译好的模块签名sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 MOK.priv MOK.der r8125.ko然后再尝试加载模块。这个过程是麻烦了一点但确实能兼顾安全启动限制和自定义驱动。我自己的体会是项目现场遇到这类问题先看是否允许关Secure Boot不允许再走MOK签名两条路都走不通时才考虑换系统。5.3 内核一升级驱动就失效DKMS是正解前面说过锁内核能防住驱动失效但锁内核的副作用是无法获得安全更新。如果你既想保持内核更新又想驱动一直可用那就得用DKMSDynamic Kernel Module Support。DKMS会在内核升级后自动重新编译已注册的模块相当于把“手动重编驱动”这件事自动化了。大部分厂商的autorun.sh脚本会顺手注册DKMS比如r8125驱动装完就有了dkms支持。如果厂商没做手动注册也不复杂。先写一个dkms.conf放在源码目录下PACKAGE_NAMEr8125 PACKAGE_VERSION9.012.02 BUILT_MODULE_NAME[0]r8125 DEST_MODULE_LOCATION[0]/kernel/drivers/net/ethernet/realtek MAKEmake -C src/ KERNELDIR/lib/modules/${kernelver}/build CLEANmake -C src clean AUTOINSTALLyes然后注册sudo dkms add . sudo dkms build -m r8125 -v 9.012.02 sudo dkms install -m r8125 -v 9.012.02之后每次系统升级内核DKMS会自动重新编译模块驱动稳定跟着内核走。对于需要长期维护的系统我觉得DKMS是唯一推荐的做法省心程度高出一个档次。6. 用系统备份固化成果最后再分享一个我这几年养成的习惯。装好系统、配好Qt、驱动加载正常后别急着把机器交付到现场先用Clonezilla给系统盘做一个镜像备份。这样同一型号的设备再装第二台、第三台时直接恢复镜像十分钟搞定一遍装机的全部工作。即便后续有人误操作搞坏了系统恢复镜像也比重新走一遍全流程快得多。整个装机流程里我踩得最深的一个坑是内核升级后驱动失效折腾了几个小时排查。如果你也按照“系统选型→分区→换源→装头文件→装Qt→跑通驱动→固化备份”这个顺序走绝大部分坑都可以在源头避开希望这篇文章能帮你省下这些时间。
返回列表