おおくまねこ

職業プログラマーです。興味のある話題を書いています。

Ruby のビルドで 「 invalid application of ‘sizeof’ to incomplete type ‘HMAC_CTX’」エラー

CentOS 7.4 に Ruby 2.6 をインストールしようと思い、
ソースコードからビルドした時に以下のエラーで失敗した。

In file included from /usr/local/include/openssl/bn.h:33:0,
                 from /usr/local/include/openssl/engine.h:23,
                 from openssl_missing.c:14:
openssl_missing.c: 関数 ‘ossl_HMAC_CTX_new’ 内:
openssl_missing.c:65:43: エラー: invalid application of ‘sizeof’ to incomplete type ‘HMAC_CTX’
     HMAC_CTX *ctx = OPENSSL_malloc(sizeof(HMAC_CTX));
                                           ^
openssl_missing.c:68:5: 警告: 関数 ‘HMAC_CTX_init’ の暗黙的な宣言です [-Wimplicit-function-declaration]
     HMAC_CTX_init(ctx);
     ^
openssl_missing.c: 関数 ‘ossl_HMAC_CTX_free’ 内:
openssl_missing.c:78:2: 警告: 関数 ‘HMAC_CTX_cleanup’ の暗黙的な宣言です [-Wimplicit-function-declaration]
  HMAC_CTX_cleanup(ctx);
  ^
openssl_missing.c: 関数 ‘ossl_X509_CRL_get0_signature’ 内:
openssl_missing.c:90:13: エラー: 不完全型のポインタへの間接参照
  *psig = crl->signature;
             ^
openssl_missing.c:92:13: エラー: 不完全型のポインタへの間接参照
  *palg = crl->sig_alg;
             ^
openssl_missing.c: 関数 ‘ossl_X509_REQ_get0_signature’ 内:
openssl_missing.c:102:13: エラー: 不完全型のポインタへの間接参照
  *psig = req->signature;
             ^
openssl_missing.c:104:13: エラー: 不完全型のポインタへの間接参照
  *palg = req->sig_alg;
             ^
openssl_missing.c: トップレベル:
cc1: 警告: 認識できないコマンドラインオプション "-Wno-tautological-compare" です [デフォルトで有効]
cc1: 警告: 認識できないコマンドラインオプション "-Wno-self-assign" です [デフォルトで有効]
cc1: 警告: 認識できないコマンドラインオプション "-Wno-parentheses-equality" です [デフォルトで有効]
cc1: 警告: 認識できないコマンドラインオプション "-Wno-constant-logical-operand" です [デフォルトで有効]
cc1: 警告: 認識できないコマンドラインオプション "-Wno-cast-function-type" です [デフォルトで有効]
make[2]: *** [openssl_missing.o] エラー 1
make[2]: ディレクトリ `/home/fujiwara/ruby-2.6.2/ext/openssl' から出ます
make[1]: *** [ext/openssl/all] エラー 2
make[1]: ディレクトリ `/home/fujiwara/ruby-2.6.2' から出ます

検索してもあまり情報がなさそうだったので、まとめました。

背景

自分のCentOS 7.4サーバーにRemineを入れようと思ったのが始まり。
CentOSRedmine を入れるのは何度かやっていたが、初めて失敗した。

結論

原因は単純にopensslのバージョンがよくなかったことのようです。
openssl のバージョン差によるAPIが違うので、関数や変数を呼び出せなかったようです。

確認すると、今回の環境には 1.0.2 のバージョンが入っていました。

$ rpm -qa |grep openssl
openssl-1.0.2k-16.el7_6.1.x86_64
openssl-libs-1.0.2k-16.el7_6.1.x86_64
openssl-devel-1.0.2k-16.el7_6.1.x86_64

Ruby 2.X は 1.0.1 のライブラリを build 時に import しないといけなかったようです。

環境
対処

openssl-1.0.1 をインストールしてから ruby をビルドすれば成功します。
※すでに openssl-1.0.1 は当時のサポート対象外ですが、必要なので諦めました。
今回の手順では、作業ディレクトリーは ~/work とします。適宜環境にあわせて読み替えて下さい。

  • OpenSSL をダウンロードします。
    サポートからは外れている上に、Donload ページからは辿れなくなっているが、URL は残っていました。
    今回は一番新しいものをダウンロードしました。
$ cd ~/work
$ curl -O http://www.openssl.org/source/openssl-1.0.1u.tar.gz
$ ls -l openssl-1.0.1u.tar.gz
openssl-1.0.1u.tar.gz
  • ビルド、インストールします。
    既存の OpenSSL を上書きしたくなかったので、config 設定時にインストール先を指定しました。
    /home/lib/openssl 配下にインストールするようにしています。
$ sudo mkdir -p /home/lib/openssl
$ tar xzf openssl-1.0.1u.tar.gz
$ cd openssl-1.0.1u
$ ./config --prefix=/home/lib/openssl shared
$ make; sudo make install
  • Ruby のダウンロード
    Rubyソースコードをダウンロードします。
    バージョンは安定板で最新のものを選んだので、お好みで。
$ cd ~/work
$ curl -O https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.2.tar.gz
$ ls -l ruby-2.6.2.tar.gz
ruby-2.6.2.tar.gz
  • Ruby のビルド、インストール
    Ruby のビルドとインストールをします。
    ビルドする時はOpenSSL の場所をオプションで指定します。
$ tar xzf ruby-2.6.2.tar.gz
$ cd ruby-2.6.2
$ ./configure --with-opt-dir=/home/lib/openssl --enable-shared
$ make; sudo make install
  • 確認
    ruby コマンドがインストールされていれば完了。
$ ruby --version
ruby 2.6.2p47 (2019-03-13 revision 67232) [x86_64-linux]

お疲れさまでした。