
两年前第一次接到“从源码编译MySQL”这个任务时我心里是有点虚的。以前部署MySQL要么是官方tar包解压初始化要么是yum、apt直接装从没碰过cmake那一长串参数。但那次情况特殊安全基线要求不能直接使用官方预编译二进制必须从源码自行构建还要把不需要的功能裁掉把字符集、数据目录、socket路径全部固化到编译阶段。硬着头皮啃完CMakeCache.txt和上百个WITH选项之后我才意识到一个问题——网上讲MySQL安装的教程铺天盖地但把编译参数讲清楚、讲透的文章确实太少。所以这篇不聊什么快捷安装法而是把MySQL源码编译时真正需要关心的编译参数一个个拆开讲明白顺便把我在反复试错中踩过的坑也一并交代。1. 为什么还要从源码编译MySQL——预编译包解决不了的问题1.1 官方预编译包的三大限制官方tar包、rpm包、apt源里的MySQL二进制本质上是“功能全集”的通用构建。这个包要在成千上万种环境里跑所以编译团队必须把所有常用功能都打开把依赖的SSL、zlib等库尽量静态链接进二进制。这带来三个很现实的问题第一功能与依赖不可裁剪。你不需要Federated引擎、不需要NDB、不需要审计插件但预编译包里全都带上了。多出来的东西不只是磁盘占用更是攻击面和潜在故障点。安全扫描工具扫到二进制里某个第三方库版本偏旧你还没法单独换只能等官方出新包。第二默认行为被锁定。预编译包的默认数据目录、默认socket位置、默认字符集都是官方编译环境下定的。部署时你确实可以通过my.cnf去改但改配置文件这种“软配置”在自动化运维和容器化场景里很容易出错——漏了一台机器参数不一致集群表现就千奇百怪。第三平台适配不够彻底。官方包通常基于特定glibc版本和CPU微架构编译。遇到特殊硬件平台或者操作系统版本较老的环境编译出来的二进制要么跑不起来要么性能达不到预期。当年正式环境里有两台机器在压力测试时CPU占用总是偏高排查到二进制指令集层面才发现是官方包没有针对本机CPU做指令集优化。1.2 哪些场景值得付出编译成本不是说所有环境都要源码编译这个成本不低编译一次全功能MySQL 8.0四核机器配合4G内存差不多要二三十分钟甚至更久。但下面这些场景编译是值得的安全合规有硬性要求等保、金融、政务类项目经常要求提供编译选项清单、依赖组件版本台账。源码编译能让这些信息完全透明。非主流硬件或操作系统ARM架构、特定的Unix-like系统、以及官方没有提供二进制包的平台。功能裁剪与攻击面收敛把不需要的引擎、组件、插件从源头去掉二进制体积能减少不少安全扫描项也少一截。性能定制针对本机CPU开启特定指令集或者在编译期就锁定Release模式、开启连接池等优化。深度运维集成把数据目录、socket路径、日志路径全部固化进二进制之后再写配置文件和初始化脚本就省心得多不怕误改导致服务起不来。1.3 编译前的准备清单动手之前先把下面这几样准备好不然编译中段报错再回去补很浪费时间内存至少2G推荐4G以上。源码编译是一个重内存活make -j并发高时内存不够直接OOM整个编译进程被杀掉。磁盘至少预留5G源码包解压加编译产物比想象中占空间。基础编译工具链gcc、g、make、cmake。MySQL 8.0要求cmake 3.x太老的版本直接拒绝运行。依赖开发包ncurses-devel、openssl-devel、libaio-devel、pkg-config。每个发行版包名略有差异但缺了哪个cmake都会明确告诉你。boost库源码包。MySQL 8.0源码不自带boost这是很多人第一次编译就卡住的坎后面我会专门说。还有一件重要的事确认你要编译哪个大版本。MySQL 5.7和8.0的编译参数有差异5.7里有些参数在8.0已经被移除或改成默认启用照着旧教程抄很容易翻车。2. cmake编译参数逐类拆解从路径到功能开关2.1 基础路径与运行参数这些参数决定了MySQL跑起来长什么样这一组参数是编译参数里的“地基”直接决定MySQL安装完之后的目录结构、默认端口、socket位置和字符集。我先给一个我平时最常用的完整cmake命令后面逐一解释cmake . \ -DCMAKE_INSTALL_PREFIX/usr/local/mysql \ -DMYSQL_DATADIR/data/mysql \ -DMYSQL_UNIX_ADDR/var/run/mysqld/mysqld.sock \ -DMYSQL_TCP_PORT3306 \ -DDEFAULT_CHARSETutf8mb4 \ -DDEFAULT_COLLATIONutf8mb4_0900_ai_ci \ -DWITH_BOOST/opt/boost_1_77_0 \ -DWITH_SSLsystem \ -DWITH_ZLIBbundle \ -DWITH_SYSTEMD1 \ -DCMAKE_BUILD_TYPERelease \ -DWITH_UNIT_TESTS0我习惯把这组参数称为“目录与身份参数”它们像房子的户型图——一开始定错后面改起来极麻烦。下表是每个参数的说明参数作用我常用的值备注CMAKE_INSTALL_PREFIX安装根目录/usr/local/mysql相当于预编译包的basedirMYSQL_DATADIR数据文件默认目录/data/mysql编译后作为默认值固化MYSQL_UNIX_ADDRsocket文件默认路径/var/run/mysqld/mysqld.sock这里我习惯专门建目录后面方便配权限MYSQL_TCP_PORT默认监听端口3306编译后可用--port临时覆盖DEFAULT_CHARSET服务端默认字符集utf8mb48.0默认就是utf8mb4但显式写上更保险DEFAULT_COLLATION默认排序规则utf8mb4_0900_ai_ci跟随字符集一般不用单独指定注意一个细节这些路径一旦编译进二进制就成了“默认值”。之后你写my.cnf时可以再覆盖但我的经验是——编译时定好配置里就不要再写第二遍避免两个地方各写一份维护时互相矛盾。2.2 存储引擎参数哪些引擎要留哪些引擎该砍这是编译参数里我最想提醒大家小心的一组。MySQL 8.0里InnoDB是默认引擎也是核心引擎cmake会自动把它编进去。其余引擎属于可选件用WITH_系列参数显式启用或者用WITHOUT_系列参数显式排除。我常用的引擎参数长这样-DWITH_INNOBASE_STORAGE_ENGINE1 \ -DWITH_MYISAM_STORAGE_ENGINE1 \ -DWITH_ARCHIVE_STORAGE_ENGINE0 \ -DWITH_BLACKHOLE_STORAGE_ENGINE0 \ -DWITH_FEDERATED_STORAGE_ENGINE0 \这里要分清楚WITH_XXX1是启用某个引擎WITH_XXX0或者不写大多情况也算不启用。但WITHOUT_XXX_STORAGE_ENGINE1是更彻底的排除方式尤其在5.7时代更常见。有两点经验供参考第一“极致裁剪”要克制。我有一段时间很热衷于把所有用不到的引擎全部干掉包括MyISAM。后来发现某些备份工具、某些系统表的兼容逻辑会依赖MyISAM引擎存在虽然不至于直接报错但在边缘场景下会冒出奇怪的小问题。后来我学乖了InnoDB之外的引擎除了明确知道不用的其余保留默认配置就行别为了删而删。第二8.0和5.7在分区表上的参数不同。5.7里分区表有专门的WITH_PARTITION_STORAGE_ENGINE参数8.0里InnoDB原生支持分区这个参数已经被移除。如果你看到老教程让你加“partition存储引擎”参数那是过时的写法。2.3 依赖库参数boost、SSL、zlib怎么配才不出妖蛾子这组参数看着不起眼但80%的编译失败都是它们引起的。先说boost。MySQL 8.0源码包编译时强依赖boost库但官方源码包默认不包含boost。很多人第一次编译就在这一步报错Could not find (the correct version of) boost. MySQL currently requires boost_1_73_0解决方式有两种。第一种到boost官网下载对应版本源码包解压到某个目录然后-DWITH_BOOST/opt/boost_1_77_0第二种让cmake自己下载-DDOWNLOAD_BOOST1 \ -DWITH_BOOST/opt/boost两种我都用过。生产环境我推荐第一种因为cmake自动下载依赖网络状况一旦下载中断或者超时重来一遍很痛苦。而且版本必须和MySQL要求的一致差一个版本都过不了检查报错信息里会明确写出当前需要哪个版本。再说SSL。编译时需要确认系统里有openssl-devel开发包。参数写法我推荐-DWITH_SSLsystem意思是使用系统的OpenSSL库。如果系统里OpenSSL版本太老或者出于安全要求必须用指定版本也可以手动指定路径例如-DWITH_SSL/usr/local/ssl这里有个特别容易踩的坑编译时没有正确链接SSLMySQL虽然能编译成功但运行时have_ssl会是DISABLED状态。客户端用SSL方式连接时会报一堆SSL相关错误对应用层来说非常难排查——因为问题不在配置而在编译期。我后面会专门讲这个。最后是zlib。zlib负责压缩支持主要用于备份压缩、网络传输压缩。参数写法-DWITH_ZLIBbundlebundle表示使用MySQL源码包自带的zlibsystem表示使用系统zlib。我推荐bundle因为系统zlib版本在不同发行版差异较大用自带的最省心。2.4 编译模式与功能开关Release、systemd、单元测试这些细节别忽略-DCMAKE_BUILD_TYPERelease这个参数我建议必加。不指定的话默认是Debug模式编译出来的二进制带了调试信息性能差一截体积大一截生产环境完全没必要。-DWITH_DEBUG0显式关闭调试支持。Release模式下默认就是关的但和CMAKE_BUILD_TYPE一起写上语义更清楚。-DWITH_SYSTEMD1如果你打算用systemd管理MySQL服务这个参数建议打开。开了之后源码里会生成一份systemd服务文件用起来比手写配置正规得多。-DWITH_UNIT_TESTS0关掉单元测试的编译能明显缩短编译时间。默认是会编测试代码的纯生产部署不需要。-DENABLE_DTRACE0DTrace动态跟踪一般用不上默认关掉即可。需要说明的是cmake参数写法有点灵活布尔类型可以写1、ON、YES表示开0、OFF、NO表示关。混着写不会报错但一个项目里最好统一风格否则看CMakeCache时容易精神分裂。3. 参数组合中的坑与依赖关系我的实测经验3.1 WITH_BOOST路径报错的完整排查记录这个坑我印象太深了。第一次编译MySQL 8.0.27时我满怀信心地执行cmake瞬间收到boost相关报错。当时我的第一反应是boost没装赶紧去官网下了一个最新版解压到/usr/local/boost加参数-DWITH_BOOST/usr/local/boost重新跑还是报错。仔细读报错信息才发现MySQL要求的是boost_1_73_0而我下载的是boost_1_78_0。版本不匹配cmake直接拒绝继续。后来我养成了一个习惯任何报错先读完整的信息再动手。报错信息里通常已经写了“MySQL currently requires boost_X_X_X”照着这个版本去下载一次就过。另外补充一个细节下完boost之后解压出来的目录名最好带版本号例如boost_1_77_0然后-DWITH_BOOST指向这个目录。不要指向boost源码目录的上级目录cmake找的是包含boost子目录的路径。这个指引不清我把-DWITH_BOOST/usr/local/src这种写法也试过一样报错。3.2 CMakeCache.txt缓存坑改参数后不生效的元凶这个坑是我在实际工作中发现的最隐蔽的问题。当时我在已有编译目录里调整参数加了一个引擎重新执行cmake发现数据字典里引擎列表根本没有变化。查了半天最后才发现问题出在缓存。cmake第一次运行后会把所有参数的取值写进CMakeCache.txt。之后再执行cmake即便你在命令行写了新参数缓存里的旧值也可能被优先使用尤其是一些依赖项探测结果。这就是为什么很多人改了参数重编输出却和上次一模一样。正确的操作是修改已有参数时先清理缓存再重新cmake。rm -rf CMakeCache.txt CMakeFiles cmake . -DCMAKE_INSTALL_PREFIX...这里有一个补充经验如果是新增参数比如原来没开某个引擎现在想加开可以直接重新cmake缓存不会冲突。但如果是修改已有参数的取值比如路径变了、字符集变了、开关从0变1就一定先删缓存。我后面有条原则是“怀疑CMakeCache.txt就删除重来”踩过两次坑之后这就成了我的默认动作。3.3 裁剪引擎时容易被忽略的连带风险源码编译最吸引人的点是裁剪最坑人的点也是裁剪。我有一段时间为了优化性能把MyISAM引擎从编译参数里禁用了。当时业务跑得挺正常后来做数据迁移时某个老工具在导入导出数据时突然卡住报错信息指向“无法创建MyISAM临时表”。查了半天才确认是编译期禁掉MyISAM导致的工具内部默认使用MyISAM引擎创建临时表。虽然这种情况可以用tmp_table相关配置规避但冷不丁冒出来一下排查成本很高。再就是插件联动。比如需要全文索引的场景8.0里内置了ngram和MeCab插件。如果你编译时把相关依赖裁了后续想启用全文索引功能就会碰壁。我的建议是编译期裁剪只砍明确不需要的功能如果不确定宁可保留。裁剪节省的那点磁盘和内存在运维省心面前不值得一提。3.4 SSL参数与运行时连接错误的关联很多人遇到“mysql ssl连接错误”第一反应是改my.cnf里的ssl配置或者纠结证书对不对。但有一种情况容易忽略——问题出在编译期。说一个我朋友运维团队的真实案例他们的MySQL是某个同事从源码编译的跑了一段时间后应用侧突然报SSL连接错误。大家查证书、查端口、查用户授权全都正常最后我让他去执行一下SHOW VARIABLES LIKE %ssl%;结果have_ssl的值是DISABLED。继续查编译参数发现当时cmake时机器上没装openssl-develcmake自动降级成“不使用SSL”的配置编译出的mysqld根本不支持SSL。应用侧却一直按SSL方式连接两边对不上就报错。这个教训很值钱编译参数决定运行时能力。:set number很多“运行时问题”的根因可以一路回溯到编译期的某个依赖缺失。生产环境编译MySQL前先确认openssl-devel已经安装编译完用ldd确认mysqld实际链接的SSL库ldd /usr/local/mysql/bin/mysqld | grep ssl正常会看到libssl相关的输出。如果看不到说明SSL压根没编进去趁早回头补依赖重编别在运行时折腾证书。4. 编译完成后的验收清单如何确认参数真的生效4.1 版本信息、编译信息与帮助输出编译加安装全部结束之后第一件事是验证版本和编译信息/usr/local/mysql/bin/mysqld --version正常会输出类似/usr/local/mysql/bin/mysqld Ver 8.0.36 for linux-glibc2.12 on x86_64 (Source distribution)注意“Source distribution”字样它代表这是源码编译版本而不是官方预编译二进制。这本身就是一条有效验证。再执行/usr/local/mysql/bin/mysqld --verbose --help | grep -E character-set-server|datadir|socket|port这些输出会展示编译时固化的默认值。如果看到的值和你cmake参数里写的值一致说明路径和端口参数确实生效了。如果和你预期不符先别急看看是不是my.cnf里的配置覆盖了默认值——这一步要区分清楚避免误判。4.2 运行时变量与引擎列表验证MySQL启动后用客户端连进去执行几组命令做最终验收。第一组是编译相关的变量SHOW VARIABLES LIKE version_compile_os; SHOW VARIABLES LIKE version_compile_machine; SHOW VARIABLES LIKE have_ssl; SHOW VARIABLES LIKE character_set_server; SHOW VARIABLES LIKE collation_server;version_compile_os和version_compile_machine直接显示编译时的操作系统和硬件平台。have_ssl这个变量尤其重要如果显示DISABLED说明编译时SSL支持没编进去这时候检查openssl-devel和WITH_SSL参数。第二组是引擎列表SHOW ENGINES;这条命令的输出里每一行就是一个引擎Support列显示YES的就是编译时纳入的。对照自己的预期看有没有多出来不该有的、或者少了不该少的。第三组建议做个建表实测CREATE TABLE test_engine_check (id INT) ENGINEInnoDB DEFAULT CHARSETutf8mb4; SHOW CREATE TABLE test_engine_check\G通过SHOW CREATE TABLE确认默认引擎和默认字符集确实是编译参数指定的值。很多运行时的“默认值”其实是多个层面叠加的结果但编译时值是最底层的那个。4.3 参数记录、文件留存与后续维护编译参数这个东西一次编译一时爽长期维护火葬场。我的习惯是编译完之后立刻把关键参数固化到文档里顺便说明编译日期、编译环境、依赖版本。参数信息从哪拿最权威的是CMakeCache.txtgrep -E ^CMAKE_INSTALL_PREFIX|^MYSQL_DATADIR|^MYSQL_UNIX_ADDR|^MYSQL_TCP_PORT|^DEFAULT_CHARSET|^DEFAULT_COLLATION|^WITH_BOOST|^WITH_SSL|^WITH_ZLIB|^CMAKE_BUILD_TYPE CMakeCache.txt把输出存到编译目录下的BUILD_INFO.txt或者直接放进运维文档里。下次升级版本、迁移机器、复现环境时这份记录能省下大量重新摸索的时间。这里要提醒一个容易混淆的点mysql_config --cflags和mysql_config --libs输出的是客户端程序编译时需要链接的库路径和头文件路径不是服务端编译参数。很多人拿这个去验证服务端构建配置完全搞错了方向。服务端参数验证看CMakeCache.txt和mysqld --verbose --help才靠谱。4.4 升级与迁移时的参数继承MySQL升级到新版本时很多人喜欢从官网直接下载新版本二进制替换这没问题。但如果你之前的版本是源码编译且做了不少定制直接替换等于丢失了原来的编译配置。我的做法是升级前先从旧版本的CMakeCache.txt里导出参数对照新版本的变更点逐项确认删掉已经废弃的参数加上新版本要求的参数比如boost版本往往要跟着升。然后在新环境下重新编译。整个过程必须重新验证一遍不要以为参数一样编译结果就完全一样——编译器版本、依赖库版本、操作系统版本都会影响最终行为。遇到编译报错先去看CMakeError.log和CMakeOutput.log这两个文件cmake自己会把探测过程和错误原因写进去。很多时候报错信息里的指引比网上搜到的过时教程可靠得多。编译参数这门手艺本质是环境掌控力源码编译MySQL的整个过程走下来我有一个很深的体会编译参数的价值不在于“源码安装”这个动作本身而在于你通过这几十个参数真正掌握了自己环境里MySQL的每一个能力边界。预编译包像精装房拎包入住源码编译像毛坯房自装你可以决定哪些墙要拆、哪些电路要改。代价是前期工作量大但换来的是后续运维时极高的确定性和掌控感。最后分享几个我积累的实操小技巧编译用的机器最好是和正式环境同一代CPU、同一套操作系统不然指令集差异可能在特定负载下显现。make并发数不要无脑拉满make -j$(nproc)在内存不足的机器上特别容易OOM。保守一点用make -j4编译时间多十几分钟但稳定。编译完成后顺手把MySQL安装目录下的lib路径加进/etc/ld.so.conf.d/再跑一次ldconfig免得客户端运行时因为找不到共享库报错。每次编译都在源码目录外单独建一个build目录例如mysql-build不要在源码根目录里原地编译。这样清理缓存、切换参数、保留现场都比在源码目录里折腾舒服得多。源码编译这条路第一次走确实有点坎坷。但只要你认真读过一遍报错信息、亲手查过一次CMakeCache.txt那些曾经看起来像天书的编译参数就会变成你手里一个个可以精确控制的开关。这份经验带来的收益远不止是一台MySQL。