news 2026/10/17 1:06:13

Windows下用MinGW构建HDF5的完整方案:CMake配置与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Windows下用MinGW构建HDF5的完整方案:CMake配置与避坑指南

简介:这份HDF5 mingw版本是面向Windows环境下使用MinGW编译器进行C++开发的预编译库资源。HDF5作为科学计算与数据分析领域常用的层级数据存储格式,支持复杂数据类型与高效数据访问;该版本针对Mingw73_32环境优化,配合CMake即可快速集成到跨平台项目中,免去自行编译源码的繁琐流程。压缩包共132个文件,约9.42MB,其中包含81个头文件、5个静态库(.a)、5个导入库(.lib)、5个动态库(.dll)以及23个工具可执行文件(.exe),另有CMake配置与pkg-config描述文件,便于不同构建方式下链接使用。目前已有145人学习下载。对于需要在MinGW环境下读写HDF5文件、构建数据处理程序的开发者来说,这份资源提供了可直接调用的头文件与库文件组合,同时内置hdf5、hdf5_cpp等静态库版本,可灵活选择静态或动态链接方式,显著降低环境配置门槛,适合中高级C++开发者作为数据存储环节的基础组件。

1. 为什么 Windows 上要用 HDF5 的 MinGW 版本:一个串口数据落盘场景引出的选择

有个数据采集类的项目(模拟项目 X)需要把高速串口数据流写成 HDF5 格式。开发环境是 Windows,工具链是 MinGW-w64。跑代码时发现官方预编译的 HDF5 库是为 MSVC 准备的,静态库和导入库格式对不上。折腾了一晚上,才意识到需要一套“MinGW 版本的 HDF5”。这篇内容就是把这套方案讲清楚。适合谁:用 MinGW 写 C/C++、要在 Windows 上创建或读取 HDF5 文件的开发者;或者想自编译、避免 MSVC 依赖的嵌入式/NVMe 数据采集场景。读完你能得到可复现的构建命令、CMake 集成方式,以及我踩过的坑。

2. 用 CMake 在 MinGW 下从源码构建 HDF5:一条命令跑通与关键选项

2.1 官方 tarball 与 CMake 构建的最小步骤

从官网或镜像获得 HDF5 源码包(例如 1.14.x)。MinGW-w64 建议使用 x86_64 架构,否则后面写入大数组会很麻烦。我一般把源码解压到无空格的路径,例如C:\work\hdf5-1.14.x。

# 在原生 Windows 命令提示符(CMD)中执行,注意使用 MinGW-w64 的 cmake 和 gcc cmake -S C:/work/hdf5-1.14.x -B C:/work/build-mingw \ -G "MinGW Makefiles" \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=C:/work/hdf5-install \ -DBUILD_SHARED_LIBS=ON \ -DBUILD_TESTING=OFF \ -DHDF5_BUILD_TOOLS=ON \ -DHDF5_BUILD_EXAMPLES=OFF \ -DHDF5_BUILD_HL_LIB=ON \ -DHDF5_BUILD_CPP_LIB=ON mingw32-make -j 4 mingw32-make install

逻辑说明:-G "MinGW Makefiles"是关键的生成器,它让 CMake 生成 GNU Makefile 而不是 Visual Studio 工程;-DBUILD_SHARED_LIBS=ON表示生成动态库,后面的链接部分会解释为什么推荐动态库;BUILD_TESTING=OFF能省掉一多半编译时间;HDF5_BUILD_HL_LIB是高层 API 库(h5hl),很多第三方工具链会用到;HDF5_BUILD_CPP_LIB是 C++ 接口,纯 C 项目可以关掉以缩短构建时间。

cmake 配置时如果提示找不到 MinGW 生成器,不要管 Fortran 之类的附带报错,先确认mingw32-make和gcc都在PATH里。建议使用原生 Windows 安装的 MinGW-w64,而不是只装了 MSYS2 内部包。配置完成后,mingw32-make -j 4会并行编译,install会把头文件、库和工具放到C:/work/hdf5-install。

