FreeSWITCH源码编译安装全指南:依赖配置、模块裁剪与启动排错
2026/9/17 5:54:03 网站建设 项目流程

行里用 FreeSWITCH 搞语音网关也快十年了,每次在新服务器上编译安装总能看到有人在群里问同样的问题:依赖装了一堆还是 configure 报错、make 到一半内存爆了、装完启动不了、日志刷得飞快也不知道哪里没对。其实 FreeSWITCH 编译安装这件事,难度不在编译器,而在你对整个构建链路有没有完整的认识。这篇文档把我这些年实际踩过的坑和验证过的步骤完整整理出来,从依赖准备到模块裁剪,从首次启动到端口确认,按顺序说清楚,照着做完能让你少折腾至少一个晚上。

可以明确的是,FreeSWITCH 是当前开源社区里功能最完整的软交换平台之一,支持 SIP、WebRTC、T.38 传真、会议、IVR 等一大堆电信级特性。源码编译的最大好处是你可以自己裁剪模块、定制编译参数,比如云服务器上不需要的蓝牙模块、电话硬件驱动之类的完全可以不编译。它适合两类人:一类是要在生产环境部署语音业务的技术工程师,另一类是想深入研究软交换内部机制的开发者。对于刚接触的新手,文章后半部分也写了 Windows 环境下的安装参考和常见报错对照表,方便你有个循序渐进的路径。

1. 编译前的整体设计与方案选型

1.1 为什么推荐从源码编译而不是直接用发行版

很多刚接触 FreeSWITCH 的朋友会问,官方明明提供了各主流发行版的安装源,为什么还要自己编译。我的建议是:如果你只是搭个测试环境随便玩玩,用发行版源确实更快;但如果你要部署生产业务,或者需要特定音编码模块、特定 patch、特定版本的配套依赖(比如 Sofia-SIP、spandsp、libks 这些核心库),源码编译几乎是唯一可控的路径。

发行版仓库里的 FreeSWITCH 版本通常滞后于官方发布周期,有时候滞后半年甚至更久。语音协议栈这种基础设施,滞后带来的问题不只是功能缺失,还可能有安全漏洞和互操作性问题。我自己遇到过的情况是,Debian 源里的 FreeSWITCH 版本对 WebRTC 的 TURN/ICE 支持不完整,导致浏览器端呼叫时不时失败,换了从源码编译的最新稳定版之后一切正常。另外,发行版安装的模块是固定的,编译时可以通过modules.conf精确控制,把不需要的模块彻底排除在安装之外,既减小体积也减少攻击面。

1.2 编译链路的核心组件和依赖关系

FreeSWITCH 的构建体系是基于 GNU Autotools 的,核心组件可以拆成几个层次。最底层是系统工具链,包括gccmakeautoconfautomakelibtool。第二层是三方基础库,比如 PCRE(正则表达式)、SQLite(内部数据库)、libcurl(HTTP 接口)、OpenSSL(TLS 加密)、zlib(压缩)。第三层是 FreeSWITCH 自己的子模块,最核心的是sofia-sip(SIP 协议栈)、spandsp(音频编码和 T.38)、libks(底层基础库)、libvpx(VP8 视频编码)。

这里要说一个新手最容易犯的误区:不要把整个编译过程当成一个黑盒。./configure脚本做的事情是检查这些依赖库是否存在、版本是否满足要求,然后把检查结果写进config.hMakefile。如果某个依赖缺失,它可能不会直接报错,而是悄悄禁用相关功能。这就是为什么有时候编译顺利完成,但安装后mod_opusmod_fsv这些模块却没生成,因为在 configure 阶段这些功能就被条件性地跳过了。判断依据在编译日志末尾的 summary 信息里,编译前最好存一份日志文件,方便事后回溯。

1.3 系统环境选择和硬件要求

FreeSWITCH 对 Linux 发行版没有硬性绑定,主流支持的是 Debian/Ubuntu、CentOS/RHEL。我个人的生产环境主力是 Debian,原因有两个:一是包管理器对编译工具链的支持比较干净,二是 Debian 系的动态链库版本通常不会太激进也不会太旧。CentOS 也能跑,但 EPEL 源里一些依赖库版本偏老,可能要多处理几个编译错误。

