📹 第八章 ONVIF框架代码案例应用
📄 一句话概括

工作空间就是五个平级目录:输入两个、输出三个。 建错位置不影响生成,但会把后面每条命令的路径都带歪, 而 Windows 还有一条 260 字符的硬上限。

📝 本节和前面几节的关系

上一节把 16 个文件下齐了,这一节把它们放到位。 这一步没有技术含量,但它是整章唯一「改一次、后面全跟着改」的地方—— 目录名一改,wsdl2h 与 soapcpp2 的每条命令都要重敲。

一、为什么非要有工作空间

因为两个工具都往「当前目录」扔文件。 wsdl2h 默认把结果写成 typemap.h, soapcpp2 一次吐八个文件——如果就在桌面或者某个项目根目录里跑,这些东西会散得到处都是。

工具 不指定目录时写哪 后果
wsdl2h 当前目录的 typemap.h 和 typemap.dat 混在一起
soapcpp2 当前目录的 8 个文件 和业务代码混在一起

第一行那个默认文件名是个坑:typemap.h 与 typemap.dat 只差一个扩展名, 看文件列表时极易看错——所以我习惯永远写 -o onvif.h,让名字差别大一点。 第二行更麻烦:八个文件里有 soapC.cpp、soapH.h 这种和业务无关的名字, 混进工程后,别人根本分不清哪个是生成的、哪个是手写的。

二、五个目录的分工

目录 输入还是输出 删了会怎样
wsdl/ 输入 要重下 16 个文件
import/ 输入 要重下外部 xsd
gsoap/ 半输入 要重新解压源码包
src/ 输出 重跑一遍生成,几分钟
bin/ 工具 要重新拷 exe

第二列是关键:只有前两个是「下不回来的」,后面三个都能重建。 所以备份只备前两个,重建只重建后三个——这个分工在做持续集成时很有用: 输入进版本库,输出进 .gitignore。 第三行那个 gsoap/ 是「半输入」:源码包能重新下,但版本号要一致, 否则生成出来的头文件结构体名可能变。

三、260 字符那条线

Windows 的老 API 对路径有 260 个字符的上限,含结尾的 0,实际可用 259。 这个限制和 ONVIF 的关系很直接:

环节 为什么路径会长 表现
工程放在深层目录 「我的文档/项目/版本/…」 C1083 打不开源文件
生成的文件名 soapC.cpp 其实不长 一般不是主因
#include 相对路径 深一层多一层前缀 同样是 C1083

第三行是最容易漏的:生成的文件里会写 #include "../import/wsse.h" 这种相对路径, 每深一层就多几个字符,而编译器的报错只说「找不到」,不说「路径太长」。 注意 C1083 这个错误码:它同时对应「文件不存在」和「路径太长」两种情况, 所以看到它第一反应不该是「我文件放错了」,而是先量一下路径长度。

四、相对路径的连锁反应

这一节最后要说清一件事:所有路径参数都是相对「当前命令行目录」的。 所以命令一定在「工作空间根目录」里敲,否则 wsdl/devicemgmt.wsdl 就找不到。

在哪敲命令 wsdl/devicemgmt.wsdl 指向 结果
工作空间根目录 <根>\wsdl\devicemgmt.wsdl 对
src/ 里 <根>\src\wsdl\devicemgmt.wsdl 不存在
任意其他目录 该目录下的 wsdl\… 不存在

第二行是最常见的情况:在 src/ 里敲,因为「生成的东西放这儿」——但输入在上一级。 解决办法有两个:要么 cd .. 再敲,要么把参数写成 ../wsdl/devicemgmt.wsdl。 后者更容易错,因为参数一多就会漏改其中一个。 我的习惯是「永远在工作空间根目录敲,输出用 -o src/onvif.h 指定」—— 输入输出都写相对根的路径,一眼能看出谁在哪。

五、动手 Demo:工作空间就五个目录

Demo 真建这五个目录,再量一次路径长度——因为「260 够不够」这件事,只有量了才知道。