2.2 构建选项怎么设:只开需要的能力,关掉无关依赖

HDF5 的 CMake 选项非常多,默认的自动检测经常帮你开一堆找不到的依赖。我常用的参数组合如下表:

参数推荐值作用
BUILD_SHARED_LIBSON生成hdf5.dll和导入库libhdf5.dll.a
HDF5_ENABLE_ZLIB_SUPPORTOFF或ON开启 gzip 压缩;OFF可避免外部 zlib 依赖
HDF5_ENABLE_SZIP_SUPPORTOFF版权和依赖问题多,默认关掉
HDF5_ENABLE_THREADSAFEOFF(多线程写建议ON)打开后库内部加锁,会牺牲性能
HDF5_BUILD_TOOLSON生成h5dump等命令行工具
CMAKE_C_FLAGS-O2发布优化

压缩支持取决于你是否需要H5Pset_deflate。如果只是做数据落盘,deflate 很有价值,一个 2GB 的文本传感器数据压缩后能到 300MB。但代价是你要先编译 zlib 的 MinGW 版本。我一般用-DZLIB_ROOT指向已经用同工具链编好的 zlib,或者第一次编译先关掉它,跑通后再开。

注意区分HDF5_ENABLE_ZLIB_SUPPORT和HDF5_ENABLE_SZIP_SUPPORT:szip 是另一种压缩算法,不是 deflate,HDF5 高层 API 里默认不推荐。szip 在 MinGW 下经常翻车,我建议直接OFF。

2.3 看看构建产物:.dll/.a/.lib 各是什么角色

安装目录会生成include、bin、lib、share等文件夹。bin下面是hdf5.dll和h5dump.exe等工具;lib下面是libhdf5.dll.a(导入库)和libhdf5.a(静态库),以及可能的libhdf5_hl.dll.a、libhdf5_cpp.dll.a。

为什么这么重要?MinGW 的.dll.a是“导入库”,它的作用是链接期告诉链接器“这个符号在哪个 DLL 里”,而不是把实现代码塞进 exe。MSVC 的.lib也可以做导入库,但 MSVC 的导入库格式是 COFF,GNU 链接器不认识。如果你直接拿官方预编译的 HDF5(MSVC 版本)里的hdf5.lib给 MinGW 用,链接器会报 “file format not recognized”。这就是标题里“MinGW 版本”的核心原因:你需要生成 GNU 格式的导入库和配套头文件。

另一个容易误会的点:静态库libhdf5.a会把代码完整编译进 exe,且多个程序同时用会各自保留一份副本,部署反而麻烦。我优先选动态库,这样hdf5.dll可以在多个程序间共享,也方便替换版本。代价是发布 exe 时要一起带上 DLL。

3. 把 HDF5 接进你的 CMake 项目:链接配置与最小可运行代码

3.1 用 find_package 接 HDF5 还是手工指定路径

HDF5 安装后会生成hdf5-config.cmake,所以标准做法是find_package(HDF5)。在 MinGW 环境下,关键是让它找到 MinGW 版本的库,而不是 MSVC 的。

cmake_minimum_required(VERSION 3.18) project(H5Demo C) set(CMAKE_C_STANDARD 11) # 指定 HDF5 安装前缀 set(HDF5_ROOT "C:/work/hdf5-install" CACHE PATH "HDF5 install path") find_package(HDF5 REQUIRED COMPONENTS C) add_executable(demo main.c) target_link_libraries(demo PRIVATE ${HDF5_LIBRARIES}) target_include_directories(demo PRIVATE ${HDF5_INCLUDE_DIRS})

逻辑说明:HDF5_ROOT告诉 find_package 去哪里找hdf5-config.cmake。COMPONENTS C表示只要 C 接口,减少链接负担。如果 find_package 失败,CMake 会自动回退到找hdf5.h和libhdf5.*,但这有可能意外匹配到 MSVC 安装的旧版本,所以务必显式设置HDF5_ROOT。

如果 find_package 还是失败,则用手工指定:

