
这段时间陆续有几个朋友拿着石器时代的服务端源码来问我说代码下下来了但一敲 make 就报错卡来卡去都是环境问题。其实石器这款老游戏的源码编译难度不算高绝大多数疑难杂症都出在大家对编译环境和老代码的特性不太熟上比如 gcc 版本选择、mysql 头文件路径、32 位库这些细节。我前前后后在 CentOS 6.5 和 CentOS 7 上都把整个流程跑通过踩坑记录攒了一大堆这篇就把环境搭建的完整过程写成一份可以直接照着做的清单覆盖从系统安装、依赖准备、数据库导入到服务端编译启动的完整链路适合想在本地把石器时代服务端源码跑起来、打算研究老游戏服务端原理的朋友参考。1. 先看清这份源码再动手1.1 石器时代服务端源码到底包含什么拿到一份石器时代服务端源码后第一步别急着敲命令先把目录结构看明白。绝大多数流传出来的版本都源自同一个技术分支目录下通常包含负责游戏逻辑的主服务程序、账号认证服务、数据库操作相关模块以及一堆启动脚本和配置文件。你可能看到的是.c/.cpp混排的老 C 工程也可能看到一个写得比较随意的 Makefile甚至有些版本根本没有 Makefile需要自己根据.cpp文件列表拼编译命令。我见过不少新手在这块栽跟头上来就make结果 Makefile 里写的绝对路径指向了原作者机器上的/root/sa/之类的目录一执行就报No such file or directory。不用慌这是很正常的现象你只需要用find . -name Makefile把所有 Makefile 找出来逐个用sed或者手动把路径改成你实际的源码路径即可。还需要注意一点老版本源码对 CPU 架构和操作系统的假设很古老很多代码默认int就是 4 字节指针不会超过 32 位网络字节序处理也写得比较硬。这意味着你在 64 位系统上编译时可能会遇到大小端、数据对齐甚至指针截断的问题。这类问题没有统一解法我的建议是先在 64 位下无脑跑一遍等真正报错了再针对性处理不要提前脑补一堆复杂情况。1.2 编译这个项目需要什么级别的环境石器时代的服务端源码编译门槛其实很低它不像现在的大型 C 项目那样依赖几十个第三方库也不需要几十 G 的编译缓存。它本质上就是一个老式的 Linux 网络服务程序底层依赖无非是标准 C/C 库、POSIX 线程库、数据库客户端库和少量压缩库。对机器配置的要求也很低1 核 1G 内存的虚拟机都绰绰有余毕竟这套东西在当年 256M 内存的服务器上都能跑得动。对照现代编译环境唯一比较挑剔的地方在于编译器版本。CentOS 6.5 自带的 gcc 4.4.7 其实是最贴近这套老代码的编译器CentOS 7 自带的 gcc 4.8.5 也能跑通大部分源码。如果拿 Ubuntu 22.04 这种自带 gcc 11 的现代发行版去编译大概率会在语法兼容性上报一堆错不是代码错了而是新编译器对老代码的容错度降低。所以标题里特别强调 CentOS 6.5 和 7是有实际原因的。还有一点容易被忽略防火墙和 SELinux。编译本身不需要网络但编译出来的服务端要监听端口如果你开着 SELinux 或默认防火墙很可能出现客户端连不上、服务器启动失败这类问题。我在测试环境里通常会直接关掉它们省去排查的麻烦。2. CentOS 6.5 和 CentOS 7 怎么选、怎么装2.1 两个版本的差异其实没那么大在动手装系统之前先说下两个系统版本在编译这个项目时的差别。CentOS 6.5 的 gcc 是 4.4.7CentOS 7 的 gcc 是 4.8.5对于石器时代源码这种老代码两个版本都用过编译结果没有实质差别。真正的差别主要体现在三块一是服务管理方式CentOS 6 用 SysVinitCentOS 7 用 systemd这影响你写开机启动脚本的方式二是默认数据库CentOS 6 是 MySQL 5.1/5.5CentOS 7 默认 MariaDB三是 yum 源的状态6.5 的官方源基本已经停止维护需要把源地址改成 vault 归档源才能正常安装软件。如果你手头没有现成的 CentOS 6.5 安装盘又不想花太多时间折腾老系统直接用 CentOS 7.9 的镜像就行这也是目前很多怀旧服务端研究者在用的方案。7.9 还在维护期内默认源可以直接用安装依赖包的时候省心很多。至于镜像去哪下载国内几个高校镜像站都有完整的历史版本存档CentOS 6.5 和 7.9 的 ISO 都能找到建议选 64 位版本安装后面处理 32 位兼容库时会方便些。虚拟机软件方面VMware 或者 VirtualBox 都可以我日常用 VMware 多一些网络模式选 NAT 就行。安装系统时不需要装带图形界面的“桌面版”选择最小化安装即可反正后面全程命令行操作。记得给虚拟机分配至少 1 核 CPU 和 1G 内存磁盘 20G 比较宽裕编译产生的临时文件和数据库文件都够放。2.2 系统装完先做这几件事系统安装完成后不要急着去下载源码先花几分钟把基础环境理顺。第一件事是确认网络畅通用ping -c 4 mirrors.aliyun.com测一下外网连通性确认能访问镜像站。第二件事是关闭 SELinux修改/etc/selinux/config文件把SELINUXenforcing改成SELINUXdisabled然后重启系统或者临时执行setenforce 0让它立即生效。第三件事是关闭防火墙CentOS 6 执行service iptables stop chkconfig iptables offCentOS 7 执行systemctl stop firewalld systemctl disable firewalld。这里要提醒一句关闭防火墙和 SELinux 只适合在本地虚拟机或内网测试环境里操作如果你是把服务放在公网机器上这样做会带来安全风险建议单独配置对外开放端口。但对于本地研究学习来说先把环境简单化能减少非常多莫名其妙的问题。网络源也要顺手处理一下。CentOS 6.5 安装完后默认的 yum 源基本处在半失效状态直接yum install会报 404 或连接超时。解决方法是手动把/etc/yum.repos.d/CentOS-Base.repo里的 mirrorlist 和 baseurl 替换成 vault 归档地址比如https://mirrors.tuna.tsinghua.edu.cn/centos-vault/6.5/这种格式。CentOS 7.9 的源则比较省心正常安装完就能直接使用嫌慢也可以换成阿里云或清华的镜像源。3. 工具链和依赖库的完整安装清单3.1 编译工具链先装齐接下来是安装编译工具链一套老 C 项目必需的软件包包括 gcc、gcc-c、make、glibc-devel 等。如果你只是拍脑袋装了个最小化系统这些包默认不会全部存在所以先用一条命令把基础包全部装上yum install -y gcc gcc-c make glibc-devel libstdc-devel这里解释一下为什么需要libstdc-devel。老代码编译时经常用到std::string、std::vector这类标准库容器如果只装了运行库没装开发包编译时会报找不到头文件的错误。同样的道理glibc-devel提供的是 C 运行时对应的头文件和静态库缺了它连最基础的stdio.h都可能找不到。如果需要交叉编译或者要编出 32 位程序还得安装 32 位兼容开发包。命令是yum install -y glibc-devel.i686 libstdc-devel.i686我在实际编译过程中很少会直接用-m32参数去强行编 32 位版本而是先正常编 64 位的如果出现指针转换相关的编译错误再回过头来加 32 位环境。原因很简单强行 32 位编译往往需要额外解决兼容库缺失问题问题面会扩大。3.2 数据库相关依赖一个都不能少石器时代服务端源码最核心的外部依赖就是 MySQL 客户端库。很多编译报错的本质都是数据库头文件缺失比如最常见的错误信息fatal error: mysql.h: No such file or directory就是因为只装了 MySQL 服务端没装开发包。在 CentOS 6.5 上直接执行yum install -y mysql-server mysql-devel在 CentOS 7 上默认数据库是 MariaDB安装命令调整为yum install -y mariadb-server mariadb-devel从兼容性角度讲老源码调用的是 MySQL 的 C APIMariaDB 的客户端库和头文件在接口层面与其保持高度兼容直接替换没有实质问题。如果你的代码中对 MySQL 版本有硬编码判断比如调用了一些只在 MySQL 5.5 之前存在的 API那就要在 CentOS 6 上装对应版本的老 MySQL这个情况比较少见但我在实际中确实碰到过一份代码调用了mysql_real_connect的旧签名导致在 MariaDB 上编译不通过。装完开发包后建议验证一下头文件是否就位执行ls -l /usr/include/mysql/mysql.h有这个文件存在编译时的头文件问题就解决了一半。另外还需要确保libmysqlclient.so动态库可以被链接器找到CentOS 上执行ldconfig -p | grep mysqlclient可以查看当前系统识别的 MySQL 客户端库路径。3.3 其他可能用到的辅助库除了数据库依赖老服务端代码还经常依赖 zlib 压缩库和一些旧式网络编程中会用到的库。zlib 的开发包安装命令是yum install -y zlib-devel不要小看这个包很多服务端在启动时要读取压缩过的配置文件或做数据包的压缩传输如果你只装了 zlib 运行库而缺少 zlib-devel编译时会报zlib.h: No such file or directory。这类错误在日志里看起来非常突兀因为报错位置可能距离真正缺少的依赖很远初次排查的人容易一头雾水。另外老代码中线程同步部分常用 pthread现代 glibc 已经将 pthread 集成进基础 C 库但部分老代码的 Makefile 依然会显式加-lpthread参数这个不用特别安装什么确认系统装了glibc-devel即可。我个人习惯在正式编译前把gcc --version、make --version、mysql_config --version这几个关键工具的版本都打印出来看一眼确认工具链就位。版本检查这一步看似多余却能帮你快速判断报错到底来自工具链问题还是代码问题属于投入产出比很高的排障手段。4. 数据库准备与SQL导入4.1 初始化数据库服务编译通过只是第一步想要让服务端跑起来数据库必须提前准备好。有些朋友把编译和数据库割裂开来看以为只要能 make 成功就大功告成结果一启动服务端就报数据库连接失败又跑回来问为什么其实源头就是跳过了数据库初始化。先启动数据库服务。CentOS 6 执行service mysqld start chkconfig mysqld onCentOS 7 执行systemctl start mariadb systemctl enable mariadb启动后最好执行一遍安全初始化脚本设置一个简单的 root 密码。基于本地测试场景我通常会设置为123456写服务端配置时也方便。执行命令mysql_secure_installation过程中会询问一系列问题按提示设置 root 密码、移除匿名用户、禁止 root 远程登录。后面两项按 Y 确认因为本地测试不需要这些暴露面。需要注意CentOS 6.5 自带的 MySQL 5.1 初始化和 CentOS 7 的 MariaDB 略有差异如果遇到mysql_secure_installation命令不存在的情况可以直接进入mysql命令行手动执行UPDATE mysql.user SET PasswordPASSWORD(123456) WHERE Userroot; FLUSH PRIVILEGES;4.2 创建游戏库并导入初始数据数据库服务起来后需要把源码包里附带的 SQL 文件导入进去。源码目录下一般会有一个sql或者db文件夹里面放着sa.sql或init.sql之类的文件。如果是压缩包先解压再说。导入之前先建一个专用数据库以常见的sa库名为例mysql -uroot -p Enter password: CREATE DATABASE sa DEFAULT CHARACTER SET utf8; USE sa; SOURCE /root/sa/sql/sa.sql;执行SOURCE命令后大量建表语句和初始数据会陆续执行。这一步如果报错最常见的原因是 SQL 文件中的字符集和老数据库版本不兼容比如某些表使用了utf8mb4字符集而 CentOS 6.5 的 MySQL 5.1 不支持这个字符集。解决办法是打开 SQL 文件全局替换把utf8mb4替换成utf8通常就能顺利导入。导入完成后创建一个专用的数据库账号供服务端连接并给足权限GRANT ALL PRIVILEGES ON sa.* TO salocalhost IDENTIFIED BY sa123456; FLUSH PRIVILEGES;这一步看似简单却能拦截掉一大批“服务端启动后连不上库”的问题。很多源码包的配置文件中写死了数据库账号密码如果你不提前把账号密码对齐成配置里的值服务端启动时会连库失败。5. 编译实操过程和踩坑记录5.1 进入源码目录、调整Makefile数据库弄好后回到源码编译的正题。先把源码包解压到一个统一的工作目录比如/root/sa解压命令mkdir /root/sa tar -zxvf sa_source.tar.gz -C /root/sa cd /root/sa ls -la进去之后重点观察根目录下是否有Makefile文件。有就直接下一步没有就到子目录里找。很多版本的主服务程序在server或gameserver子目录下Makefile 也在里面。找到 Makefile 后先用vim打开看一眼开头部分重点关注里面的CC、CFLAGS、LDFLAGS和INCPATH变量。老代码的 Makefile 往往写得非常粗糙变量名各不相同甚至直接写死了源文件路径。我遇到过一份 Makefile 里引用了/usr/local/mysql/lib/mysql这种路径但实际机器上 MySQL 头文件在/usr/include/mysql不修改就编译必挂。修改方法很简单把不存在的路径替换成实际存在的路径即可。建议统一用mysql_config提供的参数来设置mysql_config --cflags mysql_config --libs这两条命令会输出编译和链接 MySQL 所需的全部参数把它们抄到 Makefile 对应的变量里数据库相关的路径问题就彻底解决了。5.2 从make到make install的完整流程Makefile 调整完成后先执行一次全量编译看效果make clean make 21 | tee build.log第一次编译通常不会一帆风顺你可能会看到一堆警告和个别错误。我的经验是警告可以先不管错误必须逐条解决。老代码在编译时出现warning: deprecated conversion from string constant to char*这类警告属于常态不影响最终产物可以忽略。但如果出现error:开头的行就说明有硬错误。保存编译日志很重要。把make的输出通过tee同时输出到终端和文件出错时可以翻日志定位。我曾经遇到过一个非常隐蔽的问题某个源文件在 64 位系统下用了int变量存储指针编译时只有警告运行时数组越界导致服务端随机崩溃这种问题在编译阶段很难发现运行阶段的排查工作量远比编译错误大。遇到这种情况我的建议是先把编译错误清零再回头处理值得注意的警告类问题。make顺利通过后根目录或对应子目录下会出现可执行文件比如sa_server、login_server、db_server等。这些文件的名字因源码版本而异不用死记。确认生成后执行file命令查看二进制格式file sa_server输出中能看到ELF 64-bit LSB executable或ELF 32-bit LSB executable字样。如果系统是 64 位但二进制是 32 位运行前需要安装glibc.i686兼容库yum install -y glibc.i686这一步很容易被忽略我在 CentOS 7 上运行 32 位版本的服务端时如果不装glibc.i686启动会直接报No such file or directory但这个错误和文件不存在表现一模一样非常容易误判成编译失败。5.3 服务端启停与连接验证编译出可执行文件后强烈建议先手动在前台跑一次服务端而不是直接写启动脚本。原因很简单前台运行时所有日志直接输出到终端任何报错信息都能第一时间看到排查效率最高。执行命令./sa_server启动过程中观察关键日志输出是否成功连接数据库、是否成功绑定端口、是否成功加载配置文件。如果一切正常终端会停在类似“server started”的提示或持续打印运行日志此时再开一个新终端用netstat -lnp查看服务端监听的端口。石器时代服务端常见的监听端口有9065和9070等这个数据同样因版本而异以实际配置文件为准。如果启动即崩溃优先查看日志中离崩溃最近的一行输出80% 的情况不是缺库就是配置写错。有一个很典型的坑是配置文件里的数据库连接串中密码加密方式不匹配老版本 MySQL 使用mysql_native_password插件如果你建的账号默认插件是新的caching_sha2_password老服务端连接时可能直接失败。端口确认监听成功后就可以尝试客户端登录验证了。客户端方面在本地电脑上装好对应的联机客户端把配置文件里的 IP 改成虚拟机的 IP端口保持与服务器一致登录时能进入游戏即表示全链路跑通。这一步是整个环境搭建过程最有成就感的时刻。6. 编译期间最常见的错误与排查思路6.1 mysql.h 找不到错误信息形如fatal error: mysql.h: No such file or directory原因很明确缺少 MySQL 头文件。在 CentOS 6.5 上执行yum install -y mysql-devel在 CentOS 7 上执行yum install -y mariadb-devel。安装完成后确认/usr/include/mysql/mysql.h存在即可解决。如果头文件存在但仍然报错检查 Makefile 的编译参数里是否包含了-I/usr/include/mysql这一项。老代码的 Makefile 经常漏掉头文件搜索路径手动补上就好。6.2 链接阶段 undefined reference链接错误长这样undefined reference to mysql_init undefined reference to pthread_create undefined reference to inflate这三个引用分别对应-lmysqlclient、-lpthread、-lz链接参数。Makefile 的LDFLAGS或LIBS变量中缺少这些库逐个补上即可。注意-lmysqlclient需要放在源文件列表之后链接器对库的解析顺序比较严格放错位置也照样报错。6.3 编译报错 g 版本过高如果你在别的 Linux 发行版上遇到代码写法过时导致的语法错误比如.c文件用void main或者把for循环内变量声明当成 C99 特性来用又不想换系统可以在编译参数里加-stdc98或-stdgnu98。但更省事的方案还是直接用 CentOS 7 自带的 gcc 4.8 来编实测兼容性最稳妥。6.4 可执行文件启动即消失表现是执行./sa_server后没有任何输出进程立刻退出。排查步骤固定为三步先看配置文件路径和语法二是看数据库连接串中的 IP、端口、账号密码是否正确三是尝试前台运行并设置环境变量输出调试日志例如部分服务端支持-d参数打印调试信息。90% 的启动即崩溃问题都在这三步里解决。7. 最后的几个实用建议这段内容算是整篇的落地补充。我在多次安装中总结出几条习惯分享给你一是虚拟机里的 CentOS 建议打一个快照再开始编译万一环境弄乱了直接回滚省去重装系统的时间二是源码包解压后先做一次tar -czf备份因为编译过程可能生成大量临时文件源码覆盖后不好还原三是数据库每次导入数据前备份一份干净的空库快照后面测试新版本脚本时可以随时回退。再一个小技巧是在/root/sa下写一个build.sh脚本把清理编译产物、设置环境变量、运行 make、启动服务端这几步串起来。后面每次修改代码后只需要跑一次脚本就能完成全流程比一个个命令敲要高效得多。脚本的内容不复杂核心就是把你上面手动执行过的命令按顺序放进去。我个人的体会是老游戏服务端源码的编译环境搭建比拼的从来不是多高深的技术而是对细节的敏感度。路径对不对、缺没缺头文件、Makefile 里有没有多余的旧路径每一步都很机械但每一步出错都足以阻断整个流程。按这篇清单的顺序走遇到问题时再对照速查表逐项排查绝大多数环境问题都能在半小时内解决。