news 2026/9/13 2:33:41

Ubuntu 22.04源码安装Bochs:打造x86模拟调试环境

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Ubuntu 22.04源码安装Bochs:打造x86模拟调试环境

写这篇东西其实挺感慨的。我最早接触 Bochs 还是在大学做操作系统课程实验的时候,那时候为了调试一个 bootloader,在 Windows 上用 Bochs 折腾了一整晚。后来转到 Linux 平台,发现 Ubuntu 上虽然能用 apt 直接装一个 bochs,但只要你想手动编译、想开调试器、想加一些特殊支持,就必须走源码安装这条路。这次我在 Ubuntu 22.04 LTS 上完整走了一遍源码安装 Bochs 的流程,踩了几个坑,也摸索出一些经验,整理出来给同样需要的人参考。这篇文章适合正在学操作系统、写内核模块、做引导程序调试,或者单纯想研究 x86 模拟器的朋友,看完之后你应该能在自己的机器上完整复现整个过程,并且知道每一步为什么要这么做。

Bochs 是个老牌的开源 x86 模拟器,最大的特点就是“纯软件模拟”,不像 QEMU 那样大量依赖硬件虚拟化,所以它在调试底层代码的时候反而特别合适——因为 CPU 指令执行流程完全可控,断点、单步、寄存器查看这些调试功能做得很完整。源码安装的意义在于,你可以自己控制编译选项,把调试器编译进去,还能选择和自己的开发环境最匹配的显示库和调试接口,这是发行版预编译包很难做到的。

我先从整体思路上给大家拆解一下这次安装的完整方案,然后逐步讲依赖准备、configure 选项、编译过程和常见问题。文章里我会把我在安装时踩过的坑和排查过程一并写出来,方便你对照。

1. 整体设计与方案选型

在介绍具体命令之前,我想先把整个思路理清楚。很多人一上来就./configure && make && make install,结果中途报错就开始盲目百度,其实问题往往出在最开始的准备阶段。

1.1 源码安装与 apt 安装的差异

Ubuntu 22.04 的软件源里确实有 bochs,但版本比较旧,而且默认不带调试器支持。你执行apt install bochs装完之后,运行起来发现就是一个纯模拟器,按Ctrl-C进不了调试模式,很多需要单步跟踪的场景根本做不了。源码安装第一个好处就是版本新,Bochs 官方仓库的 master 分支长期保持更新,对新处理器的指令集支持也更完整。

第二个好处是可定制性。源码安装时可以自己决定要不要编译内置调试器,要不要支持 GDB 远程调试,要不要加反汇编功能,显示输出用 X11 还是 SDL。这些选项在预编译包里基本是固定的,你拿到什么就是什么。比如你做内核调试,通常希望指令执行到某条地址就停住,然后看寄存器和内存状态,这就需要把--enable-debugger--enable-disasm打开,这两个功能在 apt 版本里是默认关闭的。

第三个好处是安装路径可控。源码安装默认是/usr/local/bin,和你系统自带的/usr/bin互不干扰,后期你想卸载只需要删掉对应目录就行,不会影响系统其他软件。这一点对于需要在多台机器之间切换开发环境的人来说特别友好。

1.2 我需要什么版本的 Bochs

当前 Bochs 官方最新发布版本是 2.7 系列,源码包可以直接从官网下载。我这次用的是bochs-2.7.tar.gz,在 Ubuntu 22.04 上编译没有任何问题。如果你想用更新的开发版,也可以直接从 GitHub 的 main 分支克隆源码,但注意开发版有时候会遇到依赖库版本变化导致的编译期警告,这对新手来说不太好处理,所以我个人建议就用官方 release 包,稳定第一。

Bochs 2.7 对 Ubuntu 22.04 的兼容性非常好,因为它的配置脚本能自动检测到系统自带的库,而且 GCC 11、12 都支持得很好。如果你用的是 Ubuntu 22.04 之前的版本,比如 20.04,那需要注意 GCC 版本可能要额外装一些兼容头文件,这个后面我会提。

1.3 环境准备与依赖分析

在任何源码编译之前,第一件事是装构建工具链。Bochs 的编译需要 GNU make、GCC 编译器和一些开发头文件。一个常见的错误是新装的 Ubuntu 默认只装了基础系统,连 build-essential 都没有,所以 configure 阶段就会各种失败。