set(HDF5_INCLUDE "C:/work/hdf5-install/include") set(HDF5_LIB "C:/work/hdf5-install/lib/libhdf5.dll.a") target_include_directories(demo PRIVATE ${HDF5_INCLUDE}) target_link_libraries(demo PRIVATE ${HDF5_LIB})

参数说明:手工指定时一定要用libhdf5.dll.a而不是libhdf5.a。前者是动态库导入库,后者是静态库。用错了也能链接,但最终 exe 运行时不会自动带上 DLL 内容,反而可能出现符号重复或找不到 DLL 的怪问题。这个区别值得花一点时间理解,后面会省很多事。

3.2 一个能写能读的最小 C 程序

验证 HDF5 能不能用,最好的办法是写一个最小程序:创建文件、写一个 2x2 整数数组、读出来打印。

#include "hdf5.h" #include <stdio.h> int main() { hid_t file_id = H5Fcreate("test.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); if (file_id < 0) return 1; int data[2][2] = {{1, 2}, {3, 4}}; hsize_t dims[2] = {2, 2}; hid_t space_id = H5Screate_simple(2, dims, NULL); hid_t dset_id = H5Dcreate(file_id, "matrix", H5T_STD_I32BE, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); herr_t status = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); printf("write status=%d\n", status); H5Dclose(dset_id); H5Sclose(space_id); H5Fclose(file_id); return 0; }

逻辑说明:先创建文件test.h5,然后创建二维整数数据集matrix并写入。注意H5T_STD_I32BE和H5T_NATIVE_INT的区别:前者指定磁盘上为大端(跨平台可移植),后者是当前系统原生格式。MinGW 在 x86 上基本是小端,但如果文件要交换,显式指定磁盘类型更专业。

参数说明:H5Screate_simple的第二个参数dims是数组维度,第三个NULL表示不设上限;H5P_DEFAULT是所有默认属性集合的简写,不打算调参数时能少写很多代码。如果H5Dwrite返回负数,一般是数据空间不匹配或句柄无效,先检查每步返回值。

读取时用H5Dread到内存,再用H5T_NATIVE_INT转换。这里有个常见坑:写盘类型用了H5T_STD_I32BE,读出来直接配H5T_NATIVE_INT,HDF5 会自动做字节序转换,没问题。但如果你写的是H5T_STD_I32LE,遇到别的写入者可能是 BE,就会读乱。日常我建议统一用H5T_NATIVE_INT,除非明确要做跨平台数据交换。

3.3 动态库运行时找不到的坑:PATH 与复制 DLL

编译链接都成功后,运行demo.exe可能会报“无法启动此程序,因为计算机中丢失 hdf5.dll”。这在 Windows 上太常见了。原因是 exe 运行时按PATH和 exe 所在目录查找 DLL,MinGW 构建的 exe 不会像 MSVC 那样把 DLL 路径硬编码进去。

解决方式从简单到复杂:

  1. 把hdf5.dll复制到 exe 同目录,这是最直接的。
  2. 把 HDF5 安装目录的bin加入系统PATH,但部署到其他机器时不方便。
  3. 用 CMake 的 POST_BUILD 自动复制:
add_custom_command(TARGET demo POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "C:/work/hdf5-install/bin/hdf5.dll" $<TARGET_FILE_DIR:demo>)

参数说明:$<TARGET_FILE_DIR:demo>是 CMake 生成器表达式,指代 exe 输出目录;copy_if_different只在文件变化时复制,避免每次构建都刷新。如果你同时用了hdf5_hl.dll、hdf5_cpp.dll,也需要一并复制。这个步骤最容易遗漏,等到现场运行时才发现“缺库”的问题,属于典型的返工项。

4. HDF5 MinGW 构建的避坑指南:五个典型故障与排查

4.1 链接时 “undefined reference” 但明明导出了函数

现象:在 CMake 中链接了libhdf5.dll.a,编译时头文件正常,链接时报大量undefined reference to 'H5Fcreate'之类的错误。

原因:最常见的是find_package(HDF5)找到了 MSVC 版本的头文件,头文件中的HDF5_API宏被展开成__declspec(dllimport)。MinGW 看到dllimport后会要求从导入库中找符号,但导入库本身是 GNU 格式,符号匹配不上,于是报未定义。

