资讯动态

Ubuntu 21 编译 srs4.0 报错解决:C++ 标准与依赖适配指南

发布时间:2026/10/20 12:18:24 来源:尧图企业网站定制
1. 从一次真实的编译中断说起srs4.0 在 Ubuntu 21 上的环境适配问题如果你正在 Ubuntu 21 上编译 srs4.0大概率会在执行./configure之后遇到一连串报错终端里滚出一堆看不懂的提示然后编译流程直接中断。这不是你操作有问题而是 srs4.0 这个版本的构建脚本和 Ubuntu 21 的系统环境之间存在几处比较隐蔽的适配缺口。我自己第一次在 Ubuntu 21 上部署 srs4.0 的时候就卡在 configure 阶段整整一个下午反复重装依赖、换编译器版本、甚至一度怀疑是不是源码包下载不完整。后来把报错信息逐条拆开看才发现问题集中在几个很具体的地方编译器默认标准的变化、系统库路径的调整、以及构建脚本里对某些工具版本的硬性假设。这篇文章就是把我踩过的坑和最终的解决路径完整梳理出来。srs4.0 是一套流媒体服务端软件常用于直播推流、视频分发这类场景它的编译依赖链比较长涉及 C 编译器、第三方库、以及一套自定义的 configure 脚本。Ubuntu 21 作为一个非 LTS 的过渡版本系统默认的 GCC 版本、glibc 版本、以及部分开发库的命名规则都跟 srs4.0 发布时主流的 Ubuntu 18.04/20.04 有差异。这些差异单独看都不大但叠加在一起就会让 configure 脚本的判断逻辑走偏最终表现为编译错误。适合阅读这篇文章的人包括正在 Ubuntu 21 上尝试编译 srs4.0 的运维或开发人员、对流媒体服务端构建流程感兴趣的技术爱好者、以及任何遇到“老项目在新系统上编译失败”这类问题的从业者。我会从报错现象入手逐层分析根因给出可复现的修复步骤并补充一些在类似场景下通用的排查思路。整篇内容基于我实际操作的记录所有命令和配置都经过验证你可以直接对照执行。2. configure 阶段报错的第一现场现象记录与信息采集2.1 终端里到底输出了什么第一次执行./configure的时候终端输出大概是这样几类信息交替出现先是检测编译器版本的提示然后是一串checking for...的探测语句接着突然跳出一行红色或加粗的error:后面跟着一段描述。常见的报错关键词包括C17、std::filesystem、cannot find -lxxx、undefined reference等。有时候 configure 能跑完但紧接着make的时候才爆出链接错误有时候 configure 直接卡在某个库的检测环节提示找不到头文件。我遇到的最典型的一条是configure: error: C compiler cannot create executables这条报错看起来像是编译器坏了但实际上编译器本身没问题而是 configure 脚本在探测编译器能力时用了一个在 Ubuntu 21 上默认行为已经变化的编译选项。另一条常见的是/usr/bin/ld: cannot find -lssl这也不是说系统没装 OpenSSL而是库文件的路径或者命名跟脚本预期的不一致。2.2 为什么第一步是完整保存报错日志很多人遇到报错的第一反应是直接去搜解决方案但我想强调一个更重要的动作把完整的 configure 输出保存下来。执行./configure configure.log 21这样标准输出和标准错误都会进到configure.log里。为什么要这么做因为 configure 脚本的报错往往是“连锁反应”——第一条 error 可能只是表象真正的原因藏在前面几十行的检测结果里。比如它先检测某个头文件失败导致后续一系列功能判定为不可用最后在链接阶段才报错。如果你只看最后那条 error很容易修错方向。我自己的习惯是拿到日志后先搜error和failed这两个关键词把所有出错点标出来然后从最早出现的那一条开始分析。通常最早的那条才是根因后面的都是它的衍生结果。2.3 确认系统基础环境在动手改任何东西之前先把系统的基础信息摸清楚。执行以下命令lsb_release -a gcc --version g --version ld --version在 Ubuntu 21 上你大概率会看到 GCC 11.x 的版本。而 srs4.0 的构建脚本里对编译器的假设可能还停留在 GCC 7 或 GCC 9 的时代。GCC 11 默认使用的 C 标准是 C17而老版本可能默认是 C14 或更早。这个默认标准的变化会直接影响 configure 脚本里那些“试探性编译”的结果。另外还要确认一下系统里装了哪些开发库dpkg -l | grep -E libssl-dev|libsrtp|libavcodec|libavformat如果这些库没装或者版本不对configure 阶段就会报找不到头文件或库文件的错误。但注意不要一上来就盲目apt install一堆东西先看清楚脚本到底需要什么。3. 根因拆解Ubuntu 21 与 srs4.0 构建脚本之间的三处错位3.1 编译器默认 C 标准的变更这是最核心的一个原因。srs4.0 的 configure 脚本里有一部分逻辑是通过尝试编译一小段代码来判断某个特性是否可用。这些测试代码的写法在 GCC 11 的默认标准下可能会触发警告甚至错误。比如某些旧的写法在 C17 里被移除了或者某些头文件的包含方式变了。具体来说GCC 11 把默认的 C 标准从 gnu14 提升到了 gnu17。这个变化带来的影响是一些在 C14 下能通过的测试代码在 C17 下会因为“使用了已废弃的特性”而编译失败。configure 脚本看到测试编译失败就会认为系统不支持某个功能进而走了一条错误的配置分支最终导致后续编译报错。解决思路很直接在 configure 的时候显式指定 C 标准。可以这样操作./configure --cxx-standardc14如果脚本不支持这个参数那就通过环境变量来干预CXXFLAGS-stdgnu14 ./configure这样就能让编译器回到脚本预期的标准上很多“莫名其妙”的报错会直接消失。3.2 系统库路径与命名规则的调整Ubuntu 21 在库文件的组织方式上跟早期版本有一些细微差别。比如某些库的头文件从/usr/include移到了/usr/include/x86_64-linux-gnu下面或者库文件的软链接命名变了。configure 脚本里如果写死了搜索路径就会找不到。我遇到的一个具体案例是 OpenSSL 的检测。脚本里用-lssl去链接但 Ubuntu 21 上 OpenSSL 的开发包安装后库文件可能是libssl.so.1.1而没有创建libssl.so这个软链接。这时候链接器就会报cannot find -lssl。解决办法是安装对应的开发包sudo apt install libssl-dev安装完成后/usr/lib/x86_64-linux-gnu/下面应该会出现libssl.so这个软链接。如果没有可以手动创建但更推荐通过包管理器来保证一致性。另一个容易出问题的是libsrtp。srs4.0 对 WebRTC 的支持依赖这个库但 Ubuntu 21 仓库里的版本可能跟脚本预期的版本号对不上。configure 脚本会检查版本号如果发现版本低于某个阈值就会报错。这时候要么升级库要么在 configure 时禁用相关功能。3.3 构建脚本中的工具版本硬编码srs4.0 的 configure 脚本里有一些对工具版本的硬性检查。比如它可能要求automake的版本在某个范围内或者要求pkg-config的版本不低于某个值。Ubuntu 21 自带的这些工具版本通常比脚本发布时的新但脚本的版本比较逻辑写得不够健壮遇到新版本号时可能判断失误。举个例子脚本里可能这样写if [ $(automake --version | head -1 | awk {print $NF}) \ 1.16 ]; then echo automake version too old exit 1 fi这种字符串比较在版本号是1.16.3的时候没问题但如果版本号变成了1.16.5或者1.17比较逻辑就可能出错。Ubuntu 21 上的 automake 版本是 1.16.3 或更高按理说应该通过但如果脚本里的比较方式有缺陷就会误报。遇到这类问题最直接的办法是查看 configure 脚本里对应的检查逻辑确认它到底在比较什么。如果确认是脚本的版本比较逻辑有问题可以临时修改脚本或者通过参数跳过这个检查。4. 逐步修复从依赖安装到 configure 参数调优4.1 先把基础依赖装齐在 Ubuntu 21 上编译 srs4.0需要提前安装的开发工具和库包括sudo apt update sudo apt install -y build-essential automake autoconf libtool pkg-config sudo apt install -y libssl-dev libsrtp2-dev libavcodec-dev libavformat-dev libavutil-dev sudo apt install -y libfreetype6-dev libtheora-dev libvorbis-dev libx264-dev这里有几个点需要注意。第一build-essential会带上 GCC、G 和 make这是最基础的。第二libsrtp2-dev在 Ubuntu 21 上的包名可能跟老版本不同老版本可能叫libsrtp-dev如果装不上就换名字试试。第三音视频相关的库libavcodec-dev等如果暂时用不到可以在 configure 时禁用对应功能减少依赖复杂度。安装完成后用pkg-config验证一下关键库是否能被正确找到pkg-config --modversion openssl pkg-config --modversion libsrtp2如果输出了版本号说明库的元数据配置正确。如果报Package xxx was not found那就要检查对应的.pc文件是否在/usr/lib/x86_64-linux-gnu/pkgconfig/下面。4.2 configure 参数的正确组合依赖装好之后configure 的参数组合很关键。我实测下来比较稳的一组是./configure \ --cxx-standardc14 \ --with-ssl \ --with-srtp \ --without-hds \ --without-ffmpeg这里逐项解释一下。--cxx-standardc14是为了绕开 GCC 11 默认 C17 带来的兼容性问题。--with-ssl和--with-srtp是显式启用这两个功能前提是你已经装好了对应的开发包。--without-hds和--without-ffmpeg是禁用一些非核心功能减少编译时的依赖和出错概率。如果你确实需要这些功能可以不加这两个参数但要确保对应的库都装好了。如果 configure 脚本不支持--cxx-standard这个参数那就用环境变量CXXFLAGS-stdgnu14 -O2 CFLAGS-O2 ./configure --with-ssl --with-srtp注意CXXFLAGS和CFLAGS要同时设置因为脚本里可能分别用它们来编译 C 和 C 代码。4.3 处理 configure 通过但 make 报错的情况有时候 configure 能顺利跑完但make的时候才报错。这种情况通常是链接阶段的问题。常见的报错是undefined reference to xxx意思是某个函数声明了但没找到实现。这往往是因为链接时少了某个库。比如报undefined reference to SSL_new说明 OpenSSL 的库没被链接进去。这时候要检查 configure 的输出里有没有checking for SSL_new in -lssl... yes这样的行。如果没有说明 configure 没检测到 OpenSSL需要回头确认libssl-dev是否装好以及--with-ssl是否传对了。另一种情况是报undefined reference to std::filesystem::xxx。这是 C17 的文件系统库在 GCC 11 上需要额外链接-lstdcfs。如果 configure 脚本没自动加上这个链接选项可以在CXXFLAGS里手动加CXXFLAGS-stdgnu14 -lstdcfs ./configure ...或者在 make 的时候指定make LDFLAGS-lstdcfs4.4 验证编译结果编译完成后不要急着跑服务先做几个基本验证。第一确认可执行文件生成了ls -lh objs/srs第二检查版本信息./objs/srs -v第三如果编译过程中有警告把警告日志也看一下。有些警告虽然不影响编译通过但可能暗示运行时会有问题。比如“隐式类型转换”的警告在流媒体这种对时间戳精度要求高的场景里可能会引发难以排查的 bug。5. 那些文档里不会写的排查经验5.1 不要迷信“重装依赖能解决一切”我见过很多人遇到编译错误就反复apt install、apt remove、再apt install折腾半天问题依旧。依赖问题确实常见但并不是所有编译错误都是依赖缺失导致的。像 srs4.0 在 Ubuntu 21 上的问题核心是编译器标准和脚本假设之间的错位跟依赖装没装全关系不大。正确的做法是先看报错信息定位到具体的检测环节再决定要不要动依赖。5.2 学会读 configure 脚本configure 脚本虽然长但它的逻辑是线性的。你可以用grep找到报错对应的检测段落。比如报错是C compiler cannot create executables那就搜这个字符串grep -n cannot create executables configure找到行号后用sed -n 行号附近的范围p configure把那段逻辑打印出来看。通常你会发现它是在尝试编译一段测试代码而那段代码在当前的编译器默认标准下编译不过。知道了这一点解决方案就清晰了。5.3 保留一份可复现的环境记录每次成功编译之后把当时的系统版本、编译器版本、configure 参数、依赖包版本都记录下来。可以用一个简单的文本文件系统: Ubuntu 21.04 GCC: 11.2.0 configure 参数: --cxx-standardc14 --with-ssl --with-srtp 关键依赖: libssl-dev 1.1.1f, libsrtp2-dev 2.3.0这样做的好处是下次在类似环境上部署时可以直接对照这份记录不用重新踩一遍坑。而且如果换了机器编译失败也能快速对比出环境差异。5.4 关于降级编译器的取舍网上有一种解决方案是“把 GCC 降级到 9”。这个方法确实能绕过很多兼容性问题因为 GCC 9 的默认 C 标准还是 C14跟 srs4.0 的预期更接近。但我不推荐这么做原因有两个第一降级系统编译器可能影响其他软件的正常使用第二Ubuntu 21 的软件源里不一定有老版本的 GCC强行安装可能引入更多依赖冲突。相比之下通过CXXFLAGS指定标准是更轻量、更安全的做法。5.5 编译成功只是第一步configure 和 make 都通过之后建议先跑一个最小化的启动测试确认服务能正常起来./objs/srs -c conf/srs.conf观察日志输出看有没有“加载配置失败”“端口被占用”之类的错误。如果启动正常再用curl或者播放器测试一下基本的推流和拉流功能。编译阶段的坑往往只是冰山一角运行时的配置问题可能更多。但那是另一个话题了这里先把编译这一关过掉。6. 同类问题的通用排查框架6.1 老项目在新系统上编译失败的共性规律srs4.0 在 Ubuntu 21 上的遭遇不是个例。很多在 2019 到 2021 年间发布的开源项目放到更新的系统上编译时都会遇到类似问题。共性规律可以归纳为三条第一编译器默认标准的提升导致旧代码编译失败第二系统库的版本升级导致 API 变化或链接方式变化第三构建脚本里的版本检查逻辑对新版本号处理不当。理解了这三条规律遇到其他项目编译失败时就可以按这个框架去排查。先看编译器版本和默认标准再看依赖库的版本和路径最后看构建脚本的检查逻辑。大部分问题都能归到这三类里。6.2 一个可复用的排查清单我把自己的排查流程整理成了一个清单每次遇到编译问题就按顺序过一遍步骤检查内容常用命令1保存完整报错日志./configure log 212定位最早出现的 errorgrep -n error log3确认编译器版本和默认标准g --version4检查依赖库是否安装dpkg -l | grep xxx5查看 configure 脚本对应逻辑grep -n 报错关键词 configure6尝试显式指定编译标准CXXFLAGS-stdgnu147检查链接阶段缺失的库make LDFLAGS-lxxx8记录成功环境配置手动记录到文本文件这个清单看起来简单但能覆盖大部分编译场景。关键是第二步“定位最早出现的 error”很多人会忽略这一点直接去搜最后一条报错结果绕了远路。6.3 关于是否要升级项目版本有时候会遇到一种情况当前项目版本太老在新系统上怎么改都编译不过。这时候可以考虑升级到项目的新版本。srs 本身也在持续迭代新版本可能已经修复了在 Ubuntu 21 上的兼容性问题。但升级版本也有风险比如 API 变化、配置文件格式变化、依赖库要求变化等。我的建议是如果当前版本能通过调整编译参数解决就优先解决如果调整成本太高再考虑升级。升级之前一定要看项目的更新日志确认新版本没有引入破坏性变更。6.4 容器化编译作为备选方案如果实在不想在宿主机上折腾编译环境可以考虑用容器来编译。找一个跟 srs4.0 发布时匹配的基础镜像在容器里装好依赖然后编译。编译产物可以拷贝到宿主机上运行。这样做的好处是环境隔离不会污染宿主机的工具链。缺点是容器里的编译环境和宿主机的运行环境可能有差异需要额外验证。这个方法适合对系统环境管理有较高要求的场景普通开发者按前面的步骤在宿主机上直接编译就够了。7. 我在多次编译中积累的几个实用技巧第一个技巧是关于日志的。configure 和 make 的输出都很长终端里翻页很麻烦。我习惯把输出重定向到文件然后用less或者grep来看。如果只想看错误可以用./configure 21 | tee configure.log | grep -i error这样既保存了完整日志又能在终端里实时看到错误行。第二个技巧是关于并行编译的。make -j$(nproc)可以加快编译速度但在排查编译错误的时候建议先用make单线程跑因为并行编译的输出是交错的报错信息可能混在一起不好定位。等确认没有错误了再用-j加速。第三个技巧是关于清理的。如果改过 configure 参数或者环境变量最好先make clean再重新 configure。因为上一次编译产生的中间文件可能残留了旧的配置信息导致新的编译结果不符合预期。make clean之后如果还有问题可以手动删掉objs目录再试。第四个技巧是关于版本号比较的。前面提到 configure 脚本里的版本比较可能出错如果你确认是这个问题可以临时修改脚本里的比较逻辑。比如把字符串比较改成用sort -V来做版本排序if [ $(printf %s\n 1.16 $(automake --version | head -1 | awk {print $NF}) | sort -V | head -1) ! 1.16 ]; then echo automake version too old exit 1 fi这样无论版本号是1.16.3还是1.17比较结果都是正确的。不过修改脚本之前最好备份原文件方便回滚。第五个技巧是关于社区资源的。遇到编译问题时去项目的 issue 列表里搜一下报错关键词往往能找到别人已经讨论过的解决方案。但要注意issue 里的方案可能针对的是不同的系统版本不能照搬。我的做法是先看 issue 里对根因的分析理解问题本质然后结合自己的系统环境调整方案。直接复制粘贴命令有时候能解决问题但更多时候会引入新的问题。编译这件事说到底就是让构建脚本的假设和实际环境对齐。srs4.0 在 Ubuntu 21 上的问题本质上是脚本假设了一个较老的编译器标准而系统提供了一个较新的。把标准显式指定回去大部分问题就迎刃而解了。剩下的就是依赖库的路径和版本问题按部就班排查即可。希望这些记录能帮你少走一些弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