VS 里只有三处要动:附加包含目录、附加库目录、附加依赖项。 报 LNK2019 时先别改代码,先查这三处填的是不是同一套工具链的产物。
1.4 是 Qt 那条路,这一篇是 VS。 两篇的坑本质相同:路径、顺序、工具链。
一、三处配置,一一对应
位置 填什么 对应 Qt 的哪个
附加包含目录 C:\ffmpeg\include INCLUDEPATH 附加库目录 C:\ffmpeg\lib LIBS 里的 -L 附加依赖项 avcodec.lib 等 LIBS 里的 -l
三处都在「项目属性 → 链接器 / C/C++」下面。 VS 的界面层级比较深,记住一条: 头文件在 C/C++ 页,库在链接器页。 别用绝对路径配到系统环境变量里。 换台机器就全废,用「用户宏」或 CMake 变量管这些路径。
二、用 CMake 更省事
现在的 VS 可以直接打开 CMake 工程,不用建 .vcxproj。 行 作用
set(FFMPEG_ROOT "C:/ffmpeg") 定义根目录 include_directories(${FFMPEG_ROOT}/include) 头文件 link_directories(${FFMPEG_ROOT}/lib) 库目录 target_link_libraries(app avcodec avformat) 库名
CMake 里只写库名,不带 -l,也不带后缀。
这一点跟 .pro 不一样:Qt 那边自己拼 -l,CMake 由它去拼。
写 avcodec.lib 反而会错,CMake 会去找叫 avcodec.lib.lib 的文件。
三、LNK2019 的三种来源
同一个报错,三个不同的病根,得分开看。 情况 病根 怎么改
符号全缺 附加依赖项没填 补库名 符号带 __imp_ 前缀缺 拿 GNU 库喂 MSVC 换 .lib 只有一两个符号缺 库版本与头文件不匹配 重编或换头文件
第二种最容易误判。 报错长这样:无法解析的外部符号 __imp_avcodec_send_packet。
符号明明存在,因为 MSVC 找的是带 __imp_ 的导入符号,而 .dll.a 里存的是另一套名字。
第三种最隐蔽:头文件是新的、库是旧的,只缺几个新接口。
这种错会让人以为「这个函数不能用」,其实是版本对不上。
四、本机的情况
本机没有 Visual Studio,msbuild 也不在 PATH。 所以这一节的三处配置是清单,不是操作记录。
但这三条判断在任何一台 VS 机器上都成立,而且不依赖版本——VS 2015 到 2022,
三处配置的位置与含义都没变。
一条通用建议:先把 Demo 编成一个只调 avcodec_version() 的空程序。 它能跑通,
说明三处都对了;跑不通,就是这三处之一,不用怀疑代码。
五、动手 Demo:VS 开发环境——三处配置,混链是死路
本机没有 VS,所以这一段做的是:摆三处配置、生成 CMake 片段、按文件名判产物归属。 最后那张表是混链判定的全部依据。
files = ["avcodec.lib", "libavcodec.dll.a", "avcodec-60.dll"]
for f in files:
who = "MinGW" if f.endswith(".dll.a") else "MSVC"
print(f, who)
实跑输出:
--------------------------------------------------------------------
VS 开发环境——三处配置,混链是死路
--------------------------------------------------------------------
**① VS 里只有三处要动**
位置 填什么
----------------------------------------------------------
附加包含目录 C:\ffmpeg\include
附加库目录 C:\ffmpeg\lib
附加依赖项 avcodec.lib; avformat.lib; avutil.lib
**② 生成的 CMakeLists 写法(VS 也能直接开 CMake 工程)**
`set(FFMPEG_ROOT "C:/ffmpeg")`
`include_directories(${FFMPEG_ROOT}/include)`
`link_directories(${FFMPEG_ROOT}/lib)`
`target_link_libraries(app avcodec avformat avutil swscale swresample)`
**③ 混链的判定:看文件名就知道是谁的产物**
文件 谁的产物 能混吗
---------------------------------------------------------
avcodec.lib MSVC 不能混 MinGW
libavcodec.dll.a MinGW 不能混 MSVC
avcodec-60.dll 运行时(同名) 按工具链选
libavcodec-60.dll 运行时(同名) 按工具链选
avutil.lib MSVC 不能混 MinGW
libavutil.dll.a MinGW 不能混 MSVC
**④ 混链的报错长什么样**
`LNK2019: 无法解析的外部符号 __imp_avcodec_send_packet`。这个错最容易骗人:符号明明在库里。
原因是 MSVC 找的是 `__imp_` 前缀的导入符号,而 `.dll.a` 里存的是 GNU 格式的,名字对不上。
**⑤ 一条能省半天时间的规矩**
**Qt、VS、Python 绑定,三样东西必须用同一条工具链编出来的 FFmpeg。**
混用不会有「部分能用」这种中间状态,只有「一个符号都链不上」。
**⑥ 本机实测**:VS 目录(`C:\Program Files\Microsoft Visual Studio`)不在,`msbuild` 也不在 PATH。
所以这一节的三处配置是清单,上面那条 LNK2019 是这类问题最常见的报错文本。
.lib 归 MSVC,.dll.a 归 MinGW,.dll 两家同名但内容不同。
看见目录里两种导入库混着,就说明这里有混链风险。
30 秒实验
where msbuild与where cl,看 VS 是不是只在图形界面里存在。- 在 VS 里建一个空的 C++ 控制台工程,把
avcodec_version()编进去,看链接报什么。 dumpbin /exports avcodec.dll | findstr avcodec_send看一个 DLL 导出了什么符号。
常见误区
- 只填附加库目录不填附加依赖项。 找不到库目录是 LNK1104,缺依赖项是 LNK2019。
- 把
.dll当导入库填。 链接期要的是.lib,.dll是运行期的。 - 路径写死成绝对路径。 换机器全废,用宏或 CMake 变量。
自测三问(点开对答案)
1. VS 里三处配置分别对应 Qt 的什么? —— 附加包含目录对应 INCLUDEPATH,附加库目录对应 -L,附加依赖项对应 -l。 2. LNK2019 报 `__imp_` 前缀的符号缺失,最可能是什么原因? —— 拿 MinGW 的 .dll.a 给 MSVC 链了。导入符号命名不同,必须换 .lib。 3. 为什么建议先编一个只调 `avcodec_version()` 的空程序? —— 能跑通说明三处配置都对,跑不通就锁定在配置层,不用怀疑自己的代码。- ☐ (本节完,下一节 1.6 Linux 下使用 GCC 编译 FFmpeg 的程序)