主夫ときどきプログラマ

データベース、Webエンジニアリング、コミュニティ、etc

MySQL8.0のデバッグビルドをわりと詳しく書いてみる

MySQLデバッグビルドをやってみたので、その方法をまとめました。
参考になるブログなどは少なく、書いてある内容も暗黙知の部分が多く自分にはわからなかったので公式のドキュメントを読みながら進めました。
英語のドキュメントではありますが、わりと読めます。そしてGoogle翻訳つよい。ありがとう。 デバッグビルドしてVSCodeでデバッガーを動かすところまでの手順を紹介します。

環境

UbuntumacOSの両方で検証した。 基本的に同じ手順でできる。
Xcodeを使う場合はオプションで指定することでできる。

macOSはCatalina 10.15.6、Ubuntuは 18.04 20.04 でビルドが成功した。

事前準備

macHomebrewXcodeをインストールする。brewで必要なライブラリはインストールできる。 Linuxはaptを使ってインストールできる。

ビルドに必要なライブラリなど

ビルドに必要なライブラリはリファレンスマニュアルに記載がある。
MySQL :: MySQL 8.0 Reference Manual :: 2.9.2 Source Installation Prerequisites

これらのライブラリが必要になるので事前にインストールする。

  • g++
  • pkg-config

これらも特に記載がないが必要だった。

ncurses はそういう名前のライブラリをインストールするのではなく、コマンド群(ツール群)のようだ。以下のコマンドが使えればOK。UbuntuにもmacOSにも標準で入っているようだ。

  • captoinfo, a termcap conversion tool
  • clear, utility for clearing the screen
  • infocmp, the terminfo decompiler
  • tabs, set tabs on a terminal
  • tic, the terminfo compiler
  • toe, list (table of) terminfo entries
  • tput, utility for retrieving terminal capabilities in shell scripts
  • tset, to initialize the terminal

インストールする

Ubuntuではaptを使ってインストールする。

apt update 
apt upgrade

apt install cmake make gcc g++ openssl bison pkg-config

macOSの場合はXcodeをインストールすればCコンパイラはインストールされる。  gcc --versiong++ --version を実行すればXcodeのものが使われているのが確認できる。 他はbrewでインストールできる。

brew install cmake make openssl bison pkg-config

ソースコードを取得する

ソースコードGitHubで公開されている

git clone --depth 1  https://github.com/mysql/mysql-server.git

すべてをクローンすると時間がかかる。最新のものだけでいい場合は --depth オプションを使うと速い。

デバッグビルドする

git clone が終わるとmysql-server/ディレクトリが作られるのでソースコードディレクトリに移動する。

cd mysql-server

ビルド用のディレクトbld/ を作成しそこで作業を行う。

mkdir bld
cd bld

以降、bld/ ディレクトリでコマンド操作を行う。

CMake

CMakeのオプションはこちら。
MySQL :: MySQL 8.0 Reference Manual :: 2.9.7 MySQL Source-Configuration Options

cmakeする時にオプションでデバッグを指定することで、ビルド構成がデバッグ用となる。なのでデバッグビルドをするにはここのオプションが大事。 デバッグビルドするには -DWITH_DEBUG=ON を指定すればよい。ほか DCMAKE_BUILD_TYPE=Debug とすることでもデバッグビルドになる。

  • DCMAKE_BUILD_TYPE=type
    • Debug: Disable optimizations and generate debugging information. This build type is also used if the WITH_DEBUG option is enabled. That is, -DWITH_DEBUG=1 has the same effect as -DCMAKE_BUILD_TYPE=Debug.

デバッグ:最適化を無効にし、デバッグ情報を生成します。このビルドタイプは、WITH_DEBUGオプションが有効な場合にも使用されます。つまり、-DWITH_DEBUG = 1は-DCMAKE_BUILD_TYPE = Debugと同じ効果があります。 https://dev.mysql.com/doc/refman/8.0/en/source-configuration-options.html#option_cmake_cmake_build_type

また、Boostライブラリが必要なので -DDOWNLOAD_BOOST -DWITH_BOOST オプションを使って、自動ダウンロードと保存先を指定する。

$ cmake .. \
    -DWITH_DEBUG=ON \
    -DDOWNLOAD_BOOST=ON \
    -DWITH_BOOST=../boost