我建议先执行一次系统更新,然后安装基础工具链:

sudo apt update sudo apt upgrade -y sudo apt install -y build-essential make gcc g++ git

这里面的build-essential包含了 GCC、G++、make 等一整套编译工具,是源码安装的基础。你可能看到网上很多教程直接跳过这步,导致后续编译失败,实际上是环境不完整。

然后要装 Bochs 编译时需要的一些图形和输入库。Bochs 的显示输出依赖于图形环境,在 Linux 上通常有 X11 和 SDL 两种方式可以选。我推荐两个都装,因为有的场景用 X11 更稳,有的场景用 SDL 更好。相关的开发头文件有这些:

sudo apt install -y libx11-dev libxrandr-dev libxinerama-dev libxext-dev sudo apt install -y libsdl2-dev libgtk-3-dev sudo apt install -y libncurses5-dev libncurses-dev

这里说明一下各个库的作用:

  • libx11-dev:X Window 系统的基础开发库,Bochs 用--with-x11编译时会链接它。
  • libsdl2-dev:SDL2 图形库,比 X11 在新硬件上的兼容性更好,按键响应也更快。
  • libgtk-3-dev:GTK3 图形库,Bochs 也支持用 GTK 做显示输出。
  • libncurses-dev:文本终端控制库,Bochs 的调试器命令行界面依赖它。

如果你只是文本模式运行 Bochs,不配置图形界面,理论上可以不装 X11 和 SDL。但是你做操作系统实验时通常要看屏幕输出,所以图形库几乎必须装。而且装上这些库之后 configure 脚本就能自动识别,省掉很多手工指定路径的麻烦。

2. 源码获取与 configure 配置

依赖装好之后,接下来就是下载源码和配置编译参数。这一步是整个安装过程最核心、也最容易犯迷糊的部分,因为 Bochs 的 configure 选项非常多,每个选项背后都有实际场景在做支撑。

2.1 从官网下载源码包

Bochs 官方下载地址非常稳定,我一般直接用 wget 拉取 2.7 的源码包:

cd ~ wget https://sourceforge.net/projects/bochs/files/bochs/2.7/bochs-2.7.tar.gz tar -zxvf bochs-2.7.tar.gz cd bochs-2.7

如果你访问官方源慢,也可以从 GitHub 的镜像仓库拉取 release 分支,只是注意 GitHub 上的是 git 仓库,需要先克隆再切到 release 标签,稍微麻烦一点。我个人优先用官方 tar 包,干净直接。

下载完成后,建议先看一眼源码目录下的 README 和 CHANGES 文件,里面会写明这个版本有哪些已知问题和依赖要求。经验丰富的人通常不会跳过这一步,因为很多版本兼容性问题其实 README 里已经写得很清楚了。

2.2 configure 关键选项解读

Bochs 的 configure 脚本是通过 autoconf 生成的,执行./configure --help可以列出所有支持的选项。新手看到几百行选项肯定会懵,但实际上我们常用的就这么几个,我挑重点讲一下。

先说我这次用的完整配置命令:

./configure \ --enable-debugger \ --enable-disasm \ --enable-readline \ --enable-x86-64 \ --enable-smp \ --enable-cpu-level=6 \ --enable-pci \ --enable-usb \ --enable-sb16 \ --enable-ne2000 \ --enable-all-optimizations \ --enable-plugins \ --with-x11 \ --with-sdl2

逐个解释每个选项的用意:

--enable-debugger是 Bochs 的杀手锏功能。它会把内置调试器编译进去,在模拟器运行时可以随时中断执行,查看寄存器、内存、反汇编、设置断点。如果你要靠 Bochs 调试 bootloader 或内核,这个选项必须开。

--enable-disasm打开反汇编支持。调试器里能直接显示当前指令的可读汇编形式,否则你只能看到一个硬编码地址和原始字节,根本没法排错。我在调试引导程序时就是靠这个功能定位到一条跳转指令执行异常的。

--enable-readline让调试器支持命令行编辑和补全。调试会话中输入地址、符号、命令的时候会方便很多。

--enable-x86-64这个很关键,因为 Bochs 默认可能只支持 32 位模式。如果你后面要研究 64 位内核或者长模式切换,这个必须开。我这次就是冲着 x86-64 支持去的。

--enable-smp启用多核模拟。做多核调度实验时用得上,如果不做这方面的研究,这个选项可以不开,能节省一些编译时间。