# 五个目录,输入两个、输出三个
for d in ("wsdl", "import", "gsoap", "src", "bin"):
    os.makedirs(os.path.join(WS, d), exist_ok=True)

# 量路径:根目录与最深的一个产物
base = os.path.abspath(WS)
deep = os.path.join(base, "src", "soapClient.cpp")
print(len(base), len(deep), 259 - len(deep))

实跑输出:

--------------------------------------------------------------------
工作空间就五个目录
--------------------------------------------------------------------
**书上叫「新建工作空间」,其实是在磁盘上建五个平级目录。**
**建错位置不影响生成,但影响后面所有命令行参数。**

  目录          装什么
  --------------------------------------------------
  `wsdl/`       14 个 WSDL 和 2 个 xsd
  `import/`     wsdl2h 找不到的外部 xsd
  `gsoap/`      只用它的 `stdsoap2.c/h` 与 `wsse.h`
  `src/`        soapcpp2 生成的代码
  `bin/`        `wsdl2h.exe` 与 `soapcpp2.exe`

**这五个目录里只有前两个是「输入」**,后三个都是「输出」——
**所以重建工作空间时,删后三个随便删,删前两个就得重下。**

**第二个坑是 Windows 的路径长度。**

  项                    字符数     说明
  ----------------------------------------------------------
  工作空间根目录        51         本机实测
  最深的一个产物        70         `src\soapClient.cpp`
  **MAX_PATH 上限**     260        **含结尾的 0,可用 259**
  余量                  189        —

**本机这个路径 70 个字符,离上限还有 189 个。**
**看着很宽裕,但注意两点**:
**一是 `soapC.cpp` 里会写 `#include` 的相对路径**,深一层就多一层前缀;
**二是 MSVC 报的是 `C1083: 无法打开源文件`**,看着像文件不存在,其实是路径太长。
**所以工作空间要建在盘的浅层**,别塞进「我的文档/某项目/某版本/…」里。

第二段那三行是这一节唯一有数的东西:根目录 51 个字符、最深的产物 70 个字符、余量 189。 这个余量看着很宽裕,但要注意两件事: 一是这 70 个字符里已经包含了 I:\Desktop\自我教学\…\ch35_dev 这么深的前缀, 换成「我的文档」下的工程,前缀会更长; 二是量的是「产物路径」,不是「#include 里写的路径」——后者可能更长。 所以这条经验要按「最坏情况」记:工程目录尽量浅,最好直接放在盘根下一层。 最后那句「删后三个随便删」是有前提的:前提是输入还在、工具还在。 如果连 bin/ 里的 exe 都是自己编出来的,那删了就得重编十几分钟。

30 秒实验

  1. 把 WS 改成一份更深的路径(比如再加三层),看余量掉到多少。
  2. 在 src/ 目录里跑 wsdl2h -o onvif.h ../wsdl/devicemgmt.wsdl,看相对路径怎么算。
  3. 数一下 259 减去你的工程路径长度还剩多少——少于 60 就该考虑搬家。

常见误区

  1. 在工作空间根目录以外敲命令。 所有路径参数都是相对「当前目录」的, 在 src/ 里敲就找不到 wsdl/。
  2. 把 wsdl2h 的输出留成默认的 typemap.h。 它和 typemap.dat 只差一个扩展名, 看文件名时极易搞混。
  3. 看到 C1083 就以为文件不存在。 它也可能是路径超过 259 个字符,先量长度再改代码。
自测三问(点开对答案) 1. 五个目录里哪几个删了要重新下载? —— **`wsdl/` 和 `import/`**,它们是输入。其余三个都能重跑或重新解压恢复。 2. 为什么生成的源码里会出现很长的相对路径? —— **因为 `#include` 用的是相对路径**,工程目录越深前缀越长,**最后撞上 259 的硬限制**。 3. `wsdl2h` 不写 `-o` 时输出什么文件? —— **当前目录的 `typemap.h`**——**和 `typemap.dat` 只差一个扩展名**,很容易看错。

下一节改 typemap.dat:三处要改,而且不能按行号改。

相关笔记