bool型のオプションしてはON/OFF でも 1/0 でも良い。

Xcodeを使うには

Xcode を使う場合は -G Xcode を追加すると、Xcode用にCMakeされる。その後 make の代わりに xcodebuild を実行するとXcodeでビルドされる。bld ディレクトリを指定してXcodeを起動するとGUIデバッグなどできそうな感じだったが、使い方がわからなかった。

エラーが出る時は

エラーの場合はメッセージが詳しく出るし、ライブラリが不足している場合はインストールする方法も表示されるので、メッセージをちゃんと読めば対応できるはず。英語に臆するな。

その後はCMakeのキャッシュを削除してからもう一度 cmake しよう

make clean
rm CMakeCache.txt

Make

Makeでデバッグビルドする。

make -j 8 || make -j 6 || make -j 4 || make

-j オプションで並列ビルドができる。指定するのは並列数。マシンリソースによっては途中でエラーが出てしまう。もう一度 make すれば続きをビルドしてくれるので、並列数を徐々に減らしながら make を続ける。

makeが完了すると bin/ ディレクトリにバイナリーが出力される。

ls bin
base64_test               ibd2sdi                   mysql_config_editor       mysqlpump                 perror                    protoc
basic-t                   innochecksum              mysql_secure_installation mysqlrouter               pfs-t                     protoc-3.11.4
bug25714                  libmysql_api_test         mysql_server_mock         mysqlrouter_keyring       pfs_account-oom-t         range_check_err
comp_client_err           lz4_decompress            mysql_ssl_rsa_setup       mysqlrouter_passwd        pfs_connect_attr-t        rest_cli
comp_err                  mf_iocache_test           mysql_tzinfo_to_sql       mysqlrouter_plugin_info   pfs_host-oom-t            simple-t
comp_sql                  my_print_defaults         mysql_upgrade             mysqlshow                 pfs_instr-oom-t           skip-t
conf_to_src               myisam_ftdump             mysqladmin                mysqlslap                 pfs_instr-t               skip_all-t
gen_keyword_list          myisamchk                 mysqlbinlog               mysqltest                 pfs_instr_class-oom-t     thr_lock
gen_lex_hash              myisamlog                 mysqlcheck                mysqltest_safe_process    pfs_instr_class-t         todo-t
gen_lex_token             myisampack                mysqld                    mysqlxtest                pfs_misc-t                uca9dump
hp_test1                  mysql                     mysqldump                 mytime_client-t           pfs_noop-t                xprotocol_plugin
hp_test2                  mysql_client_test         mysqlimport               no_plan-t                 pfs_user-oom-t            zlib_decompress

MySQLサーバーを動かす

データベースの初期化

MySQLサーバーを動かすためにはデータベースファイルの初期化が必要。 デバッグビルドされた mysqld を使ってデータベースファイルの初期化を行う。

bin/mysqld --initialize --basedir=$(pwd) --datadir=$(pwd)/data 

この時標準出力にMySQLの管理者パスワードが出力されるので記録しておく。

[Note] [MY-010454] [Server] A temporary password is generated for root@localhost: o*w5h=lh?F+E

--basedir --datadir を指定しない場合はビルドディレクトリがデフォルトのbasedirになるようだ。 なので、上記の場合は指定があってもなくても結果は同じになった。

サーバーの起動

MySQLサーバーを起動するには mysqld を実行する。

bin/mysqld

MySQLサーバー起動できる。一般的にはMySQLのオプションを指定するために my.cnf を使うことが多い。

以下のように my.cnf を用意する。ディレクトリはどこでも良いが今回は bld/ に設置する。

[mysqld]
basedir=/Users/masayuki14/workspace/mysql-server/bld
datadir=/Users/masayuki14/workspace/mysql-server/bld/data

--defaults-file オプションを使って my.cnf を指定してMySQLサーバーを起動する。

bin/mysqld --defaults-file=./my.cnf

mysqlクライアントから接続

サーバーを起動したら別ターミナルを開いてMySQLクライアントからサーバーに接続する。

bin/mysql -u root -p
Enter password:

データベースの初期化時に出力された初期パスワードを使ってログインする。 このパスワードは失効状態なので、パスワードを再設定する必要がある。 ALTER USER で変更する。

ALTER USER root@localhost IDENTIFIED BY 'MySQL8.0';

