🎬 第一章 编译FFmpeg源码并搭建开发环境
📄 一句话概括

二十行程序、一条 gcc 命令,难点全在那条命令背后的 pkg-config。 四种报错对应四个病根:编译器、头文件、库路径、版本不匹配。

📝 本节和前面几节的关系

1.3 把库装好了,这一篇终于写出第一个自己的程序。 第一章到此结束,第二章开始认七个库各自管什么。

一、二十行的第一个程序

程序本身没什么可讲的,三行有效代码。 行 作用


#include 引入声明 avcodec_version() 取版本号 printf 打出来

它的价值在于「最小可验证」:只依赖一个库、一个函数、一个符号。能编过,说明头文件路径对了; 能链上,说明库路径与库名对了;能跑出正确的号,说明 DLL 也对了。三层一次验完。 版本号还能当尺子用。 打出来是 62 开头,就是 8.0 系;是 59 开头,就是 5.0 系。 跟你以为装的版本对不上,说明机器上有两套。

二、pkg-config 到底做了什么

它干的事一句话:把 .pc 文件里的路径拼成 -I 与 -L -l。 参数 输出什么


--cflags -I/usr/local/ffmpeg/include --libs -L/usr/local/ffmpeg/lib -lavcodec -l... --modversion 库的版本号 --exists 在就回 0,不在回 1

所以 gcc ver.c $(pkg-config --cflags --libs libavcodec) 等于手写了那一串。 手写容易错, pkg-config 不会错——前提是 .pc 文件在。 .pc 文件在哪儿? --prefix 目录下的 lib/pkgconfig/。 所以装完 FFmpeg,那个目录必须进 PKG_CONFIG_PATH,否则 pkg-config 说「没这个包」。 本机 PKG_CONFIG_PATH 是 0 段,pkg-config 也不在 PATH——这条路本机根本不存在。

三、四种报错,四个病根

同一个「编不出来」,四种原因,报错关键词完全不同。 报错关键词 病根 去哪看


FileNotFoundError 编译器不在 PATH 环境变量 avcodec.h: No such file 头文件路径没给 -I 或 cflags cannot find -lavcodec 库路径或库名错 -L 或 -l undefined reference 头文件与库版本不符 装了两套

第三种与第四种的差别值得记住:前者是「找不到库文件」,后者是「找到了库但没有这个符号」。 前者看路径,后者看版本。 本机 Demo 真跑了一次 gcc --version,得到 FileNotFoundError。 WinError 码是 2,意思是「这个文件不存在」。 这就是第一行的样子:不是编译失败,是连编译器的门都没进去。

四、编过了跑不起来:运行期路径

编得过、跑不动,报 error while loading shared libraries: libavcodec.so.62。 因为链接期与运行期是两套机制:链接期看 -L,运行期看 LD_LIBRARY_PATH 与 ldconfig。 做法 生效范围 适合什么


export LD_LIBRARY_PATH=... 当前 shell 临时测试 写进 /etc/ld.so.conf.d/ 全系统 正式部署 编进 rpath 这个程序 发版

ldd 你的程序 | grep avcodec 能立刻看出找没找到。 回 not found 就是路径没设, 回一个路径就说明找到了。 这三个办法里,rpath 最适合发版:路径写进可执行文件,换台机器只要有同样的目录结构就能跑, 不依赖环境变量。

五、动手 Demo:GCC 编一个调 FFmpeg 的小程序——本机编不了,但错在哪看得见

本机没有 gcc,真跑会得到 FileNotFoundError。 这一段把这个失败原样打出来,再摆四种报错的分类表。

import subprocess

try:
    r = subprocess.run(["gcc", "--version"], capture_output=True)
    print(r.returncode)
except FileNotFoundError as e:
    print("WinError", e.winerror)

实跑输出:

--------------------------------------------------------------------
GCC 编一个调 FFmpeg 的小程序——本机编不了,但错在哪看得见
--------------------------------------------------------------------

**① 要编的东西只有二十行**

`#include <stdio.h>`
`#include <libavcodec/avcodec.h>`
`int main(void) {`
`    printf("%u\n", avcodec_version());`
`    return 0;`
`}`

**② 编译命令**

`gcc ver.c -o ver $(pkg-config --cflags --libs libavcodec)`

`pkg-config` 干的事就一件:把 `-I` 与 `-L -l` 那串东西拼好交给你,省得手写路径。
它靠 `.pc` 文件工作,所以编 FFmpeg 时那个 `--prefix` 必须和 `.pc` 文件里的路径一致。

**③ 本机真跑一次,看它怎么失败**

调 `gcc --version` → **FileNotFoundError**,WinError = 2

这就是「工具链没装」在代码里的样子:
**不是编译失败,是连编译器的门都没进去。** `FileNotFoundError [WinError 2]` 这条错误,
以后见了就知道要在 PATH 上找问题,而不是在源码里找问题。

**④ 真机上的四种结局,一眼分类**

  报错关键词                             真正的病根
  ---------------------------------------------------------------
  FileNotFoundError WinError 2           编译器不在 PATH
  libavcodec/avcodec.h: No such file     头文件路径没给
  cannot find -lavcodec                  库路径或库名错
  undefined reference to av_xxx          头文件与库版本不匹配

**第五种最隐蔽**:头文件与库版本不一致时,编译能过、链接报一堆「未定义引用」。
原因是用新头文件编、拿了老 `.so` 链。
所以 `--prefix` 那套东西装完,要把旧版本从 `LD_LIBRARY_PATH` 里清掉。

**⑤ 一条验完的命令**

`pkg-config --modversion libavcodec` 报不出号,就说明 `.pc` 没进`PKG_CONFIG_PATH`;
报出来了但版本比头文件旧,就是装了两套。本机 `PKG_CONFIG_PATH` 是 0 段——连这条路都不存在。

WinError 2 就是「这个文件不存在」。 看见它,问题在 PATH,不在源码。 真机上这一句会回一个版本号,而不是异常。

30 秒实验

  1. pkg-config --exists libavcodec; echo $? 看它在不在。
  2. ldd ./ver | grep av 看运行时依赖找到没。
  3. 把 -I 故意删掉,看报错是不是 avcodec.h: No such file。

常见误区

  1. 手写 -I 与 -L 路径。 一装新版本就全错,用 pkg-config。
  2. 编过了就以为能跑。 运行期还要 LD_LIBRARY_PATH 或 rpath。
  3. 两套 FFmpeg 装在同一台机器上。 头文件与库对不上,报一堆未定义引用。
自测三问(点开对答案) 1. `pkg-config --cflags --libs libavcodec` 输出什么? —— `-I` 头文件路径与 `-L -l` 库路径库名,直接交给 gcc 就能用。 2. `cannot find -lavcodec` 与 `undefined reference to av_xxx` 有什么区别? —— 前者是找不到库文件(路径问题),后者是找到库但没这个符号(版本不匹配)。 3. 编得过却跑不起来,报找不到 .so,怎么修? —— 设 LD_LIBRARY_PATH、写 ld.so.conf.d、或编译时用 rpath 把路径写进可执行文件。

相关笔记