工作空间就是五个平级目录:输入两个、输出三个。 建错位置不影响生成,但会把后面每条命令的路径都带歪, 而 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 秒实验
- 把
WS改成一份更深的路径(比如再加三层),看余量掉到多少。 - 在
src/目录里跑wsdl2h -o onvif.h ../wsdl/devicemgmt.wsdl,看相对路径怎么算。 - 数一下 259 减去你的工程路径长度还剩多少——少于 60 就该考虑搬家。
常见误区
- 在工作空间根目录以外敲命令。 所有路径参数都是相对「当前目录」的,
在
src/里敲就找不到wsdl/。 - 把
wsdl2h的输出留成默认的typemap.h。 它和typemap.dat只差一个扩展名, 看文件名时极易搞混。 - 看到
C1083就以为文件不存在。 它也可能是路径超过 259 个字符,先量长度再改代码。
自测三问(点开对答案)
1. 五个目录里哪几个删了要重新下载? —— **`wsdl/` 和 `import/`**,它们是输入。其余三个都能重跑或重新解压恢复。 2. 为什么生成的源码里会出现很长的相对路径? —— **因为 `#include` 用的是相对路径**,工程目录越深前缀越长,**最后撞上 259 的硬限制**。 3. `wsdl2h` 不写 `-o` 时输出什么文件? —— **当前目录的 `typemap.h`**——**和 `typemap.dat` 只差一个扩展名**,很容易看错。下一节改 typemap.dat:三处要改,而且不能按行号改。
- ☐ (本节完,下一节 08.01.03 修改typemap.dat)