硬件方面,CPU 双核以上,内存 4G 起,编译时建议预留至少 8G 磁盘空间。一个常见问题是服务器内存只有 2G 甚至更少,make默认开满所有 CPU 线程并行编译,每个编译进程吃几百兆内存,直接 OOM。这个问题在 3.3 节会给出具体解法。编译时建议使用普通用户而非 root,避免污染系统环境,也避免 make install 时目录权限混乱。

2. 源码获取与依赖安装的完整步骤

2.1 获取 FreeSWITCH 源码的方式

获取源码推荐两种方式。第一种是直接下载官方发布的 tar.gz 归档包,适合追求稳定、不追踪每日提交的用户。到官方网站的 downloads 页面找到对应的版本号,比如 1.10.x 或 1.8.x,下载后用 tar 解压即可。第二种是使用 git clone 拉取仓库,这种方式方便后续随时git pull更新到最新代码,也方便切换分支。官方仓库地址是https://github.com/signalwire/freeswitch.git,当前的主分支已经演进到 1.10 系列,稳定分支通常以v1.10这样的名字存在。

无论用哪种方式,强烈建议把源码放在空间充足的独立目录,不要放在/tmp,因为编译产物体积大,系统重启后/tmp清理会把你整个构建目录杀掉。我习惯这样安排:

mkdir -p /opt/src cd /opt/src git clone https://github.com/signalwire/freeswitch.git -b v1.10 freeswitch

注意这里的-b v1.10指明清空拉取具体分支,避免直接检出的默认分支跟你的版本预期不一致。如果只想编译某个特定 tag,也可以加--branch v1.10.7 --depth 1--depth 1是浅克隆,只拉最新一次提交,省时间省磁盘。

2.2 依赖安装全列表

安装依赖这一步是最繁琐但也是最重要的。Debian/Ubuntu 系的完整依赖命令如下:

apt-get update && apt-get install -y \ build-essential automake autoconf git wget libtool \ libtool-bin pkg-config libssl-dev zlib1g-dev libdb-dev \ unixodbc-dev libexpat1-dev libgdbm-dev libgdbm-compat-dev \ libncurses5-dev libncursesw5-dev bison liblua5.2-dev \ libcurl4-openssl-dev libpcre3-dev libspeex-dev libspeexdsp-dev \ libsqlite3-dev libldns-dev libedit-dev libopus-dev libsndfile-dev \ libpq-dev libyuv-dev libavformat-dev libswscale-dev libvlc-dev \ liburiparser-dev uuid-dev libsctp-dev

CentOS/RHEL 7/8 系列对应的命令类似,包名可能会有差异。比如ncurses-developenssl-develsqlite-devellibuuid-devel等。有一个小技巧,configure 报缺哪个头文件就装对应的-devel包,但这样会拉长编译时间,不如一次性把所有常见的都装上省事。

这里要特别提醒:liblua版本要留意。系统自带的 Lua 版本如果太老,FreeSWITCH 里的 mod_lua 可能编译不过去。遇到这种情况别着急改 Lua 源码,最简单的方式是让 FreeSWITCH 在构建时使用内置的lua源码编译,这个选项在后续 configure 阶段会用--builtin-lua激活(在构建脚本里可以选)。总之,依赖安装的目的是让./configure检查全部通过,而不是“装完就算完”。

2.3 子模块初始化

源码克隆回来之后,第一件必做的事情是初始化子模块。FreeSWITCH 的仓库结构是把sofia-sipspandsplibks这些核心库作为 git submodule 管理的。直接 clone 主仓库并不会自动拉取这些子模块的内容,需要显式执行:

cd /opt/src/freeswitch git submodule update --init --recursive

如果网络不好导致子模块拉取失败,可以尝试设置 git 的 http 缓冲,或者多跑几次这个命令,因为 git submodule 是支持断点续传的,重复执行不会重复拉取已经成功的部分。判断子模块是否完整的标准是看源码根目录下有没有libsofia-sip-uaspandsplibks这些目录并且里面内容非空。我第一次做的时候就是漏了这一步,结果 configure 找不全内部依赖,报了一堆莫名的路径错误。

3. configure 配置与编译参数的精调

3.1 configure 核心参数解析