--enable-cpu-level=6指定模拟 CPU 的最高等级为 Pentium Pro 级别,也就是支持比较新的指令集特性。Bochs 里 CPU 等级最高通常就是 6,日常模拟完全足够。

--enable-pci--enable-usb--enable-sb16--enable-ne2000分别是 PCI 总线、USB 控制器、声卡和网卡的支持。这些不是必须的,但如果你想让模拟环境更接近真实硬件,就都开上。研读设备驱动代码的时候,这些模拟设备能提供很大的便利。

--enable-all-optimizations让编译器在编译 Bochs 的 CPU 核心时开启优化。这个能让模拟器的运行速度更快一些,但代价是调试时指令级精细步进可能有一点影响。我个人建议开启,因为现代编译器的优化已经很成熟了,对调试的干扰极小。

--enable-plugins开启插件机制,让部分硬件仿真模块作为动态库加载。这个不是必须的,但是我习惯开启,方便后续单独调试某个模块。

--with-x11--with-sdl2是指定图形输出方式。前面已经提到,X11 和 SDL2 都装了,这里两个都写,configure 会自己选择优先使用哪个。只用一种的话也没问题,但两个都开的话,后续切换显示环境时不用重新编译。

2.3 configure 执行与结果校验

执行 configure 脚本后,你会看到一长串输出检查信息,就像下面这样:

checking for gcc... gcc checking for C compiler default output file name... a.out checking whether the C compiler works... yes checking for X11 libraries... yes checking for SDL2... yes ...

关键是要确认最后没有报错,尤其要看 X11 和 SDL 的检测结果是否为 yes。如果显示 no,说明对应的开发头文件没有装全,返回去把依赖装上再重新跑。另外还要留意--enable-debugger是否生效,你可以在输出里搜关键字debugger,会看到类似config.status: creating config.h这样的提示,确认功能被编译进了配置文件。

configure 成功之后,源码目录下会生成一个Makefile,它是整个编译过程的枢纽。你可以用grep CONFIG_DEBUGGER Makefile快速确认调试器是否真的被打开。

另外一个小细节,configure 执行完之后,建议顺手把编译环境变量导出来,特别是线程数,这样 make 的时候就能利用多核编译:

export MAKEFLAGS="-j$(nproc)"

这一步可以大幅缩短编译时间,尤其是 Bochs 的 CPU 核心代码量很大,单线程编译可能要十几分钟,多线程能压缩到两三分钟。

3. 编译过程与安装验证

配置完成之后就是 compile 和 install,这个过程通常比较顺利,但也不是没有坑。我把我在编译时遇到的问题和解决办法都写出来,你可以对照自己的情况排查。

3.1 make 编译与常见编译报错

执行编译:

make

如果前面依赖都装好了,编译应该是顺顺利利的。Bochs 的编译信息会刷屏一样滚过去,中间可能夹杂一些 warning,比如编译器提示某个函数未使用、某个类型转换不安全,这些一般不影响最终生成,忽略即可。

在我这次安装过程中,唯一一次编译中断是因为我一开始没装libncurses-dev,导致调试器的终端界面库找不到的头文件。报错信息大概是:

error: ncurses.h: No such file or directory

这种问题很好解决,回去执行:

sudo apt install -y libncurses5-dev libncurses-dev

然后再 make 就正常了。所以你如果编译报错,先回头排查依赖库是否完整,而不是急着在源码上做修改。

编译完成后,在源码目录下会生成一个bochs可执行文件。你可以用ls -l bochs看一下大小和权限,正常情况下的 bochs 可执行文件有几十 MB,因为里面打包了 CPU 核心、设备模拟和调试器。

如果想确认编译出来的 Bochs 是否真的支持调试器,可以执行:

./bochs --help

正常输出里会有--dbglog相关的说明,而且启动之后按Ctrl-C能进入监控模式,那就说明 debugger 编译进去了。

3.2 make install 与安装位置

编译成功后执行安装:

sudo make install

默认安装路径是/usr/local/bin/bochs。这个路径在 Ubuntu 的 PATH 环境变量里通常是包含的,所以安装完之后你直接输入bochs就能启动。

验证安装:

which bochs bochs --help

which bochs应该输出/usr/local/bin/bochs。然后bochs --help能看到版本号和用法,版本号应该是2.7

