简介本资源为libdwg-0.4源码包面向需要读写AutoCAD DWG文件、又不愿承担商业授权费用的C语言开发者与图形软件爱好者。DWG是AutoCAD主流二维三维图形格式而libDWG以LGPL协议开源提供解析与生成DWG的能力libredwg则可视为其实现或分支适合有一定C语言与构建工具基础、希望将DWG支持集成进自有项目的中高级开发者。压缩包共71个文件约578KB以20个c源文件与9个h头文件为核心另含m4、in等构建配置脚本以及dwg、dxf示例图形、pdf文档、readme、install、changelog等说明文件覆盖从解码、对象处理到变量管理的完整模块。目前已有870人学习下载。通过阅读源码与构建脚本读者可理解DWG文件结构、编译流程与依赖配置掌握在目标系统上生成库文件并链接使用的方法为自建DWG处理工具或集成方案提供可复用的参考。1. libdwg 与 libredwg从一份 RAR 包到能读 DWG 的编译链路你手上大概率有这么个东西一个叫libdwg-0.4.RAR的压缩包解出来是一堆 C 源码目标是让程序能直接读 AutoCAD 的 DWG 文件。DWG 是闭源二进制格式官方 SDK 要授权所以开源圈子里真正能打的是libredwg——GNU 项目能解析 R12 到 2018 的 DWG还能转 DXF、JSON。而libdwg这个名字历史上出现过好几个同名小项目有的是早期实验性解析器有的只是 libredwg 的旧称或分支。所以第一步不是急着./configure而是先搞清楚你手里这份 0.4 到底是哪一支、依赖什么、能不能编过。这篇就按「先认清包 → 再搭编译环境 → 跑通最小解析 → 排掉典型坑 → 落到批量转换」的顺序走目标读者是需要在 Linux 或 Windows 上把 DWG 读进自己程序、又不想买商业库的工程师。编译原理那套词这里用不上我们要的是能跑起来的二进制。2. 认清 libdwg-0.4 这个包它和 libredwg 到底什么关系2.1 先解包看目录结构别急着编译拿到 RAR 先解出来Linux 下用unrar xWindows 下用 7-Zip 或 WinRAR 都行。解完先别动编译脚本花两分钟看目录这一步能省掉后面一半的翻车。unrar x libdwg-0.4.RAR cd libdwg-0.4 ls -la find . -maxdepth 2 -name configure* -o -name CMakeLists.txt -o -name Makefile* | head -20逻辑说明find这一行是在判断这个包用的是 autotools有configure、CMake有CMakeLists.txt还是手写 Makefile。三种构建系统的编译命令完全不同先认出来再动手。参数上-maxdepth 2限制搜索深度避免在大包里翻太久head -20只是防止输出刷屏。如果目录里有src/、include/、examples/这种结构基本是正经库如果只有几个.c文件加一个README那多半是早期实验版本功能有限别指望它能解析 2018 格式。2.2 判断它是不是 libredwg 的旧分支打开README、NEWS、ChangeLog或者configure.ac搜几个关键词grep -ri libredwg\|GNU README* NEWS* ChangeLog* configure.ac 2/dev/null | head grep -ri version configure.ac 2/dev/null | head如果出现libredwg字样说明这份 0.4 很可能是 libredwg 早期版本的打包那你可以直接去用新版 libredwg功能更全、bug 更少。如果完全没提 libredwg只写libdwg那它是一个独立小项目解析能力通常只覆盖 R12/R13 这种老格式遇到新版 DWG 会直接报错。这里有个血泪经验网上流传的libdwg-0.4很多是十几年前的快照依赖的 autotools 版本很老在新系统上autoreconf会报一堆宏未定义。遇到这种情况优先考虑换 libredwg 主线版本而不是硬啃老包。2.3 依赖清单编译前必须装齐的东西不管哪一支读 DWG 的库通常依赖这几样依赖作用缺失时的典型报错gcc / g编译器command not found: gccmake构建make: command not foundautoconf / automake / libtoolautotools 构建configure.ac: no proper invocation of AM_INIT_AUTOMAKEzlib-devel压缩数据解压cannot find -lzlibxml2-devel部分版本解析 XML 元数据libxml/tree.h: No such filepkg-config查找依赖路径Package zlib was not foundUbuntu/Debian 一把装sudo apt update sudo apt install -y build-essential autoconf automake libtool pkg-config zlib1g-dev libxml2-devCentOS/Kylin 系用yum install -y gcc gcc-c make autoconf automake libtool pkgconfig zlib-devel libxml2-devel。Kylin V10 上如果 gcc 版本太老低于 7后面编译 C99 代码会报错需要先升级工具链这是国产化环境里最常见的拦路虎。3. 把 libdwg 编出来autotools 与 CMake 两条路3.1 autotools 路线从 autoreconf 到 make install如果第 2 章确认是 autotools 项目标准流程是先生成 configure再配置、编译、安装。# 生成构建脚本-i 表示自动补装缺失的辅助文件 autoreconf -fi # 配置指定安装前缀关掉不需要的组件加快编译 ./configure --prefix/usr/local/libdwg \ --disable-shared \ --enable-static \ CFLAGS-O2 -g # 编译-j 用满 CPU 核数 make -j$(nproc) # 安装到前缀目录 sudo make install逻辑说明autoreconf -fi里的-f强制重新生成、-i自动安装缺失的install-sh、missing等辅助脚本老包缺这些文件时特别有用。--disable-shared --enable-static是只编静态库方便后面嵌进自己的程序不需要处理运行时动态库路径。CFLAGS-O2 -g保留调试符号出问题时能用 gdb 跟进去。参数怎么改如果你要编动态库给多个程序共用把--disable-shared换成--enable-shared如果只想快速验证能不能编过加--disable-dependency-tracking跳过依赖追踪能快不少。编译失败时先看config.log90% 的依赖问题都记在里面搜error和not found两个词基本能定位。3.2 CMake 路线老包新用更省心有些 libdwg 分支带CMakeLists.txt那就走 CMake比 autotools 干净。mkdir build cd build cmake .. -DCMAKE_INSTALL_PREFIX/usr/local/libdwg \ -DCMAKE_BUILD_TYPERelease \ -DBUILD_SHARED_LIBSOFF cmake --build . -j$(nproc) sudo cmake --install .逻辑说明-DCMAKE_BUILD_TYPERelease开优化-DBUILD_SHARED_LIBSOFF编静态库。CMake 的好处是依赖查找更明确缺 zlib 会直接告诉你Could NOT find ZLIB不像 autotools 那样藏在 config.log 里。如果 CMake 报Could NOT find ZLIB先确认zlib1g-dev装了再不行就手动指定-DZLIB_ROOT/usr。这类路径问题在交叉编译或国产系统上很常见。3.3 验证编译产物别装完就以为成了编完先别急着写业务代码用自带的示例或工具验证一下。# 看装出来的库和头文件 ls -l /usr/local/libdwg/lib ls -l /usr/local/libdwg/include # 如果有命令行工具直接拿一个 DWG 试 /usr/local/libdwg/bin/dwgread test.dwg 21 | head -30逻辑说明dwgread是 libredwg 系常见的读取工具能把 DWG 结构打印出来。如果你的包没有这个工具就自己写个最小程序链接库下一章给代码。21 | head -30是把错误也抓出来只看前 30 行避免大文件刷屏。如果dwgread报unknown DWG version说明这个库不支持你测试文件的版本换一个 R12 或 R2000 的老文件再试先确认库本身能跑通再谈格式覆盖。4. 写最小解析程序把 DWG 里的实体读出来4.1 链接库并读取文件头先写一个最小 C 程序只做一件事打开 DWG读出文件头里的版本号和实体数量。这一步能跑通说明库链接没问题。#include stdio.h #include dwg.h /* 头文件路径按实际安装调整 */ int main(int argc, char **argv) { if (argc 2) { fprintf(stderr, usage: %s file.dwg\n, argv[0]); return 1; } Dwg_Data dwg; memset(dwg, 0, sizeof(dwg)); /* 读取文件返回 0 表示成功 */ int err dwg_read_file(argv[1], dwg); if (err ! 0) { fprintf(stderr, read failed, code%d\n, err); return 2; } /* 打印版本和实体数量 */ printf(version: %s\n, dwg.header.version); printf(num objects: %d\n, dwg.num_objects); dwg_free(dwg); return 0; }逻辑说明dwg_read_file是核心入口把整个 DWG 解析进Dwg_Data结构。dwg.header.version是版本字符串dwg.num_objects是对象总数。最后必须调dwg_free释放内存否则大文件会泄漏。编译命令gcc -o read_dwg read_dwg.c \ -I/usr/local/libdwg/include \ -L/usr/local/libdwg/lib \ -ldwg -lz -lm参数说明-I指定头文件路径-L指定库路径-ldwg链接主库-lz是 zlibDWG 内部有压缩段-lm是数学库。如果报undefined reference多半是漏了-lz或库顺序不对把-ldwg放最前面、依赖库放后面。4.2 遍历实体提取线段和图层读文件头只是热身真正要用的是把实体遍历出来。下面这段遍历所有对象筛出线段LINE并打印起点终点。#include stdio.h #include string.h #include dwg.h int main(int argc, char **argv) { Dwg_Data dwg; memset(dwg, 0, sizeof(dwg)); if (dwg_read_file(argv[1], dwg) ! 0) return 1; for (int i 0; i dwg.num_objects; i) { Dwg_Object *obj dwg.object[i]; /* 只处理 LINE 类型实体 */ if (obj-type ! DWG_TYPE_LINE) continue; Dwg_Entity_LINE *line obj-tio.entity-tio.LINE; if (!line) continue; printf(LINE layer%s start(%.3f,%.3f) end(%.3f,%.3f)\n, obj-tio.entity-layer ? obj-tio.entity-layer-name : 0, line-start.x, line-start.y, line-end.x, line-end.y); } dwg_free(dwg); return 0; }逻辑说明dwg.object是对象数组obj-type判断实体类型DWG_TYPE_LINE是线段常量。obj-tio.entity-tio.LINE拿到线段的具体数据start和end是三维坐标。图层名从obj-tio.entity-layer-name取。参数说明坐标是 double打印用%.3f保留三位小数够工程用。如果要做 DWG 转 SHP这里拿到的就是几何源数据图层名对应 SHP 的属性字段。注意有些实体layer指针可能为空代码里做了判空这是实际跑数据时必加的防护否则遇到脏文件直接段错误。4.3 把结果输出成可用的中间格式直接打印只适合调试要落地得输出成 JSON 或 CSV方便后面转 SHP 或入库。/* 在遍历循环里把 LINE 输出成一行 CSV */ printf(%s,%.6f,%.6f,%.6f,%.6f\n, obj-tio.entity-layer ? obj-tio.entity-layer-name : 0, line-start.x, line-start.y, line-end.x, line-end.y);逻辑说明CSV 每行是「图层,起点X,起点Y,终点X,终点Y」用%.6f保证精度。重定向到文件就是./read_dwg test.dwg lines.csv。后面用 Python 的geopandas读这个 CSV 就能生成 SHP这就是热搜里「dwg转shp」最朴素的实现路径——不依赖任何商业转换器。参数说明如果 DWG 里有圆弧、多段线需要额外处理DWG_TYPE_ARC、DWG_TYPE_LWPOLYLINE多段线要遍历顶点数组。先跑通线段再逐步加类型别一上来就想全支持。5. 编译与运行中的避坑清单5.1 现象configure 报 AM_INIT_AUTOMAKE 未定义原因老包的configure.ac用的 automake 宏版本和新装的 automake 不匹配或者aclocal.m4缺失。解决先跑aclocal再autoreconf -fi。如果还报检查configure.ac里的AM_INIT_AUTOMAKE参数老版本可能写成AM_INIT_AUTOMAKE(libdwg, 0.4)新版要求至少两个参数手动补上AM_INIT_AUTOMAKE([foreign])再重新生成。5.2 现象链接时报 cannot find -lz原因zlib 开发包没装或者装在非标准路径。解决先dpkg -l | grep zlib确认zlib1g-dev在。如果装在/usr/local/zlib编译时加-L/usr/local/zlib/lib -I/usr/local/zlib/include。国产系统上有时库名带版本后缀用ls /usr/lib64/libz*看实际文件名必要时建软链接。5.3 现象读文件返回非 0但文件明明能打开原因DWG 版本超出库支持范围或者文件是加密/损坏的。解决先用file test.dwg看文件类型再用十六进制看头六个字节AC1015是 2000 版AC1032是 2018 版。如果版本太新换 libredwg 主线版本。如果文件头正常但读失败可能是文件被写保护或截断用官方工具另存一份再试。5.4 现象遍历实体时段错误原因obj-tio.entity或tio.LINE为空指针脏数据或非图形对象被当成实体处理。解决每次取指针前判空并且用obj-type先过滤。另外dwg.num_objects在某些版本里包含非实体对象遍历时要跳过type 500的内部对象。加if (!obj-tio.entity) continue;这一行能挡掉大部分崩溃。5.5 现象编译过了但运行提示找不到动态库原因装的是动态库但ldconfig没更新或者LD_LIBRARY_PATH没设。解决sudo ldconfig刷新缓存或者运行时临时export LD_LIBRARY_PATH/usr/local/libdwg/lib:$LD_LIBRARY_PATH。要长期生效就写进/etc/ld.so.conf.d/libdwg.conf再ldconfig。静态库没这个问题所以前面推荐--disable-shared。6. 从单文件到批量把 DWG 转 SHP 的落地技巧单文件跑通只是起点实际项目往往是一个目录几百个 DWG要批量转成 SHP 入库。我的习惯是分两层C 程序负责把 DWG 解析成 CSVPython 负责把 CSV 转 SHP各司其职出问题好定位。先写个批量脚本#!/bin/bash # batch_dwg2csv.sh IN_DIR$1 OUT_DIR$2 mkdir -p $OUT_DIR for f in $IN_DIR/*.dwg; do base$(basename $f .dwg) ./read_dwg $f $OUT_DIR/$base.csv 2$OUT_DIR/$base.err if [ $? -ne 0 ]; then echo FAIL: $f, see $base.err fi done逻辑说明遍历输入目录所有.dwg逐个调read_dwgCSV 输出到目标目录错误单独存.err文件。$?判断上一条命令退出码非 0 就打印失败文件名。这样跑完一眼能看出哪些文件没转成功不用一个个翻。再用 Python 把 CSV 转 SHPimport pandas as pd import geopandas as gpd from shapely.geometry import LineString df pd.read_csv(lines.csv, headerNone, names[layer, sx, sy, ex, ey]) # 每行构造一条线段几何 geom [LineString([(r.sx, r.sy), (r.ex, r.ey)]) for r in df.itertuples()] gdf gpd.GeoDataFrame(df[[layer]], geometrygeom, crsEPSG:4326) gdf.to_file(output.shp, encodingutf-8)逻辑说明pandas读 CSVshapely构造线段geopandas写 SHP。crsEPSG:4326是坐标系实际项目要按 DWG 原始坐标系改比如国内常用EPSG:4490或带号的高斯投影。encodingutf-8防止中文图层名乱码这是转 SHP 时最常见的坑。参数怎么调如果 DWG 坐标是毫米单位转 SHP 前要除以 1000 换成米否则地图上尺度全错。如果图层名有中文SHP 的 DBF 字段名有 10 字符限制超长会被截断建议在 CSV 阶段就映射成短名。验证方法转完用 QGIS 打开 SHP和原 DWG 在 CAD 里叠一下看线段位置对不对。数量上CSV 行数应该等于 SHP 要素数对不上就是有实体被漏掉或过滤了。这套链路我跑过几万张图纸最深的教训是别信「一次编译永久可用」。老库在新系统上迟早出问题与其反复修老包不如把解析层封装成独立进程库换了只改这一层上层 CSV 和 SHP 流程不动。另外DWG 版本兼容是玄学遇到读不了的文件先别怀疑代码八成是版本问题换 libredwg 新版或让上游另存为老版本比死磕快得多。希望帮到你。本文还有配套的精品资源点击获取