FreeSWITCH 的 configure 脚本支持大量参数,但绝大多数场景下只需要关注几个核心选项就够了。--prefix指定安装目录,默认是/usr/local/freeswitch,对生产环境来说可以保持默认或改为/opt/freeswitch--enable-core-odbc-support是启用 ODBC 支持,如果你要用数据库做用户认证、话单存储等,建议开启。另一个比较常用的是--disable-core-libs--disable-modules,用于排除不需要的库和模块,不过这两个参数用起来要小心,容易不小心弄丢核心依赖,新手不太建议动。

我自己在生产环境用的典型配置是:

./configure --prefix=/usr/local/freeswitch \ --enable-core-odbc-support \ --enable-zrtp \ --enable-assertions

--enable-zrtp是开启 ZRTP 媒体加密支持,--enable-assertions保留断言代码,方便定位问题。注意,--enable-assertions会略微影响性能,生产环境稳定运行一段时间后可以考虑去掉重新编译。

configure 通过后最后几行会打印出当前配置的摘要信息,包括启用的特性、SDL 路径、PortAudio 等,这个摘要值得截屏或者重定向保存:

./configure ... | tee /tmp/freeswitch_configure.log

3.2 模块裁剪:modules.conf 的作用

模块自由度是源码编译最大的优势。FreeSWITCH 的模块配置文件位于根目录的modules.conf,每一行代表一个要参与编译安装的模块。系统默认配置笔较多,很多模块是纯功能性或实验性的,比如与具体厂商硬件对接的mod_unicall、与视频会议相关的mod_av等,不一定每个部署都需要。

我的裁剪逻辑很简单:只保留 SIP 注册、呼叫路由、媒体处理、会议、XML 解析、事件 socket 控制这些核心模块,排除所有语音硬件驱动、嵌入式开发板、特殊 codec 等。比如,如果你单纯做 SIP trunk,就不太需要mod_alsamod_portaudio这两个音频设备接入模块。如果你用不到 WebRTC,可以去掉mod_verto,少编译一堆 WebSocket 相关依赖。如果你需要 WebRTC,那mod_vertomod_verto相关的库就很重要,不能裁。

裁剪建议是在 modules.conf 里用#注释掉不需要的模块,而不是删除那一行,方便日后恢复。有一类模块叫applications/*asr_tts/*,如果不是做复杂的 IVR 语音导航或者语音识别业务,可以有选择地注释掉大半,能显著缩短编译时间。

3.3 并行编译与内存控制的平衡

make默认使用单线程编译,速度非常慢,FreeSWITCH 这种体量的项目单线程编译可能要一两个小时。make -j$(nproc)可以自动按 CPU 核心数并行编译,本机 16 核的话编译时间能压到十分钟以内。但在低配服务器上,并行编译是内存杀手。我实测过,16 核机器同时编译时内存占用能超过 8G,如果服务器内存只有 4G,OOM 几乎不可避免。

解决办法有两个。一是手动限制并行度,比如 4 核 CPU 用make -j2,留出两核的内存余量。二是配合低优先级运行,避免编译进程把系统其它服务挤崩:

nice -n 19 make -j4

编译期间建议另开一个窗口用free -mhtop盯着内存变化。如果内存涨得太快,立即 Ctrl+C 停止,改用更小的并行度继续。make是支持断点续作的,停止后重新执行make会根据目标文件的时间戳跳过已经完成的部分,不用全部重来。

4. make 编译核心过程与关键细节

4.1 编译过程中的输出怎么看

执行make之后,屏幕上会滚动大量 gcc 编译命令和警告信息。新手容易慌,其实大多数警告是无害的,比如未使用的变量、隐式函数声明等,官方代码库也存在部分历史遗留的警告。真正要警惕的是Error 1Error 2这样的关键字,以及以fatal error:开头的编译器消息。为了区分,推荐把完整编译日志保存下来:

make -j4 2>&1 | tee /tmp/freeswitch_make.log

编译完成后的最后几行一般是:

make[1]: Leaving directory '/opt/src/freeswitch/src' make: Leaving directory '/opt/src/freeswitch'

如果之前 configure 阶段有依赖缺失,但 configure 没有识别出来,编译到某个模块时就会突然报头文件缺失。这时不要盲目 Google 整个报错信息,先看缺的是哪个头文件。比如fatal error: opus/opus.h: No such file or directory,就说明系统里缺少 libopus-dev 或者 configure 在编译该模块时找不到 Opus 库。先回到第 2 节把依赖补上,再把对应模块重新 make,不要急着清空编译缓存。