另外,Bochs 安装时会往/usr/local/share/bochs目录下拷贝 BIOS 和 VGABIOS 文件。这几个固件文件非常重要,模拟 x86 PC 启动过程中必须有它们。安装完之后如果你发现运行 Bochs 时提示找不到 BIOS 文件,多半是bochsrc配置文件里的路径写错了,我后面单独讲这个问题。

3.3 快速跑一个最小镜像验证

安装成功之后,我们最好做一次最小化验证,确保模拟器真的能启动。先别急着写什么复杂的操作系统,就用 Bochs 自带的 BIOS 和 VGABIOS 直接启动一个空软盘镜像即可。

创建一个简单的测试目录:

mkdir -p ~/bochs-test cd ~/bochs-test

然后用 Bochs 自带的工具bximage创建一块虚拟软盘镜像。bximage在源码目录的bximage子目录下,如果你执行make install了,它通常也被安装到了/usr/local/bin/bximage

bximage -mode=floppy -fd=test.img -size=1.44

这里我不展开 bximage 的全部参数,后面调试磁盘镜像的时候会细说。现在你只需要知道这个命令会生成一个 1.44MB 的软盘镜像test.img

接下来写一个最简的bochsrc配置文件。Bochs 启动时会找当前目录下的.bochsrcbochsrc.txt作为配置文件。我习惯显式指定,所以创建test.bxrc

cat > test.bxrc << 'EOF' config_interface: textconfig display_library: x11 romimage: file=/usr/local/share/bochs/BIOS-bochs-latest vgaromimage: file=/usr/local/share/bochs/VGABIOS-lgpl-latest floppya: 1_44=test.img, status=inserted boot: floppy log: bochsout.log panic: action=ask EOF

这里每一行的作用:

  • config_interface: textconfig表示用文本方式交互配置,方便命令行操作。
  • display_library: x11指定用 X11 显示输出,如果你的环境没有 X11,可以改成sdl2
  • romimagevgaromimage指定 BIOS 文件路径。这里路径是/usr/local/share/bochs/下,如果你的安装目录不同,用find /usr/local -name "BIOS*"查一下实际路径。
  • floppya指定软盘镜像。
  • boot: floppy指定启动设备为软盘。
  • log指定日志输出文件。
  • panic: action=ask表示遇到 fatal 错误时暂停并询问,方便观察故障点。

然后运行:

bochs -q -f test.bxrc

-q表示跳过交互式配置问答,直接读取配置文件并启动。启动后你会看到 Bochs 的窗口弹出来,里面是模拟的 BIOS 启动画面,因为软盘上没有任何可启动代码,最终会停留在Boot failed或者类似的提示。这就说明你的 Bochs 安装成功了。

如果你看到这里,整个安装流程就已经走完了。但是我还有一堆实际中踩的坑和经验想分享,这些内容单独放在下一节,能帮你省下很多排查时间。

4. 常见问题与排查技巧

源码安装 Bochs 的坑主要集中在三块:依赖缺失、显示库配置、BIOS 路径。我按实际频率整理了一个速查表,并补充了一些我在调试过程中的独家经验。

4.1 编译期问题速查表

错误现象可能原因解决方法
X11/Xlib.h: No such file or directory缺少 libx11-devsudo apt install libx11-dev
SDL.h: No such file or directory缺少 SDL2 开发库sudo apt install libsdl2-dev
ncurses.h: No such file or directory缺少 ncurses 开发库sudo apt install libncurses5-dev libncurses-dev
gtk/gtk.h: No such file or directory缺少 GTK 开发库sudo apt install libgtk-3-dev
configure 输出X11 no虽然检测到 X11,但没有安装开发符号文件确认libx11-dev已安装,重跑 configure
make时编译中断undefined reference to 'tputs'ncurses 链接顺序问题确保安装libncurses-dev后重新 configure

这几种错误我都实际遇到过,尤其是 ncurses 的链接问题,它不是缺头文件,而是库的链接顺序在 configure 时没对上。最简单的办法是把libncurses-dev装好之后全部清掉重新 configure 一次,不要硬改 Makefile。

4.2 运行时“找不到 BIOS”问题

Bochs 启动时如果提示找不到 BIOS 文件,百分之九十九是bochsrc里的路径设置不对。解决办法是先确认 BIOS 文件到底安装到了哪里:

find /usr/local -iname "BIOS*" -o -iname "VGABIOS*"

