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

Linux 版的 wsdl2h 命令和 Windows 版只差三处, 而其中最坑的是「反斜杠」——因为它在 shell 里是转义字符。 另外 Linux 的库搜索路径里没有「当前目录」,这是和 Windows 最大的观念差。

📝 本节和前面几节的关系

上一节把 typemap.dat 的换行问题解决了,这一节真正跑生成命令。 命令本身和 08.01.04 一样, 但 shell 会把某些字符吃掉——这一节讲的就是「被吃掉的那部分」。

一、三处差别

项 Windows Linux
可执行文件名 wsdl2h.exe wsdl2h
路径分隔符 wsdl\devicemgmt.wsdl wsdl/devicemgmt.wsdl
找动态库 exe 同目录优先 LD_LIBRARY_PATH 或 ldconfig

第二行看着是小事,其实最容易错:反斜杠在 shell 里是转义字符, wsdl\devicemgmt.wsdl 会被吃成 wsdldevicemgmt.wsdl—— 然后报「文件不存在」,而你在文件管理器里明明看得见它。 第三行是观念差:Windows 会先找 exe 同目录, Linux 不会——它只按 LD_LIBRARY_PATH、/etc/ld.so.cache、/lib、/usr/lib 这几处找。 所以「我把 .so 放在程序旁边了」在 Linux 上不管用,这是从 Windows 转过来最不习惯的一点。

二、shell 会吃掉什么

除了反斜杠,还有三个字符要小心:

字符 shell 怎么处理 要怎么写
\ 转义下一个字符 用 / 或写 \\
* 通配符展开 加引号
空格 分词 加引号
$ 变量替换 单引号或转义