4.2 编译中断后的恢复技巧

编译过程中如果因为断电、内存不足、SSH 掉线中断了,不用慌。重新登录服务器后先确认源码目录还在,然后直接再次执行make,它会基于时间戳增量编译,已经生成的目标文件不会重编。但有一个坑:如果中断发生在链接阶段,某些 .o 文件存在但对应的 .so 库没生成,make 的依赖判断有时不会重新执行链接命令,导致你看到的模块文件缺失。遇到这种情况,我通常手动找到mod_x对应的子目录,执行make mod_x单独重新编译该模块,不行就make clean后从头再编。

另外一个增量编译的坑是:修改了 modules.conf 之后直接 make install,新加的模块不会自动编译进去,因为 Makefile 依赖没有重新生成。正确的做法是在裁剪和修改模块列表之后先执行./configure重新生成 Makefile,再执行 make。我看到不少人在群里提问“为什么 modules.conf 里加了模块但是 make 之后没有生成”,多半就是这个原因。

4.3 遇到个别模块编译失败如何单独处理

FreeSWITCH 的模块非常多,每年新版本总有那么一两个模块在特定发行版上编译失败。当你只需要核心功能时,完全不必卡在这些不重要的模块上。一键编译整个项目的流程里,某个模块编译失败默认会让整个 make 终止,但你可以先跳过问题模块完成整体安装。

操作思路是:先把 modules.conf 里有问题的模块注释掉,完成正常编译和安装,服务跑起来感知一下核心功能没有问题,之后再单独研究该模块的编译错误。比如我在 Ubuntu 22.04 上编译某版本时mod_av因为 FFmpeg 头文件 API 变化编译不过,但我的业务用不到这个模块,直接注释掉即可,完全不影响整体部署。

如果你确实需要某个失败的模块,常见的处理方法是:先查该模块的Makefile里的LOCAL_CFLAGSLIBS,对照 configure 日志看是不是某个依赖库没找到。有一个排查技巧我用了很多年,就是make mod_xxx单独编译目标模块,输出信息比全量编译时更集中,报错定位更快。

5. make install 安装与首次配置

5.1 安装目录结构

编译完成的下一步是安装。make install会把可执行文件、库文件、配置模板、声音文件全部复制到 prefix 指定目录下。如果你用默认 prefix,安装后的目录结构大致是:

/usr/local/freeswitch/ ├── bin/ # 可执行程序,freeswitch 和 fs_cli ├── conf/ # 配置文件 │ ├── freeswitch.xml # 总配置文件 │ ├── autoload_configs/ # 各模块的配置文件 │ ├── dialplan/ # 拨号计划 │ ├── directory/ # 用户目录 │ └── sip_profiles/ # SIP 配置文件 ├── db/ # 内嵌数据库文件 ├── htdocs/ # Web 管理相关的静态文件 ├── mod/ # 编译出来的模块动态库 ├── recordings/ # 录音存储目录 ├── sounds/ # 系统提示音 └── storage/ # 呼叫相关文件存储

理解这个目录结构对后续排错非常重要。比如freeswitch.xml是总控配置,所有模块的配置文件都被它 include 进来。模块配置文件在autoload_configs/下,命名规律通常是模块名.conf.xml。SIP 网关的监听端口、codec 列表、NAT 穿透等设置在sip_profiles/下。

5.2 安装后的权限修正

这里要提一个很多人忽略的细节:如果你是用 root 用户执行 make install,那么安装目录下的所有文件都属于 root,而 FreeSWITCH 运行时默认会以 freeswitch 用户降权运行,会导致启动时无法写 db、log、recordings 等目录。解决方法是安装后统一修改属主:

useradd -r -s /bin/false freeswitch chown -R freeswitch:freeswitch /usr/local/freeswitch

如果不想新建用户,也可以直接用 root 启动,但生产环境强烈不建议,因为语音服务暴露在公网,一旦有漏洞被利用,root 权限带来的风险远大于收益。系统服务方式启动时,配置的用户和工作目录也需要和上面保持一致。

5.3 基础配置:修改默认密码和端口检查

安装完成后不要急着一键启动,先做两件基础安全配置。

第一,修改默认的事件 socket 密码。FreeSWITCH 默认会监听本机的 8021 端口,用 fs_cli 连接时需要密码,默认是ClueCon。这个密码在autoload_configs/event_socket.conf.xml里配置,务必改成一个强随机字符串:

