macOS Sonomaでのmysql2 gemのエラー対応

Sonomaでのmysql2関連のエラー対応メモです。
macOSアップグレードの度に毎回似たようなやつをググっては対応していたので、少し調べながら対応してみました。
根本的に理解するには、もっと深いところを調べる必要がありそう。
どれも、その筋の人にしか分からん対応な感じがする。

①'stdio.h' file not found

現象

bundle install時にエラーメッセージとして表示されているmkmf.logを確認します。

In file included from conftest.c:1:
In file included from /Users/rochefort/.asdf/installs/ruby/3.2.2/include/ruby-3.2.0/ruby.h:38:
In file included from /Users/rochefort/.asdf/installs/ruby/3.2.2/include/ruby-3.2.0/ruby/ruby.h:25:
/Users/rochefort/.asdf/installs/ruby/3.2.2/include/ruby-3.2.0/ruby/defines.h:16:10: fatal error: 'stdio.h' file not found
#include <stdio.h>
         ^~~~~~~~~
1 error generated.
checked program was:
/* begin */
1: #include "ruby.h"
2:
3: int main(int argc, char **argv)
4: {
5:   return !!argv[argc];
6: }
/* end */

stdio.h が無いというやつですね。近年よく見ますね。

対応

Xcode同梱のSDKを使うようにします。ググるとたくさん見つかります。

export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"

SDKROOTとは何なのか

xcrunのmanを見ると、それっぽいことが書いています。 具体的にbuild時にどうclangを呼び出してるかまでは見てないですが、ここに書かれているような実装なら SDKROOTに記載のSDKを指定することになるようです。

Specifies the default SDK to be used when looking up tools (some tools may have SDK specific versions).

This environment variable is also set by xcrun to be the absolute path to the user provided SDK 
(either via SDKROOT or the --sdk option), when it is used to invoke a normal developer tool 
(build tools like xcodebuild or make are exempt from this behavior).

          For example, if xcrun is used to invoke clang via:
             xcrun --sdk macosx clang test.c

then xcrun will provide the full path to the macosx SDK in the environment variable SDKROOT. 
That in turn will be used by clang(1) to automatically select that SDK when compiling the test.c file.

②'zstd' not found

現象

こちらもmkmf.log

(省略...)
compiling statement.c
linking shared-object mysql2/mysql2.bundle
ld: warning: ignoring duplicate libraries: '-lruby.3.2'
ld: library 'zstd' not found
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1

対応

zstdはbrewで入れてるので、環境変数を設定するのみ。これもググれば出てきます。

export LIBRARY_PATH=$(brew --prefix zstd)/lib/:$LIBRARY_PATH

LIBRARY_PATH とは何か

stackoverflowに挙がっていました。 gcc - LD_LIBRARY_PATH vs LIBRARY_PATH - Stack Overflow

When linking libraries with gcc or g++, the LIBRARY_PATH environment variable is read 

とのこと。(でもログ見ると ld なんだよなぁ。今回のは、LD_LIBRARY_PATH じゃないらしい。この辺はイマイチ分からない。)

see documentとして記載されてる、gccのマニュアルも同様のことが書かれています。 Environment Variables (Using the GNU Compiler Collection (GCC))

The value of LIBRARY_PATH is a colon-separated list of directories, much like PATH. 
When configured as a native compiler, GCC tries the directories thus specified 
when searching for special linker files, if it cannot find them using GCC_EXEC_PREFIX. 
Linking using GCC also uses these directories when searching for ordinary libraries 
for the -l option (but directories specified with -L come first).

そういえば

ググってみると、 --with-ldflags やら --with-opt-dir やらの話も出てきて、以下の対応入れるやつですが 今回はopenssl@3を入れてLDFLAGSあたりを設定してるから?か対応不要でした。(よく分からん)

$ bundle config --global build.mysql2 "--with-opt-dir=$(brew --prefix openssl)"

See Also

macOS Sonoma 14.1.2にrubyをinstallする - rochefort's blog