解决:检查头文件里的宏定义,确保HDF5_BUILT_AS_DYNAMIC_LIB被正确设置。推荐在 CMake 里加:

add_compile_definitions(HDF5_BUILT_AS_DYNAMIC_LIB)

如果还不行,用nm libhdf5.dll.a | grep H5Fcreate确认符号是否存在。如果符号不存在,说明构建 HDF5 时没有生成动态导出,回头检查BUILD_SHARED_LIBS是否为ON。这个坑我最初踩过,最后发现是find_package没设置HDF5_USE_STATIC_LIBRARIES,导致库类型匹配混乱。MinGW 下要么全动态,要么全静态,不要混用。

4.2 编译器版本不匹配:用错 MinGW 子版本导致 C++ ABI 错乱

现象:C 接口的程序能跑,C++ 接口(链接hdf5_cpp)在构造函数里崩溃,或者std::string传出乱码。

原因:HDF5 的 C++ 库是用 g++ 编译的,而 MinGW-w64 有posix线程模型和win32线程模型之分。比如用posix的 g++ 编译 HDF5 C++ 库,你的项目却用默认的win32线程模型 g++ 编译,标准库的std::mutex实现不同,ABI 不兼容。

解决:确保构建 HDF5 和构建你的项目用的是同一个编译器和同一套线程模型。运行g++ -v查看Thread model是posix还是win32。我的规则是:HDF5 用哪个编译器编的,项目就用那个编译器编。所以写 CMake 时用set(CMAKE_CXX_COMPILER C:/mingw64/bin/x86_64-w64-mingw32-g++.exe)指定绝对路径,并且要和编译 HDF5 时完全一致。

另外注意:64 位 HDF5 库不能链接到 32 位项目。如果你用i686-w64-mingw32-gcc编译项目,链接 64 位libhdf5.dll.a会报 “file format not recognized”,这个错误比较低级,但容易在“快速试一把”的时候踩到。

4.3 依赖链断裂:zlib/szip 在 MinGW 下的难兄难弟

现象:CMake 配置时提示Could NOT find ZLIB,或者编译时找不到zlib.h,如果开了压缩支持。

原因:HDF5 需要 zlib 的 MinGW 版本,但很多 Windows 上现成的 zlib 预编译包是给 MSVC 用的。用 MinGW 去链接 MSVC 的zlib.lib,格式不兼容;如果直接下载 zlib 源码用 MinGW 编译,需要额外花时间处理。

解决:最简单的是在构建 HDF5 时先关掉 zlib 压缩:

cmake -S ... -B ... -DHDF5_ENABLE_ZLIB_SUPPORT=OFF

等 HDF5 本体跑通了,再单独解决依赖。如果必须用 zlib,推荐用 vcpkg 安装 zlib 的 MinGW 版本(第 6 章会讲)。手动编译 zlib 也是成熟方案:用同一个 MinGW 生成器编译并安装,再给 HDF5 传-DZLIB_ROOT=你的zlib安装目录。

这里的关键是:zlib 的 CMake 构建也要用-G "MinGW Makefiles",确保生成 GNU Makefile。如果直接用 MSYS2 里现成的 zlib,但你的编译器是原生 MinGW,同样会 ABi 不匹配。一句话:整个依赖链必须走同一套工具链。

4.4 构建过程里 “cmake -G” 指定生成器失败的玄学

现象:在命令行执行cmake -G "MinGW Makefiles" ..,提示Could not create named generator MinGW Makefiles,或者构建时提示sh.exe not found in PATH。

原因:CMake 的 “MinGW Makefiles” 生成器依赖很微妙。首先你得安装的是 MinGW-w64,而不是 Cygwin 或 MSYS2 内部的 bash 环境。其次它要求能找到mingw32-make,如果PATH里同时有 MSYS2 的make.exe,CMake 会尝试用sh.exe执行构建命令,然后报错。