<param name="password" value="你的强密码"/>

第二,确认 SIP 端口没有被防火墙拦截。默认 SIP 监听 UDP/TCP 5060,WebRTC 需要 7443 端口(TLS)和 8081 端口(WSS)。如果你配置了媒体端口范围(一般是 16384-32768),这些 UDP 端口也需要放行,不然语音会单向或者完全无声。

配置好后,可以用bin/freeswitch -nc以非控制台方式启动,也可以直接bin/freeswitch前台运行观察启动日志。首次启动建议前台运行,日志直接输出到屏幕,方便看模块加载情况。看到类似Successfully Started的日志时,说明核心进程已经起来了。

6. 启动验证与常见问题排查

6.1 首次启动和模块加载验证

启动后第一个要做的事是验证自己的模块是否都加载成功。进入 FreeSWITCH 控制台的方式是执行:

/usr/local/freeswitch/bin/fs_cli

输入version可以查看版本号,show modules可以列出所有已加载的模块。有些模块虽然编译安装了,但因为配置文件缺失或依赖的动态库不对,启动时会加载失败并打印一行mod_xxx: Fatal Error。模块加载情况也可以从启动日志里loading module mod_xxx和对应的success/ERROR字样推断。

常见的模块加载失败原因有两个:一是autoload_configs目录下对应的配置文件语法错误,尤其是 XML 文件标签没配对;二是模块动态链接的某个共享库没找到,比如mod_av需要libavformat.so,你用ldd检查一下模块的链接情况就能定位。

6.2 呼叫链路初步打通:本地分机测试

基础启动验证通过后,建议马上做一个最简的本地分机注册测试,验证 SIP 协议栈和媒体处理链路。在directory/default/下创建两个用户,比如 1000 和 1001,确认 profile 里的register配置为 true。然后用任意软电话(比如 Zoiper、MicroSIP)注册到服务器。

两个分机注册成功后,用 1000 呼叫 1001,如果听到回铃音,说明 early media 已经正常通过。这里扩展开说一句,early media 指的就是主叫在呼叫被应答之前听到的回铃音或彩铃,FreeSWITCH 里叫作p-early-media-support,如果运营商侧的 SIP 中继需要透传早期媒体,需要在 SIP profile 里增加<param name="p-early-media-support" value="true"/>,不然会出现一种很常见的问题:电话呼得通但听不到回铃音,接听后双方却能正常通话。这个问题排查过好几次,都是这个参数引起的。

还有parkhold相关功能也可以在这个阶段验证。Park 是呼叫驻留,把通话暂时转入保持状态,之后再由其他分机取回;Hold 则是单方保持。这两个功能分别依赖mod_dptools里的parkhold应用,平时排查用户投诉“电话挂不住”“转接后音乐不播放”时,优先看这两个应用有没有正确调用以及传给它们的时间参数、保持音文件路径是否正确。

6.3 常见编译与运行问题速查表

每次写这种实操分享我都倾向于把问题改成表格放在最后,方便收藏之后翻阅。下面这表格是编译安装和首次运行阶段我遇到频率最高的几个问题,结合排查命令和解决方案一并整理。

问题现象可能原因排查命令/方法解决方案
configure 提示Library requirements (sqlite3 >= xxx) not met系统 SQLite 版本过旧sqlite3 --version安装新版 SQLite 或加--disable-sqlite(如果不需要)
make 报fatal error: pcre.h: No such file or directory缺少 PCRE 开发包dpkg -l | grep pcreapt-get install libpcre3-dev
make 期间 OOM 被杀并行编译内存不足free -m减少-j并行度,或临时加 swap
make install 后启动提示Failed to open log file目录属主不对ls -l /usr/local/freeswitch/logchown -R freeswitch /usr/local/freeswitch
show modules没有mod_sofiaconfigure 阶段 sofia-sip 检查失败查看 configure 日志中的sofia相关行重新初始化子模块再 configure
呼叫无回铃音(early media 丢失)SIP profile 未开启 early media 透传sofia global siptrace on抓包确认设置p-early-media-support=true
控制台fs_cli连接被拒event socket 密码错误或端口被防火墙挡ss -lntp | grep 8021检查event_socket.conf.xml密码及 iptables 规则
软电话注册 401 反复循环digest 认证不通过查看directory/default用户密码重置目录中的 user 密码或删除 DB 缓存
打包声或提示音缺失sounds 目录未正确安装或路径配置不对ls $prefix/sounds重新执行make sounds-install