この時、デフォルトのポリシーでは英大文字小文字数字記号を含む8文字以上のパスワードにしないといけない。

サーバーの停止

mysqladmin コマンドを使うかMySQLサーバーに接続してSHUTDOWN コマンドを入力する。

bin/mysqladmin -u root shutdown -p
Enter password:
/bin/mysql -u root -p
Enter password:

mysql> SHUTDOWN;

VSCodeのDebuggerを動かす

C/C++拡張をインストール

ソースコードがある mysql-server/ ディレクトリでVSCodeを開くとソースコードが読める。C/C++拡張のインストールをお勧めされるのでインストールする。これによってコードジャンプとかデバッガーとかが動くんだと思う。拡張機能で何が追加されるとかそのへんはよくわかってない。 デバッグビルドをする前後で型情報とかの表示も変わるようだ。

.gitignore を編集したほうがいい

ビルド用のディレクトリがGitの差分として認識されてしまうので、 .gitignore を編集したほうがVSCodeに余計な負荷がかからなさそう。

bld/
boost/

を追加する。

デバッグ構成の追加

VSCodeの左サイドメニューからデバッガを選ぶ。三角と虫のアイコンのやつ。デフォルトではNode.jsのみが利用可能だが、C/C++拡張によりlldbが追加されている。 [構成の追加]からlldbを選んで追加すると launch.json が作成されエディタに表示される。

launch.json の一部を以下のように変えてMySQLサーバーが起動するようにする。

        "program": "${workspaceFolder}/bld/bin/mysqld",
        "args": ["--defaults-file=${workspaceFolder}/bld/my.cnf"],

${workspaceFolder}ソースコードを開いた mysql-server/ ディレクトリになるので、デバッグビルドしたmysqldと引数の--defaults-fileを指定する。

デバッガを動かしてブレークポイントを設定

デバッガは三角の起動ボタンをクリックすると動き出す。起動するとデバッグコンソールにメッセージが表示されMySQLサーバーが立ち上がる。 試しに sql_parse.cc:1178do_command() 関数あたりにブレークポイントを設定する。 その後MySQLクライアントをつないで SELECT 1; などを実行してみるとブレークポイントで処理が止まって変数の中身などが確認できる。

bin/mysql -u root -p
Enter password:

mysql> select 1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)

f:id:masayuki14:20200730164524p:plain
VSCodeによるDebug

こんな感じで確認できる。マウスポインターを変数に当てれば中身が見えるし、コールスタックなども確認できる。
正直なところさっぱりわからない。

これでデバッグビルドしてデバッガを動かす、の一連の作業はおわり。

デバッグビルドは何が嬉しいの?

mysqldmysqlデバッグ関連のオプションはデバッグビルドされた場合に使えるようになります。mysqld では --debug-sync-timeout=N が使えるようになったり、 mysql クライアントコマンドでは --debug --debug-check --debug-info のオプションが使えるようにります。スタックトレースなども出力できますが見方がわからないので、どう役立てていいか良くわかりません。だれか教えて。

以前なにかのスライドでMySQLクライアントでトレース情報みたいなものを出しているのを見たことがあるけど、どうやってやるんだろう。勘違いかな。

ということで普通にMySQLを使う上では何も嬉しいことはないと思います。ソースコード読んでみたいとか、デバッガ動かしたい、みたいなマニアックな欲求がない場合はデバッグビルドに手を出すことはないでしょう。一部の情報によるとmysqldumpソースコードは読みやすいらしいです。

きっかけ

デバッグビルドやってみようと思ったのは2年前でこのブログがきっかけでした。

labs.gree.jp

当時これを見ながらやってみたところ、うまくいかず原因もわからずで放置していましたが、MySQL熱が最近すこし上がってきたのと時間の余裕ができたのでやってみました。 作業ログをGitHub Issue に残してあり速攻で諦めているのがよく分かります。

MySQL8.0 source build · Issue #15 · masayuki14/worklog · GitHub

今回はじっくりリファレンスマニュアルを読みながら進めたので時間がかかりましたが、いろんな情報が自分の中でつながっていく感覚というのは良いものです。 MySQLデバッグビルドに興味がある方は試してみてください。

最後に、最近発売された MySQL徹底入門 第4版はいいぞ!