第二行那个通配符在 ONVIF 命令里很危险: 如果参数写成 wsdl/*.wsdl,shell 会展开成 14 个文件名—— 这恰好是想要的;但如果你想要的是「一个叫 *.wsdl 的文件」,就错了。 这其实是 Linux 的一个便利:批量喂 WSDL 可以写成 wsdl/*.wsdl, 不用逐个列——但要注意展开顺序不一定是你要的(按字典序)。 第三行那个空格在 Windows 用户看来不可思议(路径里有空格很常见), 而在 Linux 上「带空格的路径」必须加引号,否则会被切成两个参数。

三、-I 参数到底指哪

Linux 侧的 -I 和 Windows 侧含义一样,但「指哪」常被搞错:

写法 含义 对不对
-I import 在当前目录下的 import/ 里找 对
-I /usr/local/gsoap/include 绝对路径 对
-I import/wsse.h 指到一个文件 错,-I 要指目录

第三行是最常见的错:-I 指的是「目录」不是「文件」, 指到文件上,wsdl2h 会在这个「目录」里找 wsse.h—— 而那个「目录」其实是个文件,于是找不到。 报错信息是「找不到 wsse.h」, 而你已经把路径写上去了——这种「写了却没用」的错最让人怀疑人生。 第二行那个绝对路径要注意:用绝对路径的坏处是不可移植,换台机器就得改; 所以我倾向「先 cd 到工作空间根目录,然后用相对路径」。

四、生成之后先验三处

和 08.01.04 一样,生成完先验,别急着往下走:

验什么 怎么验 不对说明什么
文件行数 wc -l onvif.h 太小说明 WSDL 没读全
有没有 tt__ 类型 grep -c "_tt__" onvif.h 0 说明 typemap 没生效
有没有 wsse__ grep -c "wsse__" onvif.h 0 说明鉴权那行没加

第一行那个「太小」是个粗判据:1810 个 element 对应的头文件在万行量级, 如果 wc -l 出来只有几百行,说明大部分 WSDL 没读进去。 最常见的原因是「只喂了一个 WSDL」——命令里那一长串 URL 或路径,漏掉一个就少一大块。 第二、三行用 grep -c 数匹配行数,这是 Linux 上最快的「有没有」检查: grep -c 返回 0 就说明一处都没有。 这三条检查加起来不到十秒,但能省掉后面「编译报一万个错」的半小时。

五、动手 Demo:Linux 下生成 onvif.h 的命令

Demo 用 Python 模拟 shell 的转义规则,看 wsdl\devicemgmt.wsdl 会被吃成什么。 这是本节唯一能「在本机复现」的现象。

arg = "wsdl\\devicemgmt.wsdl"
print(arg)                      # wsdl\devicemgmt.wsdl
print(arg.replace("\\", ""))    # wsdldevicemgmt.wsdl

# shell 里的效果等价于「把反斜杠当转义符」
# 于是路径丢了分隔,报「文件不存在」

实跑输出:

--------------------------------------------------------------------
Linux 下生成 onvif.h 的命令
--------------------------------------------------------------------
**和 Windows 版的差别只有三处**,但每一处都会让命令跑不起来:

  项                 Windows                    Linux
  -----------------------------------------------------------------------------------
  可执行文件名       `wsdl2h.exe`               `wsdl2h`
  **路径分隔符**     `wsdl\devicemgmt.wsdl`     **`wsdl/devicemgmt.wsdl`**
  找头文件的参数     `-I import`                **`-I import`(一样)**
  **运行动态库**     `wsdl2h.dll` 要同目录      **要 `LD_LIBRARY_PATH` 或 ldconfig**

**第二行看着是小事,其实最容易错**:
**反斜杠在 Linux 的 shell 里是转义字符**,
**`wsdl\devicemgmt.wsdl` 会被 shell 吃成 `wsdldevicemgmt.wsdl`**,
**然后报「文件不存在」**——**而你在资源管理器里明明看得见它。**
**这是「Windows 习惯带到 Linux」的第一课**,几乎人人踩过。

**用 Python 的 shell 规则模拟一下这个转义**:

原样写:`wsdl\devicemgmt.wsdl`
经过 shell 转义后:`wsdldevicemgmt.wsdl`
**少了那个反斜杠,路径就没了分隔**,
**所以「文件不存在」的报错其实是对的。**

**第四行是第二课**:**Linux 的动态库搜索路径里没有「当前目录」**。
**Windows 会先找 exe 同目录,Linux 不会**——
**所以 `wsdl2h: error while loading shared libraries: libgsoap-2.8.116.so` 这种错**,
**解法是 `export LD_LIBRARY_PATH=/usr/local/gsoap/lib:$LD_LIBRARY_PATH`**,
**或者装完跑一次 `sudo ldconfig`。**

第二行那个 wsdldevicemgmt.wsdl 就是「文件不存在」的真相: 路径里的分隔没了,变成一个不存在的文件名。 注意这个模拟是「简化版」:真正的 shell 只会吃掉紧跟在 \ 后面的那个字符, 而这里是全删——不过结论一样:路径坏了。 所以你看到「文件不存在」但文件明明在的时候,第一件事是把命令原样 echo 一遍, 看 shell 到底把它变成了什么。 echo 是 Linux 上最被低估的调试工具: 它不执行、只回显,正好用来确认「我传进去的到底是什么」。

30 秒实验

  1. 在 Linux 上 echo wsdl/../wsdl/devicemgmt.wsdl,看 shell 会不会规范化路径。
  2. 把 -I import 写成 -I import/(带斜杠),看行为有没有变化。
  3. 跑 grep -c "_tt__" onvif.h,看数量级对不对。

常见误区

  1. 在 Linux 上写 wsdl\devicemgmt.wsdl。 反斜杠是转义符,路径会被吃坏, 报「文件不存在」而文件明明在。
  2. 把 .so 放在程序旁边就以为能找到。 Linux 不搜当前目录, 要 LD_LIBRARY_PATH 或 ldconfig。
  3. -I 指到一个文件上。 它要指目录,指到文件就找不到里面的头文件。
自测三问(点开对答案) 1. Linux 版 `wsdl2h` 和 Windows 版差哪三处? —— **可执行文件名、路径分隔符、动态库搜索路径**。 **第二项最容易错**,因为反斜杠在 shell 里是转义符。 2. 为什么 `.so` 放程序旁边找不到? —— **Linux 的动态库搜索路径里没有「当前目录」**(这是和 Windows 最大的观念差)。 3. 生成完怎么快速判断 WSDL 读全了? —— **`wc -l onvif.h` 看行数**,再用 `grep -c "_tt__"` 看类型数。 **太小就说明只读了一部分 WSDL。**

下一节讲鉴权:算法不分平台,但有三个「跨平台才会犯」的错。

相关笔记