然后把你查到的真实路径填进bochsrc。另外注意 Bochs 的 BIOS 文件名在不同版本略有差异,2.7 版本常见的是BIOS-bochs-latestVGABIOS-lgpl-latest。如果你只看到BIOS-bochs-2.7之类的名字,也完全能用,路径对上就行。

还有一个容易忽略的点是文件权限。如果你用普通用户运行 Bochs,而 BIOS 文件在/usr/local/share/bochs下,通常是有读权限的,但如果文件权限特殊,也会导致读取失败。这时执行sudo chmod 644 /usr/local/share/bochs/BIOS*就能解决。

4.3 显示输出的选择与配置

Bochs 的图形显示在 Ubuntu 22.04 上优先推荐 X11,因为它不需要额外运行一个 SDL 事件循环,在纯 GNOME 环境里启动会更稳定。如果你像我一样是在虚拟机里跑 Ubuntu,可能没有完整的 X11 显示环境,这时 SDL2 会更友好,因为它自带窗口管理器和事件处理。

我自己的做法是编译时--with-x11--with-sdl2都开,需要切换显示库时,只改 bochsrc 里display_library这一行就行,不需要重新编译。比如:

display_library: sdl2

如果你打算用 VNC 远程访问模拟器屏幕,需要额外加--enable-vnc选项重新编译,这个我没有在这次安装里用,但如果有远程实验室需求的话,建议提前加上。

4.4 使用内置调试器的基本操作

编译时开了--enable-debugger之后,默认运行 Bochs 并不会自动进入调试模式,除非你在 bochsrc 里写debugger: enable,或者在启动时加-d参数。我一般喜欢启动时按Ctrl-C手动进入,因为很多场景下我需要先让它自由跑一段,等到关键位置再挂起。

进入调试器后,常用的命令有:

  • help:查看所有命令,一开始用不到那么多,但知道有这货就行。
  • ccontinue:继续执行。
  • sistepi:单步执行一条指令。
  • info reg:查看通用寄存器状态,包括 RAX、RBX、RIP 这些。
  • x /nfu addr:查看内存内容,例如x /4bx 0x7c00表示从 0x7c00 开始的 4 个字节。
  • u addr:反汇编地址附近的内容,比如u /10 0x7c00会列出 0x7c00 开始的 10 条指令。
  • break addrb addr:设置断点,例如b 0x7c00让它停在引导代码入口。

调试 bootloader 时,最常用的组合是:先启动,然后按Ctrl-C,再设置断点b 0x7c00,然后c让它继续跑。BIOS 完成自检后会跳转到0x7c00,正好踩在断点上,就能用si一条指令一条指令地跟下去。这个过程对理解 CPU 启动流程非常有帮助。

4.5 GDB 远程调试配置

如果你更喜欢用 GDB 的界面来调试,比如配合 VSCode 的 gdb 插件,Bochs 也支持作为 GDB 的远程目标。需要在 configure 时加上--enable-gdb-stub

./configure --enable-gdb-stub --enable-debugger ...

然后 bochsrc 里加一行:

gdbstub: enabled=1, port=1234

启动 Bochs 后,它会监听本地 1234 端口。此时在另一个终端启动 GDB:

gdb (gdb) target remote :1234

之后你就能用 GDB 的breakstepiinfo registers等命令远程调试模拟的 CPU 了。这种方式对习惯现代调试工具链的人来说非常方便,还能直接看 C 源码级别的单步,定位逻辑错误比单纯用 Bochs 内置命令行要高效得多。我曾经用它配合一个自己写的引导扇区代码,把一条跳转指令的问题定位到源码里某个变量越界,非常直观。

4.6 创建虚拟磁盘镜像并挂载

前面我们只用了软盘镜像,实际做操作系统实验的时候,更多会创建虚拟硬盘。Bochs 自带bximage工具,不过命令行交互比较麻烦,我更喜欢直接用它生成一个镜像文件,然后用bochs配合合适的硬盘接口启动。

例如创建一个 100MB 的 IDE 磁盘镜像:

bximage -mode=create -hd=100 -imgmode=flat -q disk.img

这里的-imgmode=flat表示生成一个平铺的原始镜像,后续可以用losetup或者直接编译到内核的 loop 设备来读写。我给原始镜像绑定 loop 设备时建议尽量使用普通用户权限加--read-only当数据盘挂载,避免误写导致 Bochs 启动异常:

