MySQL源码编译全攻略:从cmake配置到make安装的实战指南

发布时间:2026/10/10 3:58:32
MySQL源码编译全攻略:从cmake配置到make安装的实战指南
我最早自己动手编译MySQL是很多年前在一台部署机上折腾存储引擎。官方二进制包装完才发现项目需要的自定义插件和字符集排序规则根本不带只能老实从源码走一遍。后来做过的测试环境和线上小规模部署多了慢慢摸清了这条路MySQL源码编译本身门槛不高但它确实有一堆文档不会明说的细节比如依赖库的坑、cmake参数的取舍、make阶段的内存杀手。这篇文章就是把这几年的实操经验梳理出来从环境准备到编译安装、再到二进制包落地的完整过程给那些想自己编译、或者被官方包限制住的朋友做个参考。1. 放着现成的二进制包不用非要从源码编译的动机先说一句大实话90%的场景下直接下载官方编译好的二进制包是最省事的。但剩下的10%恰恰是源码编译体现价值的地方。1.1 官方二进制包搞不定的几个典型场景我遇到过需要自己动手编译MySQL的基本逃不出这几种情况存储引擎定制。官方包把所有引擎都编进去了但你某些场景下根本不需要MyISAM甚至InnoDB的部分功能。如果是在嵌入式设备或内存受限的容器环境里把不需要的引擎和组件裁掉二进制体积能小不少启动占用也会更低。特殊插件和功能。一些分支特性、自定义插件、或者官方包没有启用的编译选项只有从源码编译才能带上。比如某些企业环境要求开启额外的审计日志功能或者集成自己的鉴权插件。性能相关的编译参数调整。官方包的编译参数是面向通用环境的默认不开-marchnative这类针对CPU指令集的优化。自己编的时候可以根据部署机的CPU微调虽然提升幅度看业务而定但在特定计算密集场景下确实能感受到差异。安全与合规要求。有些项目交付要求所有组件从源码构建方便做代码审计和依赖追溯。这时候你会发现源码编译不光是技术选择更是流程要求。1.2 什么情况下真没必要学人家编译反过来说如果你只是想装个MySQL跑业务又没有上面这些特殊诉求直接用官方包就行。我也见过有人为了看起来专业非要编译一遍结果卡在依赖上浪费一下午最后一句话没必要。还有一点要提醒源码编译不代表一定更安全。源码级审计是有意义但前提是你真的去看过那些代码而不是编完就万事大吉。如果你对C代码不熟官方二进制包反而更省心毕竟人家有庞大的测试体系兜底。2. 编译前的准备工作依赖、工具链和目录规划MySQL从源码构建本质上是一个C项目的编译过程。你得先把编译器、构建工具、依赖库都配齐这一步做不好后面全是坑。2.1 核心工具链GCC和CMake的版本匹配MySQL的源码包对编译器版本有明确要求版本太老或太新都可能出问题。以两个最常见的版本线来看MySQL版本推荐的GCC版本CMake版本备注MySQL 5.7GCC 4.8以上CMake 3.0老版本兼容性好系统自带通常够用MySQL 8.0GCC 7.5以上CMake 3.19依赖C17特性太老的编译器直接报错我在Rocky Linux 9上编过8.0系统默认的GCC 11和CMake 3.20都能通过。Ubuntu 22.04默认GCC 11也没问题。如果你用的还是CentOS 7那种老系统编8.0之前必须先检查GCC版本低于7.5的建议用scl或者devtoolset切换新版本硬着头皮编会遇到一堆莫名其妙的模板语法错误。检查工具链版本可以用这几条命令gcc --version g --version cmake --version make --version如果版本不达标Ubuntu/Debian系用apt install build-essential cmake补齐Rocky/RHEL系用yum groupinstall Development Tools再加yum install cmake。2.2 依赖库逐个说清楚MySQL编译时涉及的依赖库不算多但没有一个能缺。不同操作系统上的包名有差异我用表格说明方便对号入座依赖库作用Ubuntu上的包名Rocky/RHEL上的包名ncurses终端处理libncurses5-dev / libncurses-devncurses-developensslSSL/TLS支持libssl-devopenssl-devellibaio异步IOlibaio-devlibaio-develpkg-config依赖查找pkg-configpkg-configbison语法分析器生成bisonbisonzlib压缩支持zlib1g-devzlib-devel装依赖的命令Ubuntu下是这样apt update apt install -y build-essential cmake libncurses-dev libssl-dev libaio-dev pkg-config bison zlib1g-devRocky/RHEL下则是yum install -y gcc gcc-c cmake make ncurses-devel openssl-devel libaio-devel pkgconfig bison zlib-devel这里要特别说下libaio。如果你在源码目录执行cmake时看到类似Could NOT find AIO的报错但明明系统里装了libaio一般是缺libaio-devel这个开发包。在容器等精简环境里尤其容易踩libaio.so运行时库和编译用的头文件是两回事。2.3 Boost库MySQL 5.7时代最经典的坑如果你是编MySQL 5.7Boost是绕不开的一道坎。5.7的源码里大量使用Boost库但源码包本身不附带需要手动准备。两种常见做法# 方式一下载boost到本地cmake时指定路径 wget https://boostorg.jfrog.io/artifactory/main/release/1.59.0/source/boost_1_59_0.tar.gz tar -xzf boost_1_59_0.tar.gz -C /opt/ # 方式二让cmake自动下载需要外网速度看网络环境 cmake -DDOWNLOAD_BOOST1 -DWITH_BOOST/opt/boost …我个人习惯方式一原因很简单自动下载经常因为网络问题失败而且Boost包的体量不小解压也慢。手动下载指定版本至少能把网络故障和编译故障分开排查。MySQL 8.0起Boost要求被内置到了源码包里不再需要单独准备这也算是少了一个大坑。2.4 磁盘和内存的底线要求编译MySQL是一个吃资源和吃磁盘的过程。我建议至少预留磁盘源码包解压加编译中间产物5.7大概需要5GB左右8.0因为代码量更大10GB起步比较稳。内存如果只开make -j24GB内存勉强能跑。想用make -j4甚至-j8加速最好有8GB到16GB内存否则编到一半出现Killed进程基本都是内存不足导致。另外不要在/tmp空间很小的机器上解压源码/tmp默认分区不够大就改到/opt这类大分区下工作。3. cmake配置阶段这步定生死编译MySQL和编译很多开源项目一样cmake负责生成构建系统make才是真正干活的人。configure阶段把参数写明白后面就顺很多。3.1 先看核心参数和含义我整理了一份常用参数表按重要程度排列参数作用示例备注CMAKE_INSTALL_PREFIX安装目录-DCMAKE_INSTALL_PREFIX/usr/local/mysql默认值不设的话容易装到奇怪位置MYSQL_DATADIR数据目录-DMYSQL_DATADIR/data/mysql建议一开始就规划好别装完再挪DEFAULT_CHARSET默认字符集-DDEFAULT_CHARSETutf8mb4现在基本都选utf8mb4DEFAULT_COLLATION默认排序规则-DDEFAULT_COLLATIONutf8mb4_general_ci与字符集配套WITH_BOOSTBoost目录-DWITH_BOOST/opt/boost_1_59_05.7专用8.0不需要DOWNLOAD_BOOST自动下载Boost-DDOWNLOAD_BOOST1配合WITH_BOOST使用CMAKE_BUILD_TYPE构建类型-DCMAKE_BUILD_TYPERelease默认RelWithDebInfoRelease去掉调试符号SYSCONFDIR配置文件目录-DSYSCONFDIR/etc/mysql不设的话配置文件位置可能和预期不符WITH_SSLOpenSSL支持-DWITH_SSLsystem使用系统OpenSSL一个我在生产环境常用的最小配置写出来就是这样cmake . \ -DCMAKE_INSTALL_PREFIX/usr/local/mysql \ -DMYSQL_DATADIR/data/mysql \ -DDEFAULT_CHARSETutf8mb4 \ -DDEFAULT_COLLATIONutf8mb4_general_ci \ -DWITH_BOOST/opt/boost_1_59_0 \ -DSYSCONFDIR/etc/mysql \ -DWITH_SSLsystem如果你编8.0把WITH_BOOST那行去掉就行。3.2 按需裁剪引擎和组件的实际收益默认情况下MySQL会把InnoDB、MyISAM、CSV等一堆引擎都编进去。如果场景明确可以用WITHOUT_xxx_STORAGE_ENGINE参数裁掉不需要的引擎。比如一个纯OLTP业务只需要InnoDB可以这样配cmake . \ ... \ -DWITH_INNOBASE_STORAGE_ENGINE1 \ -DWITHOUT_MYISAM_STORAGE_ENGINE1 \ -DWITHOUT_CSV_STORAGE_ENGINE1 \ -DWITHOUT_ARCHIVE_STORAGE_ENGINE1 \ -DWITHOUT_BLACKHOLE_STORAGE_ENGINE1 \ -DWITHOUT_FEDERATED_STORAGE_ENGINE1 \ -DWITHOUT_PARTITION_STORAGE_ENGINE1注意MySQL 8.0里WITHOUT_PARTITION_STORAGE_ENGINE已经无效了因为分区功能整合进了InnoDB。这类参数在升级版本时要重新核对吃不准就保持默认。裁剪的实际收益有两个方面一是编译时间变短二是二进制文件减小。但对大多数服务器部署来说收益其实有限毕竟磁盘和内存都不缺。真正受益的是嵌入式或容器化场景能省一点是一点。3.3 cmake阶段的典型报错信号配置阶段报错不可怕可怕的是报错了你不知道往哪看。常见的几个信号找不到BoostCould NOT find Boost。如果Boost目录确实存在先确认路径是否填对再看版本是否匹配。5.7源码对Boost版本有硬性要求太新的可能编译不过。找不到OpenSSLCould NOT find OpenSSL。多半是只装了运行时库没装开发包用前面表格里的包名补上。编译器版本过旧报错的文字里通常会提到C17或者std::filesystem。这种直接换编译器版本别在这里浪费时间。依赖缺bison/yacc报错会提示bison版本过低甚至根本没找到。装上之后记得cmake需要重新跑一遍。配置阶段还有个小技巧cmake失败后它会提示你查看CMakeCache.txt或者日志文件。如果你改了系统环境、装了新依赖重新执行cmake前最好直接删掉CMakeCache.txt不然旧配置会造成遗留干扰。rm -rf CMakeCache.txt CMakeFiles4. make构建阶段漫长的等待和内存杀手cmake通过后真正的体力活开始了。这一步不需要动太多脑筋但耐心和资源规划是成本。4.1 -j参数怎么设速度和安全怎么平衡make -jN是用N个线程并行编译。N越大概率越快但不是无脑设成CPU核心数就完事。我自己的经验规则是-j的值不要超过CPU核心数nproc能看到系统核心数量。内存不宽裕时-j 核心数的一半更稳。8核机器用-j4内存16GB以上的再考虑-j8。太老的机器比如2核4线程的云主机用make -j2就好别贪。举个例子在一台8核16GB内存的机器上编MySQL 8.0我用make -j6大约耗时40到60分钟。同一份源码用make -j2可能要2个小时。但如果你只有4GB内存还硬开-j8那就等着看下面这个场景吧。4.2 编到一半进程被Killed内存不足的完整排查链路这是我踩过最痛的坑没有之一。现象是这样make -j8进行到差不多30%的时候终端突然报出一堆奇怪的错误最后出现g: fatal error: Killed signal terminated program cc1plus。当时第一反应是磁盘满了因为编译中间文件占空间很凶。df -h看完磁盘还有大量剩余排除。第二反应是看看是不是/tmp或者内存swap不够。free -h一看内存全部耗尽swap分区几乎没用上。此时已经能基本判断是OOM内存不足导致内核把编译进程干掉了。再仔细看dmesg -T | tail里面能看到Out of memory: Killed process ...之类的记录这就能实锤了。解决办法也不复杂free -h dmesg -T | tail -30然后做三件事调低并行度从-j8改-j2。把swap分区临时加上给编译过程一个缓冲fallocate -l 8G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile清理之前的编译产物重新make。因为被中断的编译状态并不完全可靠保险起见make clean重新执行make -j2这次老老实实等它编完。这个坑教会我一个道理编译大型C项目时内存规划比CPU核数规划更重要。你追求速度没问题前提是内存撑得住。4.3 增量编译改配置不用全量重来有时候你会想调整某个编译参数比如加一个引擎或者从Debug改成Release。这时候不需要从头再来。在源码目录下重新运行cmake带新参数然后直接makeMySQL的构建系统会自动识别哪些目标文件受影响只重编改动部分。这个流程在很大程度上能节省时间所以我从不删除源码目录里的CMakeFiles除非要做完全干净的构建。不过也要说一句如果你改的是CMAKE_BUILD_TYPE这种影响全局的变量增量编译可能还不如make clean后来得干净。这个自己看着办反正我改这类全局参数时会选择全量重编。5. 编译完成后的安装与初始化部署make结束看到Build complete之类的提示编译就算成功。但MySQL真正能跑起来还差安装、初始化和配置这三步。5.1 make install和目录里的关键内容执行安装make install不出意外的话/usr/local/mysql下面会生成完整的目录结构。我习惯装完后先确认权限MySQL的运行账号不能是root。useradd -r -s /sbin/nologin mysql chown -R mysql:mysql /usr/local/mysql chown -R mysql:mysql /data/mysql这里解释一下为什么不能直接用root跑MySQL官方策略也是不给root权限运行mysqld进程为了安全隔离用它自己的低权限账号最稳妥。如果你跳过这一步后面初始化数据目录时指不定会遇到什么权限报错。5.2 初始化数据目录的两种方式MySQL 5.7和8.0的初始化方式有差异这个是新手绕不开的分水岭。5.7沿用旧逻辑可以这样初始化/usr/local/mysql/bin/mysqld --initialize-insecure --usermysql --datadir/data/mysql加了--initialize-insecure之后root账号默认没密码适合刚建完马上改密码的场景。如果想一开始就有随机密码去掉insecure初始化日志里会打印临时密码。8.0的初始化必须用--initialize或者--initialize-insecure旧的mysql_install_db脚本已经移除。所以8.0的初始化命令通常这样写/usr/local/mysql/bin/mysqld --initialize-insecure --usermysql --datadir/data/mysql初始化过程如果顺利数据目录下会出现mysql、performance_schema、sys等子目录。这一步失败时常见原因依然是目录权限或者依赖库问题。5.3 my.cnf配置与systemd服务注册初始化完成后写一份最基础的配置[mysqld] basedir/usr/local/mysql datadir/data/mysql socket/tmp/mysql.sock pid-file/tmp/mysql.pid port3306 character-set-serverutf8mb4 collation-serverutf8mb4_general_ci配置文件的加载顺序有系统默认路径但我们之前cmake指定了SYSCONFDIR/etc/mysql所以把配置放到/etc/mysql/my.cnf即可。然后注册systemd服务新建/etc/systemd/system/mysqld.service内容大致如下[Unit] DescriptionMySQL Server Afternetwork.target [Service] Typeforking Usermysql Groupmysql PIDFile/tmp/mysql.pid ExecStart/usr/local/mysql/bin/mysqld --defaults-file/etc/mysql/my.cnf ExecReload/bin/kill -s HUP $MAINPID ExecStop/usr/local/mysql/bin/mysqladmin shutdown PrivateTmpfalse [Install] WantedBymulti-user.target启动之前先测试配置/usr/local/mysql/bin/mysqld --defaults-file/etc/mysql/my.cnf --validate-config没问题就systemctl daemon-reload systemctl enable --now mysqld systemctl status mysqld到这里从源码编译出来的MySQL就跑起来了。6. 从源码包到长期维护几个非常实用的收尾动作编译安装的终结不是能启动而是好维护。以下几个习惯是我踩坑之后慢慢养成的分享出来真的能帮你少走弯路。6.1 保留编译目录别编完就删不少人make install成功后就觉得源码目录没用了直接删掉。我不建议这样。原因有两个后续想追加编译参数、重新编译保留源码树能省去重新解压和配置的时间。cmake缓存里保留了完整的编译参数以后看这个目录能清楚回忆当初是怎么编的。当然源码目录确实占几个GB空间正式服务器上不舍得留就打包搬到存储机器上归档但别丢。6.2 用自定义版本号标记自己的编译产物我自己编的MySQL有个习惯在cmake阶段加一个自定义版本标记这样日后看版本号就知道是不是自编译的。编译时指定-DMYSQL_SERVER_SUFFIX-custom装完执行/usr/local/mysql/bin/mysql --version输出会带着自定义后缀一眼就能识别。这在多台机器混合部署时尤其有用不会和官方二进制搞混。6.3 编译版MySQL后续升级怎么处理源码编译版升级不能像二进制包那样直接覆盖替换。我的建议策略是保留旧版本的源码编译参数记录就是上面说的cmake缓存或者你自己写个部署文档。下载新版本源码包在另一个目录重新配置编译。编译期间旧实例继续服务编完再计划内停机切换。切换前务必完整备份数据并且对新二进制在同一数据目录做一次冷启动验证。顺序上要注意不要先升级数据目录再编译万一编译失败你的数据可能已经被新版本的mysqld改过结构了。数据目录的安全优先级永远高于二进制更新优先级。6.4 编译参数记录输出历史好习惯我在处理了很多次编译部署之后养成了一个非常“笨”但无敌好用的习惯把每次的编译命令完整存成一个文件。此外还会把服务器的系统版本、内核参数、依赖包版本、编译时间、遇到的问题和解决方式都记下来。为什么这个习惯这么重要因为MySQL源码编译的坑不是编完就结束后续每次升级、换机器、重新部署时这些记录都会变成第一手排查依据。特别是当你编的是5.7这种老版本换台新系统编译时可能完全不一样当年的记录能省掉大量重复排查时间。我的记录长这样# 2024-05-XX MySQL 8.0.36 编译记录 # 系统: Rocky Linux 9.3 / GCC 11.4.1 / CMake 3.20.2 cmake . \ -DCMAKE_INSTALL_PREFIX/usr/local/mysql \ -DMYSQL_DATADIR/data/mysql \ ... make -j6 make install这个习惯看似简单但长期坚持下来它带来的价值可能比编译本身还大。至少每次新部署不用再靠回忆推断当初的配置。MySQL源码编译就是这样一件事第一次做觉得处处是坑做熟了以后它其实只是一条流程清晰、步骤确定的路径。希望这篇分享能让你在第一次走这条路的时候少浪费点时间在多踩的那些坑上。