Windows 这边没有 configure,改的是一份 win32config。 最常见的坑不在命令上,在 /MD 与 /MT 这个开关上。
8.2.1 讲 Linux 下的编译,这一节讲 Windows 下的同一件事。 两边产物一样,但工具链、配置方式、坑全不一样。
一、改配置而不是跑脚本
Linux 靠 genMakefiles 从 config.xxx 生成 Makefile;
Windows 靠 genWindowsMakefiles 从 win32config 生成 .mak。
思路一模一样,只是文件名不同。
所以第一件事永远是打开 win32config 改几行:
① MSVCDIR:指向本机的 VC 目录。
这个值里有空格(Program Files (x86)),
所以整段必须带引号,否则 -I 后面只认到 C:\Program。
② MSVC_VER:写编译器版本号。
1900 是 VS2015,191x 是 VS2017,192x 是 VS2019,193x 是 VS2022。
写错的后果不是编译失败,而是某些条件编译分支走错。
③ NODEBUG:1 表示发布版,注释掉就是调试版。
这一行决定用哪个运行时库,是下一节那个坑的源头。
二、/MD 与 /MT:编得过却跑崩的根源
这是 Windows 编译 Live555 最经典的问题, 而且它不报错,只在运行时崩。
① /MT:把 C 运行时静态链进 EXE。
每个模块各带一份,于是进程里就有好几个堆。
在一个模块里 new、在另一个模块里 delete,必崩。
② /MD:用系统的运行时 DLL。
全进程共用一份堆,跨模块释放是安全的。
代价是目标机器上要有对应的运行库。
所以规则只有一句: 你编 Live555 用的那个开关,你的工程也必须用同一个。 不一致的典型表现是「Debug 版好好的,Release 版一播就闪退」——因为两个配置的运行时库默认就不一样。
还有个连带问题:
NODEBUG=1 时编出来的是发布版,用的是发布版运行时。
你的 VS 工程如果还停在 Debug 配置,两边立刻对不上。
这就是「明明照教程做了却崩」的常见原因。
三、生成什么、怎么编
genWindowsMakefiles 会一次生成一组 .mak 文件:
四个库各一个,示例程序一个,服务端与代理各一个。
编译要在「x64 Native Tools 命令提示符」里做,不能在普通 cmd:
因为 cl.exe、nmake.exe 和头文件路径都在那个专用窗口里才配好。
在普通 cmd 里连 nmake 都找不到。
顺序还是那个依赖顺序:
先 UsageEnvironment,再 groupsock,再 BasicUsageEnvironment,
然后 liveMedia,最后才是 testProgs。
逐个 nmake /f xxx.mak 执行。
编完在 testProgs 目录里会有 openRTSP.exe、
testOnDemandRTSPServer.exe 这些程序。
跑起来能连上,就说明这一套都是对的。
四、在自己的 VS 工程里用它
要让自己的项目用上 Live555,需要做四件事:
① 加头文件路径:指向 live 根目录与四个库目录。
Live555 的头文件是平铺的,路径别指错层。
② 加库文件:四个 .lib 全加上。
链接顺序按依赖来:被依赖的放后面。
③ 加系统库:ws2_32.lib 是必须的,它提供 socket 相关函数。
用到认证还要加 crypt32.lib。
④ 统一运行时库:就是上一节说的那个开关。
最容易漏的是第 ③ 步。
漏了的报错长这样:unresolved external symbol __imp_socket。
看到 __imp_ 前缀,基本就是缺一个系统库。
五、动手 Demo:Windows 下编译——win32config 里的几个坑
真解析一遍 win32config,看它到底读了哪几个变量; 再核对运行时库那几种组合。
import re
CFG = """\
NODEBUG=1
MSVCDIR=\"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\"
MSVC_VER=1900
INCLUDES=-I$(MSVCDIR)\\include
COMPILE_OPTS=$(INCLUDES) -I. -nologo -GR -EHsc -O2 -MD
"""
pat = re.compile(r"\$[({]([A-Za-z0-9_]+)[)}]")
def expand(text):
env = {}
for line in text.strip().splitlines():
k, _, v = line.partition("=")
env[k.strip()] = v.strip()
out = {}
for k in env:
cur = env[k]
for _ in range(12):
nxt = pat.sub(lambda m: env.get(m.group(1), ""), cur)
nxt = " ".join(nxt.split())
if nxt == cur:
break
cur = nxt
out[k] = cur
return out
for k, v in expand(CFG).items():
print("%-12s = %s" % (k, v))
实跑输出:
--------------------------------------------------------------------
Windows 下编译——win32config 里的几个坑
--------------------------------------------------------------------
**① Windows 这边不用 configure,改一份 win32config**
**Linux 靠 `genMakefiles` 从 config.xxx 生成 Makefile;**
**Windows 靠 `genWindowsMakefiles` 从 win32config 生成 .mak。**
**所以第一件事永远是:把 win32config 里那几行路径改对。**
**真解析一遍这份文件,看它到底读了哪几个变量:**
**MSVCDIR = "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC"**
**MSVC_VER = 1900**
**PLATFORM = x64**
**LIBRARY_LINK = lib -nologo -out:**
**COMPILE_OPTS =**
-I"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC"\include -I.
-nologo -GR -EHsc -O2 -MD -DNO_STRSTREAM_H
**`MSVCDIR` 是斜杠方向与空格两个雷:**
**路径里有空格(Program Files (x86)),整个值必须加引号,**
**否则 `-I` 后面只认到 `C:\Program`,然后报找不到头文件。**
**② /MD 与 /MT 选错,编得过但跑起来崩**
**这是 Windows 编译 Live555 最常见的坑,而且报错根本看不出来。**
运行时库 谁提供 CRT 和别的库混链会怎样
--------------------------------------------------------------------------
/MT 静态链进 EXE 两个模块各有一份堆,跨模块 free 必崩
/MD 用系统 DLL 共用一份堆,安全;但目标机要有对应运行库
**所以规则只有一句:**
**你编 Live555 用的那个开关,你的工程也必须用同一个。**
**不一致的表现是「Debug 版好好的,Release 版一播就闪退」。**
**还有个连带问题:**
**`NODEBUG=1` 时用的是 Release 运行时,**
**你的 VS 工程如果还停在 Debug 配置,两边就对不上了。**
**这也是「明明照教程做了却崩」的常见原因。**
**③ 会生成哪些 .mak**
**`genWindowsMakefiles` 一次把这几个文件摆出来:**
**liveMedia.mak 核心库**
**groupsock.mak 组播与套接字**
**UsageEnvironment.mak 环境抽象**
**BasicUsageEnvironment.mak 基础实现**
**testProgs.mak 示例程序**
**mediaServer.mak 点播服务器**
**proxyServer.mak 代理服务器**
**hlsProxy.mak HLS 代理**
**用 nmake 编的时候,顺序还是刚才那个依赖顺序:**
**先 UsageEnvironment,最后才是 testProgs。**
**【📋 实操路径】真编译的完整步骤**
1. 改 win32config:MSVCDIR 指向本机 VC 目录,NODEBUG 按需设
2. 开「x64 Native Tools 命令提示符」进 live 目录
3. genWindowsMakefiles.cmd
4. nmake /f liveMedia.mak
5. nmake /f testProgs.mak
6. 跑 testProgs\openRTSP.exe 验证
**第 2 步最容易被跳过:**
**在普通 cmd 里连 nmake 都找不到,**
**报的是「nmake 不是内部或外部命令」,看着像没装 VS。**
**就算 PATH 里有 nmake,它启动 cl.exe 时照样失败——**
**因为编译器和头文件路径都在那个专用命令窗口里才配好。**
$(MSVCDIR) 展开后那一大段路径,就是带空格的坑。
-MD 会一直留在 COMPILE_OPTS 里,它就是运行时库开关。
MSVC_VER=1900 是 VS2015,教材用的就是它。
换个版本号只是改一个数字,但改了要成套改。
30 秒实验
- 把
-MD改成-MT,想想哪里会崩——跨模块 new/delete,堆不是同一个。 - 把
MSVCDIR的引号去掉,看展开结果——-I后面只到C:\Program,路径断了。 - 把
NODEBUG那行删掉,猜会编出哪一版——默认走调试分支,运行时库也跟着换。
常见误区
- 「Windows 也要跑 configure」——改 win32config,没有 configure。
- 「/MT 与 /MD 只是体积差别」——是堆的差别,会崩。
- 「在普通 cmd 里就能 nmake」——连 nmake 都找不到。
自测三问(点开对答案)
1. MSVC_VER 1900 对应哪个 VS 版本? —— **VS2015**。191x 是 2017,192x 是 2019,193x 是 2022。 2. /MT 与 /MD 的本质区别是什么? —— **运行时库静态链入还是共享 DLL**,也就是进程里几份堆。 3. 看到 `unresolved external symbol __imp_socket` 缺什么? —— **缺 `ws2_32.lib`**,`__imp_` 前缀基本就指系统库。- ☐ (本节完,下一节 8.3 Live555 点播服务器流程分析)