sudo losetup /dev/loop0 disk.img

不过注意,Bochs 模拟的是整个磁盘控制器,所以你不要让 Linux 内核直接读写/dev/loop0的分区表而当真正的系统盘去挂载,否则容易出现分区格式错乱。更好的做法是用 Bochs 启动后,在模拟环境里用内置的 FD 或 HD 工具操作镜像内容,或者配合mtools软件直接往 FAT 镜像里写文件。如果你对分区结构不熟,建议先用fdisk把镜像分区格式化好再放数据,这一点我踩过很深很深的坑,希望你能避开。

4.7 我的几条实操心得

最后分享几条我最想强调的经验。第一条,不要跳过 configure 阶段的输出检查,尤其是那些以checking for开头的行,它们决定了整个编译是否顺畅。如果发现某个关键库显示 no,先补库再继续,不要硬着头皮往下走。

第二条,bochsrc 配置文件的路径要养成写绝对路径的习惯,尤其是 BIOS 文件和磁盘镜像。相对路径在 Bochs 切换工作目录时很容易出问题,我之前因为在/root目录下跑一个../test/bh这样的配置,结果磁盘镜像找不到,排查了大半天。

第三条,遇到 Bochs 启动黑屏或者崩溃,第一时间打开日志文件bochsout.log,里面会有详细的错误原因。比如磁盘镜像格式不对、BIOS 文件版本不匹配、内存配置过小,日志都会明明白白告诉你。很多时候看日志比猜原因要快得多。

第四条,如果你只是为了跑个现成的系统,源码安装确实费劲,直接用 apt 版本就够了。但一旦你开始调试引导代码、研究 CPU 模式切换、跟踪设备初始化,源码安装的 Bochs 就是你最得力的工具。它能让你在一条指令的执行路径上停留,观察每一个寄存器的变化,这种精细度是 QEMU 都很难做到的。

从 Ubuntu 22.04 上的源码编译到跑通第一个模拟启动,整个过程也就是二十分钟的事。之后你可以拿它做很多事情,比如配合nasm写一个最小的 bootloader,在 0x7c00 处打印一行字符,然后通过 Bochs 的调试器逐条跟踪,那种“控制底层硬件”的感觉,是纯软件学习很难替代的。我个人在实际操作中最常做的,就是用 Bochs 配合 GDB 调一个自己写的 FAT12 引导扇区,每一行汇编指令的执行情况全都一清二楚。这种经验一旦建立,后面学内核、学设备驱动、学虚拟化底层都会顺畅很多。

最后再分享一个小技巧:把常用的 configure 参数保存成脚本,放到源码目录里,下次重新编译或者换机器时直接执行,省得每次都敲那一长串命令。我在~/bochs-build.sh里写了一份,以后升级 Bochs 版本只需要同步改版本号和解压目录,其余全部复用。希望这篇记录能帮你少走一些弯路,顺利把 Bochs 源码装起来。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 2:30:56

基于JavaWeb的社区老人健康管理系统开题报告写作指南

开题报告这种东西&#xff0c;很多人一开始都以为就是走个形式&#xff0c;随便写写交给导师就完事了。但等到真做起来才发现&#xff0c;开题报告其实是整个毕业设计最重要的“定盘星”——题目定得准不准、技术选型合不合理、功能边界清不清晰&#xff0c;全在这一篇里见真章…

作者头像 李华
网站建设 2026/9/13 2:28:35

Jmeter安装配置与性能测试实战:从环境搭建到命令行压测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 2:28:29

Qt程序打包全攻略:从DLL依赖到安装包制作与工具对比

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 2:25:20

开源项目HivisionIDPhotos:本地部署自动生成证件照,省钱又安全

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 2:24:26

医院蓝牙AoA定位系统选型指南:从原理到验收的实操细节

医院里说要上蓝牙AoA定位系统&#xff0c;这两年我听到的频率明显高了。护理部想找输液中的患者、后勤想看资产在哪、急诊想追踪胸痛病人动线、保卫处又希望重点区域有人滞留能告警——需求五花八门&#xff0c;但采购流程一启动&#xff0c;问题就全堆到信息科或者基建智能化负…

作者头像 李华
网站建设 2026/9/13 2:24:07

ODPS SQL正则表达式实战指南:函数、转义与性能优化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华