不需要iis的网站开发一个成功的网站必须具备
不需要iis的网站开发,一个成功的网站必须具备,多少钱能运营一个网站,老外采购平台1. 为什么选择QEMU来模拟imx6ul开发板#xff1f;
很多刚开始接触嵌入式Linux开发的朋友#xff0c;可能都和我一样#xff0c;第一反应就是买一块真实的开发板。这当然没错#xff0c;实物在手#xff0c;调试起来感觉更踏实。但现实往往很骨感#xff1a;开发板不便宜&…1. 为什么选择QEMU来模拟imx6ul开发板很多刚开始接触嵌入式Linux开发的朋友可能都和我一样第一反应就是买一块真实的开发板。这当然没错实物在手调试起来感觉更踏实。但现实往往很骨感开发板不便宜尤其是像i.MX6UL这种性能不错的板子接线、供电、串口调试一套流程下来桌面乱成一团更头疼的是如果你只是想验证一个内核模块的改动或者测试一个驱动每次修改都要编译、烧录、重启这个循环非常耗时。我最早也是这么折腾过来的直到后来开始用QEMU才发现原来虚拟开发环境能省下这么多事儿。简单来说QEMU是一个开源的硬件虚拟化模拟器它能模拟整个计算机系统包括CPU、内存、各种外设。对于我们嵌入式开发者它的核心价值在于可以模拟特定的开发板比如我们这里要讲的NXP i.MX6UL。这意味着你可以在你的Ubuntu电脑上直接运行一个“虚拟的”imx6ul开发板系统启动、运行程序、调试内核全部在软件层面完成。听起来是不是有点像虚拟机但底层原理不同。QEMU是系统模拟它甚至可以模拟不同架构的CPU比如在x86电脑上模拟ARM芯片而VMware/VirtualBox更多是同架构的系统虚拟化。用QEMU模拟imx6ul你得到的是一个几乎完全一致的软件运行环境特别适合进行操作系统移植、内核驱动开发、应用程序调试这些纯软件层面的工作。它启动速度快按个快捷键就能重启不用插拔电源文件共享方便宿主机和虚拟板子之间传文件就是复制粘贴最香的是调试内核配合GDB你可以像调试普通程序一样给内核代码设断点、单步执行、查看变量这在真实板子上是很难实现或者非常缓慢的。当然它也不是万能的。QEMU模拟的是“标准”的硬件一些非常具体的、依赖特殊硬件时序或未公开寄存器细节的驱动在QEMU里可能无法完美工作。但对于学习Linux内核架构、理解驱动模型、验证核心功能来说它绝对是一个“神器”。我自己的经验是大约80%的驱动开发和内核学习工作都可以在QEMU环境里高效完成剩下的20%再上真机做最终验证这样能极大提升学习效率和开发速度。2. 手把手搭建你的虚拟开发板环境好了理论不多说我们直接开干。搭建环境就像搭积木步骤清晰就不难。我会把每个步骤的细节和可能遇到的坑都讲清楚你跟着做就行。2.1 准备你的“地基”宿主机与虚拟机虽然理论上可以直接在Windows上安装QEMU但对于嵌入式开发我强烈建议在Linux环境下进行。各种编译工具链、脚本在Linux下兼容性最好省心。所以我们的方案是Windows宿主 VMware虚拟机 Ubuntu系统。宿主机Host你的Windows 10或11电脑。配置上建议至少给虚拟机分配4GB内存和50GB硬盘空间CPU核心数越多越好编译内核时会快很多。虚拟机软件VMware Workstation Pro或者免费的VMware Player都可以VirtualBox也行看个人习惯。我用的是VMware。客户机GuestUbuntu 18.04 LTS 64位。为什么是18.04因为很多嵌入式教程和工具链对这个版本的支持最成熟、最稳定。当然使用更新的20.04或22.04也可以但可能需要自己解决一些依赖库版本问题。对于新手求稳是第一位的。这里有个超级省事的办法直接使用百问网提供的Ubuntu 18.04虚拟机镜像。这个镜像已经预装好了很多嵌入式开发需要的软件和配置比如交叉编译工具链、常用库等能帮你跳过一大堆繁琐的安装和配置步骤特别适合快速上手。你只需要下载这个OVA文件用VMware直接“打开”它就得到一个立即可用的开发环境。镜像的登录密码通常是123456。当然如果你喜欢从零开始打造自己的系统手动安装Ubuntu并配置好基础开发环境build-essential,git,vim等也是完全可行的。2.2 安装QEMU与性能加速器KVM装好Ubuntu并启动后第一件事就是打开终端。我们先更新软件源列表然后安装QEMU和它的好搭档KVM。sudo apt-get update sudo apt-get install qemu-system-arm qemu-utils qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager这条命令安装了以下几个东西qemu-system-arm这是模拟ARM架构的核心包没有它就没法模拟imx6ul。qemu-utils包含一些有用的QEMU工具比如创建磁盘镜像的qemu-img。qemu-kvm这是关键的性能加速器。KVM是Linux内核本身支持的一种虚拟化技术。当宿主机是Linux我们的Ubuntu虚拟机且CPU支持虚拟化Intel VT-x或AMD-V时启用KVM可以让QEMU直接调用硬件虚拟化指令而不是纯软件模拟。效果就是模拟器的运行速度会有质的飞跃几乎接近原生速度。记得要在VMware的虚拟机设置里把“虚拟化Intel VT-x/EPT或AMD-V/RVI”这个选项勾上否则KVM可能无法启用。后面几个libvirt和virt-manager是管理虚拟机的工具套件我们不一定用到但装上也无妨。安装完成后可以输入qemu-system-arm --version看看是否安装成功。如果显示版本号那就没问题。2.3 获取“灵魂”imx6ul的QEMU系统镜像光有模拟器QEMU还不行我们还需要被模拟的对象——也就是针对imx6ul开发板预先配置好的完整系统镜像。这包括了uboot、Linux内核、设备树、根文件系统。自己从头制作这个镜像非常复杂幸运的是社区有现成的资源。我们可以使用韦东山老师团队维护的镜像通过git直接克隆到本地git clone https://e.coding.net/weidongshan/ubuntu-18.04_imx6ul_qemu_system.git下载完成后你会得到一个名为ubuntu-18.04_imx6ul_qemu_system的目录。进去看看结构里面通常会有这几个关键部分qemu-imx6ull-gui.sh/qemu-imx6ull-nogui.sh启动模拟器的脚本分别对应带图形界面和不带图形界面。imx6ull-system-image/存放系统镜像文件的目录比如内核文件zImage、设备树文件*.dtb、根文件系统等。可能还有一些预编译好的工具链或工具。这个目录就是我们后续所有操作的“工作基地”。2.4 首次启动解决依赖与图形界面问题进入镜像目录我们准备第一次启动。如果是带图形界面GUI的版本需要SDL库的支持。项目很贴心地准备了一个安装脚本./install_sdl.sh但这里往往是第一个“坑”。脚本可能会因为系统缺少某些依赖而报错提示一些libxcb*、libgl*之类的包配置失败。别慌这是因为安装的deb包之间有依赖关系没理顺。Linux的包管理器apt提供了修复依赖的“神器”sudo apt --fix-broken install运行这个命令它会自动尝试修复破损的依赖关系下载缺失的包。完成后再重新运行一次./install_sdl.sh应该就能顺利安装了。依赖搞定后激动人心的时刻来了。如果你想看到完整的桌面环境就像真的开发板接上了屏幕运行./qemu-imx6ull-gui.shQEMU窗口会弹出来模拟的串口终端也会显示启动信息。等待系统启动完成登录用户名是root没有密码直接回车就进去了。你会看到一个精简的Linux桌面这对于调试需要图形界面的应用比如基于Qt的程序非常有用。如果你更专注于命令行操作或者觉得图形界面占用资源可以运行无GUI版本./qemu-imx6ull-nogui.sh这个脚本会直接启动到一个串口控制台同样是root用户无密码登录。我平时调试内核和驱动时更常用这个模式因为它更轻量启动更快而且所有输出都集中在终端里方便复制和查看日志。3. 深入核心编译与定制你的Linux内核用现成的镜像跑起来只是第一步。作为开发者我们肯定要修改内核代码比如添加一个驱动、调整一个参数然后编译测试。这才是QEMU环境最大的优势所在——快速迭代。3.1 获取内核源码与工具链我们需要下载专门为这个QEMU imx6ul环境适配的内核源码。这里通常使用repo工具Google用来管理多个Git仓库的工具来同步代码因为内核、uboot、设备树等可能在不同的仓库里。git clone https://e.coding.net/codebug8/repo.git mkdir -p 100ask_imx6ull-qemu cd 100ask_imx6ull-qemu ../repo/repo init -u https://e.coding.net/weidongshan/manifests.git -b linux-sdk -m imx6ull/100ask-imx6ull_qemu_release_v1.0.xml --no-repo-verify ../repo/repo sync -j4这个过程可能会花点时间因为它要拉取很多代码。完成后当前目录下应该会有linux-4.9.88内核源码目录和ToolChain交叉编译工具链目录等。交叉编译工具链是什么简单类比你的Ubuntu是x86_64架构的电脑而imx6ul是ARM架构的芯片。在x86电脑上编译出能在ARM芯片上运行的程序就需要一个“翻译官”这就是交叉编译工具链。它里面包含了针对ARM架构的编译器gcc、链接器ld等一整套工具。3.2 配置编译环境变量编译前我们需要告诉系统三件事1. 目标CPU架构是ARM2. 使用哪个交叉编译前缀3. 交叉编译工具链的路径在哪里。你可以把这些环境变量设置命令写在~/.bashrc里永久生效但像我这样经常切换不同平台工具链的更喜欢“临时”设置只对当前终端窗口有效export ARCHarm export CROSS_COMPILEarm-linux-gnueabihf- export PATH$PATH:/home/book/100ask/100ask_imx6ull-qemu/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin注意第三行PATH的路径一定要改成你电脑上的实际路径book是我虚拟机里的用户名你的可能叫ubuntu、user或者其他。你可以通过pwd命令在ToolChain的bin目录下查看绝对路径。arm-linux-gnueabihf-这个前缀hf代表硬件浮点Hard Floati.MX6UL的CPU支持硬件浮点运算用这个工具链编译的程序性能更好。设置好后可以验证一下输入arm-linux-gnueabihf-gcc --version如果能显示版本信息说明工具链路径设置正确。3.3 执行内核编译万事俱备进入内核源码目录开始编译cd linux-4.9.88首先进行一次彻底的清理确保没有之前的编译残留影响这次编译make mrproper然后应用针对这个QEMU imx6ul开发板的默认配置。这个配置文件100ask_imx6ull_qemu_defconfig已经预先设置好了所有必要的选项比如CPU类型、内存大小、支持的文件系统、网络驱动等。make 100ask_imx6ull_qemu_defconfig接下来是关键步骤编译内核镜像。这里有个小技巧-jN选项可以指定并行编译的作业数N通常设置为你CPU的物理核心数可以用nproc命令查看。比如我的虚拟机有4个核心就用-j4能大幅缩短编译时间。make zImage -j4编译过程中可能会提示缺少lzop工具。这是一个压缩工具内核编译某些部分时会用到。按提示安装即可sudo apt-get install lzop安装后重新运行make zImage -j4。编译成功的话你会在arch/arm/boot/目录下找到生成的zImage文件这就是压缩后的Linux内核镜像。最后编译设备树Device Tree文件。设备树是描述硬件信息的一种数据结构告诉内核这个板子上有什么硬件、地址在哪里。make dtbs编译完成后针对我们这个板子的设备树文件100ask_imx6ull_qemu.dtb会出现在arch/arm/boot/dts/目录下。3.4 替换镜像验证成果编译生成的新内核和设备树并不会自动替换QEMU使用的旧文件。我们需要手动把它们“部署”上去。找到之前下载的QEMU系统镜像目录ubuntu-18.04_imx6ul_qemu_system/imx6ull-system-image/把里面的zImage和100ask_imx6ull_qemu.dtb备份一下比如加个.bak后缀然后将我们刚编译好的两个文件复制进去覆盖。# 假设当前在linux-4.9.88目录 cp arch/arm/boot/zImage /path/to/ubuntu-18.04_imx6ul_qemu_system/imx6ull-system-image/ cp arch/arm/boot/dts/100ask_imx6ull_qemu.dtb /path/to/ubuntu-18.04_imx6ul_qemu_system/imx6ull-system-image/现在回到镜像目录再次运行启动脚本比如./qemu-imx6ull-nogui.sh。观察启动过程中的内核版本信息如果显示的时间戳是你刚刚编译的时间或者你修改了内核源码里的版本字符串能看到你的自定义信息那就恭喜你成功运行了自己编译的内核4. 实战内核调试让问题无所遁形能编译和替换内核已经解决了大部分开发需求。但当我们写的驱动导致内核崩溃Oops或者想深入理解内核某个函数的执行流程时就需要更强大的工具——内核调试。在真实硬件上做内核级单步调试非常困难但在QEMU里这变得异常简单。4.1 配置支持调试的内核默认的配置文件可能没有开启所有的调试选项。为了获得最好的调试体验我们需要确保内核编译时包含了调试符号和KGDB内核调试器支持。首先进入内核配置菜单make menuconfig这是一个基于文本的图形化配置界面。使用方向键导航回车进入子菜单或选择选项空格键勾选[*]表示编译进内核[M]表示编译为模块[ ]表示不编译。我们需要重点检查以下几个地方Kernel hacking - Kernel debugging确保这个是选中的。Kernel hacking - Compile-time checks and compiler optionsCompile the kernel with debug info(DEBUG_INFO)必须选中。这会在内核镜像中包含调试符号这样GDB才知道代码地址和变量名的对应关系。Reduce debugging information(DEBUG_INFO_REDUCED)不要选我们要完整信息。Kernel hacking - KGDB: kernel debugger确保KGDB: kernel debugger被选中。在Device Drivers等区域确保你正在开发或调试的驱动比如一个字符设备驱动被编译进了内核[*]而不是模块[M]这样在早期启动阶段就能调试。配置完成后保存退出。然后重新编译内核zImage和设备树dtbs。记住每次修改.config后都需要重新编译。4.2 以调试模式启动QEMU要让QEMU等待调试器连接需要在启动命令中加入特殊的参数。我们修改启动脚本或者直接使用命令行。最方便的是复制一份原有的启动脚本比如qemu-imx6ull-nogui.sh命名为qemu-imx6ull-debug.sh然后修改它。找到原来启动QEMU的那行长命令通常以qemu-system-arm开头在里面添加以下几个关键参数-s 这是-gdb tcp::1234的简写意思是让QEMU在TCP的1234端口上开启一个GDB服务器等待调试器连接。-S大写S。这个参数告诉QEMU在启动时暂停CPU的执行。也就是说虚拟机一上来就冻结住直到调试器GDB发出继续运行的命令。这对于调试内核启动初期的代码至关重要。修改后的命令片段可能看起来像这样qemu-system-arm -M mcimx6ul-evk -m 512M -kernel ./imx6ull-system-image/zImage \ -dtb ./imx6ull-system-image/100ask_imx6ull_qemu.dtb ... \ -s -S \ # 新增的调试参数 -nographic ...保存脚本然后运行它./qemu-imx6ull-debug.sh。你会发现终端卡住了没有像往常一样输出启动日志。这就对了因为虚拟机CPU被-S参数暂停了正在等待调试器的指令。4.3 使用GDB连接并调试现在我们需要另一个终端窗口。在这个新终端里进入你的内核源码根目录linux-4.9.88。首先启动GDB并指定带调试信息的内核镜像文件vmlinux注意不是zImagevmlinux是未经压缩的、包含完整调试符号的内核文件它在源码根目录下。arm-linux-gnueabihf-gdb vmlinux如果你系统里没有安装arm-linux-gnueabihf-gdb可能需要安装交叉编译工具链对应的gdb包或者使用gdb-multiarch这个通用工具。进入GDB交互界面后执行以下命令(gdb) target remote localhost:1234这条命令让GDB连接到本机localhost1234端口上QEMU开启的调试服务。连接成功后GDB会打印出当前CPU暂停的地址。现在你可以像调试普通程序一样调试内核了break start_kernel在内核启动的start_kernel函数处设置断点。这是内核C语言代码执行的起点。c或continue让被暂停的CPU继续执行。它会一直运行直到遇到你设置的断点。当断点命中时你可以list查看断点附近的源代码。next/n单步执行不进入函数内部。step/s单步执行进入函数内部。print variable_name打印变量的值。backtrace/bt查看函数调用栈这对于分析崩溃原因极其有用。info registers查看CPU寄存器的值。举个例子我想看看printk函数是如何被调用的。我可以先break printk然后c接着在QEMU那边的终端如果已经启动到shell里输入ls命令触发一些内核日志输出GDB就会在printk函数入口处停下来。这时我用bt命令就能清晰地看到是谁调用了printk整个调用链路一目了然。4.4 调试实战案例一个简单的内核模块理论讲完了我们来个更贴近实战的。假设我们写了一个简单的内核模块hello.ko加载时打印一条消息。但在QEMU里insmod后系统挂死了。怎么办复现问题在QEMU里确保能稳定复现这个挂死。定位代码我们怀疑问题出在模块初始化函数hello_init里。在GDB中给这个函数设断点break hello_init。注意模块的符号需要加载后才能被GDB识别。一种方法是先让内核启动完成在宿主机上用gdb连接后通过add-symbol-file hello.ko 0x地址来添加模块的调试符号地址可以从/sys/module/hello/sections/.text获取。更简单的方法是直接把模块编译进内核[*]这样在启动前就能设断点。分析现场让QEMU运行触发模块加载。GDB会在hello_init处停下。这时单步执行n或s观察每一步的执行情况检查变量值。当执行到某一行代码后系统失去响应问题很可能就出在这一行或它调用的函数里。查看调用栈如果发生了内核恐慌panicGDB可能会中断。使用bt查看崩溃时的调用栈结合内核输出的Oops信息就能精准定位到出错的具体代码行和原因。这种“修改代码 - 编译 - 启动调试 - 单步跟踪”的闭环在QEMU里几分钟就能完成一轮。而在真实硬件上每次修改都需要编译、烧录、重启一次循环可能就要十几分钟甚至更久。效率的提升是巨大的。5. 高效开发的进阶技巧与避坑指南环境搭好了基础调试也会了最后分享一些让我事半功倍的技巧和常见的“坑”。5.1 宿主机与QEMU虚拟机之间的文件交换调试时经常需要把编译好的测试程序或驱动模块传到QEMU里。有几种方法网络传输这是最推荐的方式。确保QEMU启动脚本里包含了网络配置通常使用-net nic -net user或更现代的-netdev user,idmynet等参数这样QEMU虚拟机就能通过虚拟网络访问宿主机。你可以在QEMU里使用scp或wget从宿主机下载文件。宿主机可以开启一个简单的HTTP服务器python3 -m http.server 8080然后在QEMU里wget http://宿主机IP:8080/你的文件。虚拟SD卡镜像QEMU可以模拟一个SD卡设备并将其映射到宿主机的一个镜像文件。你可以将文件挂载到宿主机复制进去然后在QEMU里挂载这个SD卡设备。这种方式更接近真实硬件操作。9P Virtio文件系统这是QEMU提供的一种高性能的宿主机-客户机文件共享机制。需要在启动QEMU时配置-virtfs参数并在客户机内核中启用9P文件系统支持。配置稍复杂但一旦配好共享目录就像本地目录一样方便。5.2 利用脚本自动化重复工作编译、替换、启动、调试这一套流程每天可能要重复几十次。手动操作太累写脚本我通常会写一个build_and_run.sh的脚本放在内核源码目录外。它的工作流程是进入内核目录执行make zImage -j$(nproc)和make dtbs。将生成的zImage和dtb文件复制到QEMU镜像目录覆盖旧文件。自动启动QEMU带或不带调试参数。更进一步可以结合inotifywait工具监控内核源码目录当检测到.c或.h文件变化时自动触发编译和重启QEMU实现某种程度的“热重载”效率飞起。5.3 常见问题与解决方案QEMU启动报错Could not initialize SDL这通常是SDL图形库的问题。确保按照前面的步骤正确安装了SDL依赖。如果还有问题尝试安装libsdl2-2.0-0和libsdl2-dev包或者直接使用-nographic参数运行无图形界面版本。编译内核时提示arm-linux-gnueabihf-gcc: not found百分之百是交叉编译工具链的路径PATH环境变量没设置对。请仔细检查export PATH...那一行命令确保路径指向了正确的bin目录。可以用echo $PATH查看用which arm-linux-gnueabihf-gcc验证。GDB连接失败提示Connection refused首先确认QEMU启动脚本里是否包含了-s -S参数。其次检查是否有其他QEMU进程占用了1234端口或者防火墙是否屏蔽了该端口。可以尝试换一个端口比如-gdb tcp::1235然后GDB用target remote localhost:1235连接。GDB断点无效提示Cannot access memory at address这通常是因为GDB使用的内核符号文件vmlinux与你正在运行的QEMU内核镜像zImage不匹配。务必确保你每次修改内核配置或代码并重新编译zImage后也使用同一套源码编译出的vmlinux文件来启动GDB。不要混用不同版本或不同配置编译出来的文件。QEMU虚拟机没有网络检查启动参数是否包含了网络设备配置。对于user模式的网络-net user虚拟机通常可以访问外网但宿主机不能直接访问虚拟机。如果需要双向访问可以考虑配置TAP网络桥接但这需要宿主机有相应的权限和配置。踩过这些坑之后你会发现QEMU模拟的imx6ul环境是一个非常稳定和强大的学习开发平台。它把编译-调试的循环从以“小时”计缩短到以“分钟”甚至“秒”计让你能把精力真正集中在代码逻辑和理解系统原理上。我现在做任何内核或驱动相关的实验第一反应都是先到QEMU环境里跑一遍验证通了再上真机这已经成了我的肌肉记忆。希望这份详细的指南也能帮你建立起这样一套高效的工作流。