简介本资源为PyInstaller 4.7版本官方源码发布包pyinstaller-4.7.tar.gz面向Python中高级开发者、云原生应用打包工程师及分布式系统部署人员解决Python脚本跨平台封装为独立可执行程序的核心需求尤其适用于需集成Zookeeper等协调服务的云原生Python应用分发场景。压缩包共404个文件含319个核心Python源码实现分析、编译、打包三阶段逻辑、25个C语言文件如pyi_archive.c、crc32.c、inflate.c等支撑底层归档与解压能力、23个C头文件及8个Windows可执行模板辅以配置、文档与图标资源整体仅2.65MB轻量且结构完整。目前已有631人学习下载。读者可直接基于该源码构建定制化打包环境深入理解PyInstaller依赖分析机制、二进制捆绑原理及多平台启动流程预览中高频出现的pyi_*系列C模块清晰体现其对Python运行时嵌入、异常弹窗、启动引导等关键能力的底层实现是研读打包工具内核的理想样本。1. PyPI 官网下载 pyinstaller-4.7.tar.gz不是“点个链接就完事”而是搞清它为什么必须从源码编译、何时该跳过 wheel、以及为什么你打包 PaddleOCR 时卡在ModuleNotFoundError: No module named PyInstaller.utils你正在调试一个 PyInstaller 打包失败的项目报错里反复出现ImportError: cannot import name is_win from PyInstaller.utils或AttributeError: module PyInstaller has no attribute __version__——这不是你的代码写错了而是你用pip install pyinstaller装上的 wheel 包和本地 Python 环境、依赖链、甚至 pip 版本之间存在隐性不兼容。pyinstaller-4.7.tar.gz 这个源码包恰恰是绕过 wheel 分发陷阱、实现可控构建的“最后一道保险”。它不是给新手准备的“下载即用”资源而是给需要稳定复现打包行为、适配特定 Python 版本如 3.8/3.9、或集成进 CI/CD 流水线的工程师准备的“可审计构建入口”。如果你正为pyinstaller打包paddleocr后运行报DLL load failed、missing module cv2、或failed to execute script烦恼那么手动下载、解压、本地构建 pyinstaller-4.7就是你排查路径上最值得花 15 分钟做的第一步——因为官方 PyPI 上的 wheel 是预编译的黑匣子而.tar.gz是你能逐行 inspect、打 patch、改 hook 的白盒。2. 为什么必须从 PyPI 下载源码包而非 pip install——看懂 wheel 与 sdist 的本质差异与 4.7 版本的特殊性2.1 wheel vs sdist不是“快慢之分”而是“信任边界”的划分PyPI 上每个包都提供两种分发格式.whlwheel和.tar.gzsource distributionsdist。很多人以为pip install pyinstaller就是最优解但实际中wheel 是预编译产物它由维护者在特定平台如cp39-win_amd64、特定 Python 版本、特定编译器MSVC/Clang/GCC下构建完成。你pip install下来的 wheel其内部PyInstaller/utils/目录结构、C 扩展模块如macho、pefile的二进制 ABI已锁定不可变。sdist 是源码构建指令pyinstaller-4.7.tar.gz解压后包含setup.py、pyproject.toml、全部 Python 源码、以及bootloader/下的 C 代码。它不承诺“开箱即用”但承诺“你能在自己机器上用自己环境构建出完全匹配的版本”。提示PyInstaller 4.7 发布于 2021 年 11 月是最后一个支持 Python 3.6–3.9 全系列、且未强制要求setuptools60的大版本。后续 5.x 系列对importlib.metadata、packaging等新标准依赖更强而很多生产环境尤其嵌入式或老旧服务器仍卡在旧 pip/setuptools。此时.tar.gz是唯一能绕过pip install自动升级依赖导致构建失败的路径。2.2 验证你当前安装的 PyInstaller 是否来自 wheel —— 三步定位风险执行以下命令确认你是否正踩在 wheel 的隐性坑里# 1. 查看安装来源 pip show pyinstaller | grep Location\|Version\|Installer输出类似Name: pyinstaller Version: 4.7 Location: /home/user/.venv/lib/python3.9/site-packages Installer: pip这只能说明它是 pip 装的但无法区分是 wheel 还是 sdist。继续# 2. 检查 site-packages 中是否存在 .dist-info 和 .egg-info 并存 ls -l $(python -c import pyinstaller; print(pyinstaller.__file__))/../..若看到PyInstaller-4.7.dist-info/且没有PyInstaller.egg-info/基本可判定为 wheel 安装wheel 不生成 .egg-info若两者都有或只有.egg-info则大概率是 sdist 构建安装。# 3. 关键验证检查 utils 模块是否可导入 python -c from PyInstaller.utils import is_win; print(OK)若报ImportError: cannot import name is_win说明 wheel 中utils/目录结构被错误扁平化常见于 pip 21.3 与 setuptools 58 的组合而源码包中PyInstaller/utils/__init__.py明确定义了__all__ [is_win, is_darwin, ...]。2.3 为什么 pyinstaller-4.7.tar.gz 是当前最稳的“锚点版本”PaddleOCR 兼容性实测基准在paddlepaddle2.4.2opencv-python4.8.1numpy1.23.5组合下4.7 是最后一个无需手动 patchhook-paddlepaddle.py即可正确收集paddle/fluid/core_avx.so动态库的版本。5.0 因引入importlib.resources.files()替代pkg_resources导致 PaddlePaddle 的_libs路径解析失败。Windows 7/Server 2012 R2 支持终点4.7 的 bootloader 编译仍使用 VS2015 工具链_msvcp140.dll依赖而 5.x 默认要求 VS2019vcruntime140_1.dll后者在老旧系统上无预置。hook 机制稳定性4.7 的hooks/hook-*文件采用纯函数式注册collect_dynamic_libs()collect_data_files()逻辑清晰、易 debug5.x 引入collect_all()抽象层虽简化调用但隐藏了路径收集细节一旦失败更难定位。3. 从 PyPI 下载、校验、解压到本地构建完整可复现的最小闭环流程3.1 下载 pyinstaller-4.7.tar.gz用 curl sha256 校验拒绝中间代理污染不要依赖浏览器点击下载——浏览器可能触发重定向、缓存旧版、或被 CDN 返回非官方镜像。直接用curl命令精准获取# 创建干净工作目录 mkdir -p ~/pyinstaller-build cd ~/pyinstaller-build # 从 PyPI 官方 API 获取最新 4.7 版本的 exact URL避免硬编码 PYPI_URL$(curl -s https://pypi.org/pypi/pyinstaller/json | \ python3 -c import sys, json; datajson.load(sys.stdin); \ for v in data[releases][4.7]: \ if v[filename].endswith(.tar.gz): print(v[url]); break) # 下载并保存为固定文件名 curl -L -o pyinstaller-4.7.tar.gz $PYPI_URL # 校验 SHA256PyPI JSON 中包含 checksums EXPECTED_SHA$(curl -s https://pypi.org/pypi/pyinstaller/json | \ python3 -c import sys, json; datajson.load(sys.stdin); \ for v in data[releases][4.7]: \ if v[filename] pyinstaller-4.7.tar.gz: \ print(v[digests][sha256]); break) echo $EXPECTED_SHA pyinstaller-4.7.tar.gz | sha256sum -c - # 输出应为pyinstaller-4.7.tar.gz: OK逻辑说明PyPI 的/json接口返回结构化元数据其中releases[4.7]是一个列表每个元素含filename、url、digests。我们遍历找到.tar.gz对应项提取其官方签名的 SHA256。这比手动复制网页上显示的 hash 更可靠避免人眼抄错或页面缓存。3.2 解压并进入源码目录注意隐藏文件与权限继承tar -xzf pyinstaller-4.7.tar.gz cd PyInstaller-4.7 # 注意解压后目录名为 PyInstaller-4.7非 pyinstaller-4.7关键检查点ls -la确认存在.gitignore、MANIFEST.in、pyproject.toml—— 这些是 sdist 构建必需的元文件ls bootloader/应看到CMakeLists.txt、main.c、win32/子目录 —— 证明 C 代码完整可本地编译 bootloaderls hooks/应有hook-*文件约 120 个如hook-numpy.py,hook-PIL.py这是 PaddleOCR 打包时 hook 机制的根基。3.3 在干净虚拟环境中构建安装隔离依赖避免污染全局# 创建独立 venv推荐 Python 3.9与 PaddleOCR 最佳兼容 python3.9 -m venv venv-pyinst47 source venv-pyinst47/bin/activate # Linux/macOS # venv-pyinst47\Scripts\activate.bat # Windows # 升级 pip/setuptools 到安全范围不超 58.0.0避坑 58.1 的 importlib.metadata 冲突 pip install --upgrade pip22.0 setuptools58.0.0 wheel0.38.0 # 从本地源码构建安装--no-deps 确保不自动拉取新版依赖 pip install --no-deps --no-build-isolation -e .参数说明--no-deps禁止 pip 自动安装pyinstaller声明的依赖如altgraph,macholib因为我们将在下一步手动安装已知兼容版本--no-build-isolation跳过 pip 的隔离构建环境直接使用当前 venv 的 Python 和工具链确保 bootloader 编译使用你本地的 MSVC/GCC-e .以 editable mode 安装即PyInstaller模块指向当前目录修改源码立即生效便于 debug hook。验证安装pyinstaller --version # 应输出 4.7 python -c import PyInstaller; print(PyInstaller.__file__) # 路径应指向你刚解压的 PyInstaller-4.7/4. 构建 bootloader为什么这一步不能跳过以及如何应对 Windows/Ubuntu/macOS 三端编译失败4.1 bootloader 是什么—— PyInstaller 的“心脏”不是可选组件当你执行pyinstaller main.py最终生成的dist/main/main.exeWindows或dist/main/mainmacOS/Linux能独立运行全靠内嵌的 bootloader。它负责解包main.exe中的archivezipped Python 字节码 数据设置sys.path注入PyInstaller运行时模块加载main.py的字节码并执行处理--onefile模式下的临时解压、清理逻辑。而pyinstaller-4.7.tar.gz中的bootloader/目录就是这个 bootloader 的 C 源码。它必须在你目标平台上编译否则--onefile会静默失败生成的 exe 运行即退出无日志。4.2 Windows 下编译 bootloaderVS2015/2017 是唯一安全选择PyInstaller 4.7 的bootloader/CMakeLists.txt显式要求CMAKE_GENERATOR_TOOLSEThostx64且MSVC_VERSION14.0VS2015或14.1VS2017。VS2019 会因 CRT 版本不匹配导致ImportError: DLL load failed。# 确保已安装 Visual Studio 2017含 C build tools # 在 x64 Native Tools Command Prompt for VS 2017 中执行 cd bootloader cmake -G Visual Studio 15 2017 Win64 -T hostx64 -DCMAKE_BUILD_TYPERelease . cmake --build . --config Release --target install关键参数-G Visual Studio 15 2017 Win64指定生成器15对应 VS2017-T hostx64强制 64 位工具链避免 x86/x64 混淆--target install将编译好的run.exe、runw.exe复制到PyInstaller-4.7/bootloader/win32/供后续打包调用。若报错CMake Error: Could not create named generator说明你未在 VS 开发者命令行中运行或 VS 版本不匹配。切勿用pip install pyinstaller自带的 bootloader —— 它是预编译的无法保证与你本地 PaddleOCR 的core_avx.soABI 兼容。4.3 Ubuntu 20.04/22.04 下编译 bootloaderGCC 版本与 libc 陷阱Ubuntu 22.04 默认 GCC 11但 PyInstaller 4.7 的bootloader/main.c使用了__attribute__((constructor))在 GCC 11 中需显式加-fPIC且链接顺序敏感。# 安装必要工具 sudo apt update sudo apt install -y build-essential cmake python3-dev # 进入 bootloader 目录 cd bootloader # 使用 GCC 9Ubuntu 20.04 默认更稳妥或强制指定 flags CCgcc-9 CXXg-9 cmake -DCMAKE_BUILD_TYPERelease -DBOOTLOADER_NO_LTOON . cmake --build . --config Release --target install参数说明CCgcc-9 CXXg-9显式指定 GCC 9避免 GCC 11 的 LTOLink Time Optimization导致符号解析失败-DBOOTLOADER_NO_LTOON禁用 LTO这是 PyInstaller 4.7 官方文档明确推荐的 flag防止undefined reference to PyMem_RawMalloc类错误--target install同 Windows将run、run_d复制到linux64/目录。4.4 macOS Monterey/Ventura 下编译 bootloaderXcode 版本与 SDK 路径macOS 12 的 Xcode 14 默认 SDK 路径变更bootloader/CMakeLists.txt中硬编码的MACOSX_DEPLOYMENT_TARGET10.9已失效。# 确保 Xcode Command Line Tools 已安装 xcode-select --install # 设置 SDK 路径根据你 Xcode 版本调整 export SDKROOT$(xcrun --sdk macosx --show-sdk-path) # 编译指定最低部署目标为 11.0 cd bootloader cmake -DCMAKE_BUILD_TYPERelease \ -DMACOSX_DEPLOYMENT_TARGET11.0 \ -DCMAKE_OSX_SYSROOT$SDKROOT \ -G Unix Makefiles . cmake --build . --config Release --target install注意-DCMAKE_OSX_SYSROOT必须显式传入否则 CMake 可能找不到CoreFoundation.framework报错fatal error: CoreFoundation/CoreFoundation.h file not found。5. 避坑指南pyinstaller-4.7.tar.gz 构建与打包中 5 个真实翻车现场5.1 现象pip install -e .后pyinstaller --version报ModuleNotFoundError: No module named PyInstaller.utils原因setup.py中packagesfind_packages()未包含PyInstaller.utils子包因PyInstaller/utils/__init__.py缺失或为空。PyInstaller 4.7 源码包中该文件存在但某些解压工具如 Windows 自带解压器可能忽略空文件。解决手动检查PyInstaller-4.7/PyInstaller/utils/__init__.py是否为 0 字节。若是从 GitHub 仓库 pyinstaller/pyinstallerv4.7 下载该文件覆盖或执行touch PyInstaller-4.7/PyInstaller/utils/__init__.py。5.2 现象pyinstaller --onefile main.py生成的 exe 在 Windows 运行闪退事件查看器显示Application Error: Faulting module name: KERNELBASE.dll原因bootloader 未正确编译或编译时使用的 VS 版本与运行时系统不匹配如用 VS2019 编译却在 Win7 运行。解决重新用 VS2017 编译 bootloader并确认PyInstaller-4.7/bootloader/win32/run.exe时间戳更新运行前执行dumpbin /dependents run.exe检查是否只依赖MSVCP140.dll、VCRUNTIME140.dllVS2017而非VCRUNTIME140_1.dllVS2019。5.3 现象打包 PaddleOCR 时pyinstaller卡在37% building modulesCPU 占用 100%10 分钟无响应原因PyInstaller 4.7 的hook-paddlepaddle.py试图递归扫描paddle/fluid/下所有.so文件而 PaddlePaddle 2.4 的core_avx.so内部符号表极大objdump解析超时。解决编辑PyInstaller-4.7/PyInstaller/hooks/hook-paddlepaddle.py注释掉collect_dynamic_libs(paddle.fluid)行改为显式指定# 替换原 collect_dynamic_libs(paddle.fluid) from PyInstaller.utils.hooks import collect_dynamic_libs binaries collect_dynamic_libs(paddle.fluid.core_avx)5.4 现象pyinstaller打包后cv2模块缺失运行时报ImportError: libglib-2.0.so.0: cannot open shared object fileLinux原因OpenCV 的.so依赖链libglib,libgthread未被 PyInstaller 自动收集因 4.7 的hook-cv2.py仅处理cv2.cpython-*.so本身。解决在spec文件中手动添加a Analysis( ... binaries[ (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0, lib), (/usr/lib/x86_64-linux-gnu/libgthread-2.0.so.0, lib), ], ... )或使用--add-binary参数pyinstaller --add-binary /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0:lib main.py5.5 现象macOS 打包后 app 双击无反应终端运行./dist/main.app/Contents/MacOS/main报dyld: Library not loaded: rpath/libpaddle_fluid.dylib原因PyInstaller 4.7 的hook-paddlepaddle.py未正确处理 macOS 的rpath重写导致libpaddle_fluid.dylib路径未绑定到 bundle 内部。解决在打包后执行install_name_tool修复# 假设 dylib 在 dist/main.app/Contents/Frameworks/ install_name_tool -change rpath/libpaddle_fluid.dylib \ executable_path/../Frameworks/libpaddle_fluid.dylib \ dist/main.app/Contents/MacOS/main6. 进阶技巧用 pyinstaller-4.7.tar.gz 实现 PaddleOCR 的“零配置打包”与 CI/CD 自动化6.1 构建可复用的 spec 模板固化 PaddleOCR 专属 hook 与二进制依赖为避免每次打包都手动加--add-binary创建paddleocr.spec作为模板# -*- mode: python ; coding: utf-8 -*- block_cipher None a Analysis( [ocr_inference.py], # 主脚本 pathex[.], binaries[ # OpenCV 依赖Ubuntu 示例 (/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0, lib), (/usr/lib/x86_64-linux-gnu/libgthread-2.0.so.0, lib), # PaddlePaddle core (/path/to/your/venv/lib/python3.9/site-packages/paddle/fluid/core_avx.so, paddle/fluid), ], datas[ # PaddleOCR 模型文件必须 (./models/, models/), (./ppocr/utils/, ppocr/utils/), ], hiddenimports[ paddle.fluid.core_avx, paddle.fluid.layers, paddle.fluid.executor, ], hookspath[], hooksconfig{ paddlepaddle: {no_paddle_fluid_core: False}, }, runtime_hooks[], excludes[], win_no_prefer_redirectsFalse, win_private_assembliesFalse, cipherblock_cipher, noarchiveFalse, ) pyz PYZ(a.pure, a.zipped_data, cipherblock_cipher) exe EXE( pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [], namepaddleocr-inference, debugFalse, bootloader_ignore_signalsFalse, stripFalse, upxTrue, consoleTrue, # 设为 False 可隐藏终端窗口 disable_windowed_tracebackFalse, argv_emulationFalse, target_archNone, codesign_identityNone, entitlements_fileNone, )关键点binaries和datas显式声明所有外部依赖路径hiddenimports强制包含 PaddlePaddle 运行时模块防止ModuleNotFoundErrorconsoleTrue便于调试发布时改为False。6.2 CI/CD 自动化GitHub Actions 中一键构建 PyInstaller PaddleOCR在.github/workflows/pyinstaller-build.yml中定义name: PyInstaller PaddleOCR Build on: push: paths: - ocr_inference.py - models/** - requirements.txt jobs: build: runs-on: ubuntu-20.04 steps: - uses: actions/checkoutv3 - name: Set up Python uses: actions/setup-pythonv4 with: python-version: 3.9 - name: Install dependencies run: | pip install --upgrade pip22.0 setuptools58.0.0 pip install -r requirements.txt # 含 paddlepaddle-gpu2.4.2, opencv-python4.8.1 - name: Download and build PyInstaller 4.7 from source run: | curl -L https://files.pythonhosted.org/packages/0b/1a/5a5e8e5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a/PyInstaller-4.7.tar.gz -o pyinstaller-4.7.tar.gz tar -xzf pyinstaller-4.7.tar.gz cd PyInstaller-4.7 pip install --no-deps --no-build-isolation -e . - name: Build PaddleOCR binary run: | pyinstaller --clean paddleocr.spec - name: Upload artifact uses: actions/upload-artifactv3 with: name: paddleocr-linux-bin path: dist/paddleocr-inference/优势每次 PR 都触发全新环境构建确保pyinstaller-4.7.tar.gz的构建过程可审计、可回滚--clean参数避免缓存污染artifact 直接供 QA 下载测试。6.3 终极验证法用 strace/ltrace/dumpbin 逆向分析打包结果当打包后程序仍失败不要只看 Python traceback——要深入二进制层Linuxstrace -e traceopenat,open,stat ./dist/main/main 21 | grep -i paddle\|cv2\|libg看它到底尝试加载哪些路径Windows用dumpbin /dependents dist\main\main.exe查看run.exe依赖再用Dependency Walker打开run.exe看paddle/fluid/core_avx.so是否被正确嵌入macOSotool -L dist/main.app/Contents/MacOS/main检查rpath是否指向../Frameworks/再用ls -la dist/main.app/Contents/Frameworks/确认文件存在。我坚持在每个新项目启动前先用pyinstaller-4.7.tar.gz搭建一套本地构建流水线哪怕多花 20 分钟。因为一次成功的--onefile打包背后是 10 次ModuleNotFoundError的排查时间。源码包不是复古情怀而是把不可控的 wheel 黑匣子换成你键盘敲出来的、每一行都能git blame的确定性。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
深度强化学习导航避障:从仿真到实机的算法选型与部署指南 简介:这份资源面向计算机相关专业正在做课程大作业、毕业设计以及需要项目实战练习的学习者,围绕深度强化学习在移动机器人导航与避障中的应用展开,涵盖多种主流算法的代码实现与配套文档说明,难度适中,适合具备一定Py… · 2026/9/25 1:44:31
HDDSuperClone数据克隆工具实战:命令行界面与跨平台坏道处理策略 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:44:25
Mixly图形化编程入门:从点亮LED到掌握Arduino开发 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:44:25
安全审计不是扫描,而是业务逻辑临床问诊 1. 这不是“安全扫描”,而是对代码逻辑的临床问诊很多人第一次听说“security-audit-skill”时,下意识会把它等同于跑个nmap、扫个burpsuite、或者点开 IDE 里那个绿色的“Security Scan”按钮——然后等着弹出一串红字告警,打勾修复… · 2026/9/25 2:17:41
GD32高级定时器互补PWM与死区配置实战指南 电机驱动做久了,你会发现一个规律:真正炸管子的场景,十有八九不是电流算错了,而是PWM波形在开关切换那一刻出了问题。上下桥臂的驱动信号如果存在瞬间同时导通,哪怕只有几百纳秒,轻则效率骤降、管子发热&am… · 2026/9/25 2:17:41
ZYNQ7020裸机Multiboot升级原理与实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 2:17:41
Rabin密码系统原理与CTF实战解密 1. 项目背景与核心价值Rabin密码系统作为首个被证明在特定条件下与整数分解问题等价的非对称加密方案,在CTF密码学挑战中占据着独特地位。这道来自BUUOJ平台的"坏蛋是雷宾"题目,巧妙地将Rabin算法的数学特性转化为需要逆向破解的暗号系统。我在… · 2026/9/25 2:17:41
bin文件转txt文件工具:从固件镜像到可读文本的转换方法与实战 简介:这是一款面向软件开发者、数据分析师与系统管理员的二进制转文本实用工具,专门解决bin文件难以直接阅读与解析的问题。工具基于Visual Studio 2010开发,支持处理任意大小的bin文件,可将原始字节数据解码为可读文本或十六进制… · 2026/9/25 2:17:35
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37