解决:使用一个干净的 Windows 命令提示符(CMD),只把 MinGW-w64 的bin目录加入PATH,比如C:\mingw64\bin。不要在 MSYS2 的 shell 里跑原生 CMake。如果还是报sh.exe,在 CMake 配置时显式指定:

cmake -S . -B build -G "MinGW Makefiles" -DCMAKE_MAKE_PROGRAM=C:/mingw64/bin/mingw32-make.exe

这个坑很“玄学”:同样的命令在 CMD 里能运行,在 MSYS2 里就迷失在路径转换上。所以我现在的习惯是写一个脚本,先set PATH=C:\mingw64\bin;%PATH%,再执行 cmake。

4.5 头文件路径混乱:include 了源码目录还是安装目录

现象:编译时出现hdf5.h: No such file,或者编译通过但函数签名对不上,比如H5Fcreate的参数数量不对。

原因:HDF5 源码根目录下也有一个hdf5.h,它和安装目录里的头文件不同。源码里的头文件需要配合一大批内部头文件才能正常 include;如果你把源码根目录加到 include 路径,就可能误用了开发版本的头文件,而链接的却是安装好的库。

解决:永远把CMAKE_INSTALL_PREFIX下的include放在第一位。在 CMake 里检查:

message(STATUS "HDF5_INCLUDE_DIRS = ${HDF5_INCLUDE_DIRS}")

确保它指向C:/work/hdf5-install/include。如果指向源码目录,在find_package之前设置HDF5_ROOT为安装根。另一个相关坑:安装目录的include下有H5pubconf.h,它由配置阶段生成,包含很多关键宏。如果这个文件没被找到,会看到大量“缺少宏定义”错误,所以make install这一步不能省略。

5. 验证你的 MinGW 版 HDF5 可用性:从文件回读到内存泄漏检查

5.1 用 h5dump 验证文件结构

安装目录的bin下有h5dump.exe。运行:

h5dump test.h5

输出会列出数据集名称、类型、尺寸和数据。如果输出正常,说明 HDF5 核心写入正确。调试时很有用的还有-H参数,只显示头信息:

h5dump -H test.h5

参数说明:-H只显示头信息不显示数据,适合快速确认数据集结构。h5dump由HDF5_BUILD_TOOLS=ON生成。如果构建时没开这个选项,可以用别的工具,但h5dump是最顺手的。

典型输出包括:

HDF5 "test.h5" { GROUP "/" { DATASET "matrix" { DATATYPE H5T_STD_I32BE } } }

验证要点:确认DATATYPE和你写入的类型匹配。如果你写的是H5T_NATIVE_INT,在 x86 上会显示H5T_STD_I32LE,这是正常的。

5.2 写一段回归测试同时验证 C 和 C++ 接口

我习惯在项目里加一个h5_smoke_test.c,只做“写-读-比对”三件事。这个测试可以放进本地脚本,也可以作为集成测试的一部分。

#include "hdf5.h" #include <assert.h> #include <string.h> int main() { const char* fname = "smoke.h5"; int write_buf[4] = {1, 2, 3, 4}; hsize_t dims[1] = {4}; hid_t file = H5Fcreate(fname, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); assert(file >= 0); hid_t space = H5Screate_simple(1, dims, NULL); hid_t dset = H5Dcreate(file, "data", H5T_NATIVE_INT, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); assert(H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, write_buf) >= 0); H5Dclose(dset); H5Sclose(space); H5Fclose(file); file = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT); dset = H5Dopen(file, "data", H5P_DEFAULT); int read_buf[4] = {0}; H5Dread(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, read_buf); assert(memcmp(write_buf, read_buf, sizeof(write_buf)) == 0); H5Dclose(dset); H5Fclose(file); return 0; }

逻辑说明:这个测试覆盖了文件创建、数据集创建、写入、关闭、重新打开、读取、比较。assert在调试版本里有效,足够暴露问题。如果这一步就挂,不用继续往下排查,说明 HDF5 库本身有问题,回到第 2 章重新构建。

5.3 在项目里做内存与线程检查