6.4 运行日志分析与常用排错兵器

FreeSWITCH 运行时的日志位于log/freeswitch.log,默认带上时间戳、等级(INFO、WARNING、ERR)和模块名。个人习惯是在排查问题时先打开控制台的详细日志,执行console loglevel debug,这样涉及的呼叫内容会在屏幕上滚动,信息量巨大但足够直观。生产环境调试完记得切回console loglevel info,避免日志刷爆磁盘。

SIP 信令跟踪建议使用sofia global siptrace on,开启后控制台会打印进出的 SIP 消息原文。这个命令对排查注册失败、呼叫路由错误、early media 不生效的问题几乎是必须的。用它配合 Wireshark 抓包对比,基本能定位 90% 的 SIP 互操作问题。媒体问题的重点则要看 RTCP 的丢包和抖动数据,FreeSWITCH 控制台里可以用sofia status profile internal查看每个 profile 的呼叫状态,show channels as json查看通道详情。

7. Windows 环境安装速览

7.1 Windows 下通常不做源码编译

搜索热词里很多人问windows安装freeswitch,这里专门说一句。FreeSWITCH 官方在 Windows 上主要提供预编译的安装包(MSI 格式),不推荐在 Windows 上自行源码编译,因为 FreeSWITCH 的大量模块用到了 POSIX 接口,在 Windows 下编译需要额外的兼容层和补丁,流程复杂且官方不保证所有模块都能正常构建。

Windows 用户直接下载官方或社区发布的 MSI 安装包,双击安装即可。安装时选择完整的默认组件,装完后桌面会生成fs_cli的快捷方式,点击进入控制台输入version能看到版本信息,比 Linux 源码编译省心很多。测试环境或内网实验用官方 Windows 安装包完全够用。

7.2 从 Windows 到 Linux 的开发部署思路

如果是做开发,我倒是建议在主机的 Windows 上写代码,然后把改动同步到 Linux 服务器或者虚拟机里编译运行。Windows 上使用 VS Code 或 CLion 配好远程开发插件,直接编辑 Linux 上的 FreeSWITCH 源码,热点是保存后自动同步。编译放在 Linux 端做,这样既保留 Windows 的桌面环境体验,又避开 Windows 编译的各种坑。

有一类问题也很典型:vs2010编译报error msb6006 cmd.exe已退出,代码为3这类编译报错,本质是 Windows 的构建工具链自身出问题或者有路径/环境变量不对,和 FreeSWITCH 本身关系不大。你在 Windows 上做 FreeSWITCH 二次开发时如果遇到这种问题,优先检查环境变量的 PATH 是否包含了编译器的路径、引用的头文件目录是否存在、杀毒软件是否拦截了子进程创建,这些比改代码更常见。

8. 个人实操体会

FreeSWITCH 编译安装这件事,说难也难,说简单也简单。难在依赖多、链路长,任何一个环节的版本不匹配都可能导致最后的模块缺失或者运行异常;简单在于它的构建体系是标准的 Autotools,你只要完整走通一次,之后换版本、迁移服务器都有章可循。

我个人的习惯是每在全新环境上编译前,先把 configure 日志保存下来,然后 make 日志单独存一份,这样无论以后排查什么怪问题,都有据可查。日常运维建议把freeswitch.log按天切割,结合 logrotate 保留 30 天,录音文件单独挂载大容量磁盘,db 目录做定期备份。另外,刚安装完的 FreeSWITCH 不要急着接生产话务,先跑几天模拟呼叫,重点观察内存是否会缓慢上涨、模块有没有异常崩溃。我在多个版本上都遇到过长时间运行后 mod_sofia 内存泄漏的情况,重启周期不规律,后来对比版本日志才发现是上游的一个已知问题,升级小版本后消失。

最后再分享一个经验:很多看似是编译问题、运行问题的事故,最终排查下来其实是基础环境不一致。两台机器同样的安装步骤,一台正常一台不正常,优先对比的是操作系统小版本、gcc 版本、依赖库版本,用gcc --versionldconfig -p | grep <库名>一查便知。用这种思路去面对编译安装,你会少走很多弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询