另一个验证维度是内存安全。MinGW 下可以用gcc的地址消毒器(ASan)来编译你的程序,但需要确认 HDF5 库也是用-fsanitize=address编译的,否则 ASan 只能检查你自己的代码。我一般用更轻量的方法:在 Debug 构建里开 HDF5 的错误回调,让它把运行时错误打印出来。

线程方面,如果你的数据采集是多线程写入的,建议做一个小压力测试:4 个线程同时打开同一个 HDF5 文件、写入不同数据集。注意:HDF5 默认不是线程安全的,除非构建时开了HDF5_ENABLE_THREADSAFE。多线程并发写文件会数据损坏或崩溃。我的习惯是先不加锁,用单线程方案确认逻辑正确,再决定是否开线程安全。开线程安全会损失一部分性能,但换来稳定。

6. 一个更顺手的做法:用 vcpkg 安装 HDF5 的 mingw 版本

如果你不想自己啃源码构建,还有一个更顺手的路线:vcpkg。vcpkg 里提供了 HDF5 的 port,并且支持 MinGW 三元组(triplet)。我最近几个项目都用这条路径,尤其当 zlib、szip 依赖链变得复杂时,vcpkg 会自动把所有依赖用 MinGW 编译好,免去第 4 章那些互相匹配的问题。

vcpkg install hdf5:x64-mingw-dynamic

这条命令让 vcpkg 以x64-mingw-dynamic三元组编译并安装 HDF5。三元组里x64表示目标架构,mingw表示使用 MinGW-w64 工具链,dynamic表示生成动态库。如果你想要静态链接,可以用x64-mingw-static,但动态库在 Windows 上更新 HDF5 版本时更方便。

安装完成后,头文件在installed/x64-mingw-dynamic/include,库文件在.../lib,DLL 在.../bin。接着在项目 CMake 中接入 vcpkg 的 toolchain:

cmake -S . -B build \ -DCMAKE_TOOLCHAIN_FILE=C:/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake \ -DVCPKG_TARGET_TRIPLET=x64-mingw-dynamic

这里的CMAKE_TOOLCHAIN_FILE会全局接管编译器和库查找,不需要再设置HDF5_ROOT。VCPKG_TARGET_TRIPLET必须和安装时一致,否则 CMake 会去别的目录找库,然后报“无法打开 hdf5.lib”之类的错误。vcpkg 路径最好是无空格纯英文,比如C:\vcpkg,中文路径容易让工具链脚本死在路径编码上。

vcpkg 方案也有边界:它选定的 HDF5 版本由 port 维护,你没法临时改某个编译选项。比如想开HDF5_ENABLE_THREADSAFE,就得修改 port 文件或走源码编译。另外,vcpkg 默认会编译 release 和 debug 两套库,磁盘空间紧张时可以加-DVCPKG_BUILD_TYPE=release只编 release。

我现在遇到 MinGW+HDF5 的需求,会先跑一遍 vcpkg,如果能把 demo 编过,就直接用;如果卡在 vcpkg 的某个编译错误超过 30 分钟,就切回源码 CMake 那条路。这个判断帮我减少了很多无谓的折腾。希望帮到你。

本文还有配套的精品资源,点击获取

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

两串电芯被动均衡实战:MP2642GR-Z与PIC32MX664F064L的BMS设计

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

作者头像 李华
网站建设 2026/10/17 1:05:15

Tomcat与war包部署实战:从目录结构到打包上线的完整指南

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

作者头像 李华
网站建设 2026/10/17 1:05:12

图像分割技术演进路线:从FCN到U-Net与DeepLab的架构变革

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

作者头像 李华
网站建设 2026/10/17 1:04:13

基于MP2642GR-Z与STM32F410RB的两串电池主动均衡方案设计与实现

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

作者头像 李华
网站建设 2026/10/17 1:03:56

开源三国杀引擎开发105天:事件驱动规则引擎与状态机设计

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

作者头像 李华
网站建设 2026/10/17 1:02:54

储能电池主动均衡方案:MP2642GR-Z与MKV42F64VLH16实战

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

作者头像 李华