Raspberry Pi 3 上の CentOS 7 で cURL をビルドする。

スポンサーリンク

はじめに

 cURL は対応するプロトコルの多いデータ転送を行えるツール。
 例えば Web サーバーの設定時に正しく設定したプロトコルでデータ転送を行っているかヘッダを見たりするなんて言う場面で結構使える。
 別に野良ビルドせずとも cURL の導入は Raspberry Pi 3 用 CentOS 7 でもパッケージの提供はされている。

curl.armv7hl : A utility for getting files from remote servers (FTP, HTTP, and others)
libcurl.armv7hl : A library for getting files from web servers
libcurl-devel.armv7hl : Files needed for building applications with libcurl

ビルドする理由

 他のパッケージをビルドするときに依存するパッケージ解消としてのみ cURL を使用する場合なら yum で一発とした方が楽でいいだろう。
 しかし検証時に使いたいという場合には少しばかり機能不足かなと感じる部分がある。

/bin/curl --version
curl 7.29.0 (armv7hl-redhat-linux-gnu) libcurl/7.29.0 NSS/3.28.4 zlib/1.2.7 libidn/1.28 libssh2/1.4.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smtp smtps telnet tftp 
Features: AsynchDNS GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz unix-sockets 

 この様にプロトコルとしては十分に多く対応は出来ているが HTTP/2 への対応が出来ていなかったりそろそろ大々的になってくるかもしれな TLS 1.3 への対応も出来ていない。

/bin/curl -s -v --http2 https://bucci.bp7.org/ > /dev/null
curl: option --http2: is unknown
curl: try 'curl --help' or 'curl --manual' for more information
/bin/curl -s -v --tlsv1.3 https://bucci.bp7.org/ > /dev/null
curl: option --tlsv1.3: is unknown
curl: try 'curl --help' or 'curl --manual' for more information

 HTTP/2 と TLS 1.3 を使えるようにしたいと思ったのでビルドをする。

cURL のビルドまでの道のり

 先ずは cURL のビルドに必要な依存するライブラリ類をビルドしていく事から始まる。正直面倒臭いけど依存するライブラリをポイっと yum でドーン出来る程パッケージは用意されていないので仕方が無い。
 各自作業パスや prefix、ld.so.conf.d 以下に置くライブラリパス通知用のファイル名などは任意で調整すること。
 CentOS 自体は USB 接続した SSD 上で動作しているので microSD カード上で動作させるよりも I/O 周りが速くなっている。各ソフトウェアのビルド参考時間を記載しているがそれを踏まえて参考になればと。

OpenSSL のビルド

 かなり広範囲に影響力のあるソフトウェア。SSL/TLS といった暗号経路を確保するために使われたりその他証明書関連の暗号化処理も出来たりする。
 今回は複数のソフトウェアから使われるので折角だからメンテナンス期間の長い最新の安定版として Version 1.1.1 を用いる。TLS 1.3 もこのバージョンからの対応となっている。

cd ~/src
curl -LO https://www.openssl.org/source/openssl-1.1.1.tar.gz
tar xzvf openssl-1.1.1.tar.gz
cd openssl-1.1.1 
./config --prefix=/usr/local/openssl shared zlib enable-tls1_3
make -j4
sudo make install
sudo sh -c "echo /usr/local/openssl/lib >> /etc/ld.so.conf.d/lib.conf"
sudo ldconfig

 ビルドが完了してインストールも終えた後には OpenSSL の共有ライブラリが存在するパスをライブラリパスに通して上げる。

ビルドに掛かる参考時間
make -j4 1082.92s user 76.09s system 393% cpu 4:54.31 total

nghttp2 のビルド

 これは cURL に HTTP/2 をサポートさせるために必要なソフトウェアになる。
 先にビルドしておいた OpenSSL のライブラリを使用する。

cd ~/src
git clone https://github.com/nghttp2/nghttp2.git
cd nghttp2
git submodule update --init
autoreconf -i
automake
autoconf
./configure OPENSSL_CFLAGS="-I/usr/local/openssl/include" OPENSSL_LIBS="-L/usr/local/openssl/lib -lssl -lcrypto" --enable-asio-lib
make -j4
sudo make install
ビルドに掛かる参考時間
make -j4 752.45s user 28.14s system 350% cpu 3:42.91 total

libssh2 のビルド

 cURL で scp や sftp をサポートさせるために必要になる。

cd ~/src
git clone https://github.com/libssh2/libssh2.git
cd libssh2
./buildconf 
./configure --with-crypto=openssl --with-libssl-prefix=/usr/local/openssl
make -j4
sudo make install
ビルドに掛かる参考時間
make -j4 130.16s user 9.18s system 359% cpu 38.713 total

libmetalink のビルド

 Metalink 対応をさせる為に必要。
 依存するライブラリに libxml2 があるが、yum にパッケージがあったのでそちらで対応。

sudo yum install libxml2 libxml2-devel
cd ~/src
git clone https://github.com/metalink-dev/libmetalink.git
./buildconf
./configure
make -j4
sudo make install
ビルドに掛かる参考時間
make -j4 15.94s user 1.90s system 289% cpu 6.157 total

libidn2 のビルド

 国際化ドメイン名のエンコードとデコードに必要となるのでビルドする。
 依存するライブラリに libunistring と libiconv があるが、パッケージが無いので合わせてビルドを行う。

cd ~/src
curl -LO https://ftp.gnu.org/gnu/libunistring/libunistring-0.9.10.tar.gz
tar xzvf libunistring-0.9.10.tar.gz
./configure --prefix=/usr/local
make -j4
sudo make install
ビルドに掛かる参考時間
make -j4 615.34s user 84.29s system 219% cpu 5:18.68 total
cd ~/src
curl -LO https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.15.tar.gz
tar xzvf libiconv-1.15.tar.gz
cd libiconv-1.15
./configure --prefix=/usr/local --with-libunistring-prefix=/usr/local --with-libintl-prefix=/usr
make -j4 
sudo make install
ビルドに掛かる参考時間
make -j4 65.89s user 3.53s system 114% cpu 1:00.79 total

 libidn2 は make 終了時にエラーと表示があったが、make check をすると正常に動作していたのでそのまま導入した。

cd ~/src
curl -LO https://ftp.gnu.org/gnu/libidn/libidn2-2.0.5.tar.gz
tar xzvf libidn2-2.0.5.tar.gz
cd libidn2-2.0.5
./configure --prefix=/usr/local --with-libiconv-prefix=/usr/local --with-libunistring-prefix=/usr/local
time make -j4
make check
sudo make install
ビルドに掛かる参考時間
make -j4 62.69s user 4.69s system 247% cpu 27.227 total

libbrotli のビルド

 Google の Brotli 形式の圧縮フォーマットに対応させたかったのでビルドをする。

cd ~/src
git clone https://github.com/bagder/libbrotli.git
cd libbrotli
./autogen.sh
./configure --prefix=/usr/local
make -j4
sudo make install
ビルドに掛かる参考時間
make -j4 219.18s user 5.17s system 309% cpu 1:12.51 total

cURL のビルドを行う

 依存する物や付け加えたい機能のライブラリ類のパッケージを入れたりビルドしたりで結構時間がかかったが、ここに来てやっと本体のビルドに取りかかる。

cd ~/src
git clone https://github.com/curl/curl.git
cd curl
./buildconf
LDFLAGS="-Wl,-rpath -Wl,/usr/local/curl/lib" ./configure --prefix=/usr/local/curl --with-nghttp2=/usr/local --with-libidn2=/usr/local --with-gssapi --with-ssl=/usr/local/openssl --enable-ipv6 --enable-unix-sockets --with-libssh2=/usr/local --with-libmetalink=/usr/local --with-brotli=/usr/local
make -j4
sudo make install
sudo ln -s /usr/local/curl/bin/curl /usr/local/bin
2018/10/11 追記内容
 何を設定せずとも rpath が設定されていたので、良く分からないうちに設定されるよりも明示的にした方が良いかなと思ったので configure 前に LDFLAG にて rpath としてインストール先ディレクトリ以下の lib を明記した。
ビルドに掛かる参考時間
make -j4 301.63s user 22.99s system 318% cpu 1:42.07 total

 Raspberry Pi 3 上でビルドをした場合、ここまでで動作をした。

/usr/local/bin/curl --version
curl 7.62.0-DEV (armv7l-unknown-linux-gnueabihf) libcurl/7.62.0-DEV OpenSSL/1.1.1 zlib/1.2.7 brotli/1.0.1 libidn2/2.0.5 libssh2/1.8.1_DEV nghttp2/1.35.0-DEV
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp 
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz brotli TLS-SRP HTTP2 UnixSockets HTTPS-proxy Metalink 

残る疑問

 他の x86_64 なアーキテクチャの CentOS 7 ならこの後 /etc/ld.so.conf に /usr/local/curl/lib などと追加して ldconfig をしないとライブラリパスが通らずに curl を実行してもエラーが出た。
 しかし今回、筆者の場合だと Raspberry Pi 3 上でビルドした curl には rpath として /usr/local/curl/lib が入っており、別段ライブラリパスを通さずとも上記の様にエラーも無く実行が出来た。

objdump -p /usr/local/bin/curl

/usr/local/bin/curl:     ファイル形式 elf32-littlearm

(snip...

動的セクション:
  NEEDED               libcurl.so.4
  NEEDED               libmetalink.so.3
  NEEDED               libexpat.so.1
  NEEDED               libnghttp2.so.14
  NEEDED               libidn2.so.0
  NEEDED               libunistring.so.2
  NEEDED               libiconv.so.2
  NEEDED               libssh2.so.1
  NEEDED               libssl.so.1.1
  NEEDED               libcrypto.so.1.1
  NEEDED               libgssapi_krb5.so.2
  NEEDED               libkrb5.so.3
  NEEDED               libk5crypto.so.3
  NEEDED               libcom_err.so.2
  NEEDED               libbrotlidec.so.0
  NEEDED               libz.so.1
  NEEDED               libpthread.so.0
  NEEDED               libc.so.6
  NEEDED               libgcc_s.so.1
  RPATH                /usr/local/curl/lib

(snip...

 ビルド方法によっては yum コマンドが使っている pycurl.so が /usr/local/curl/lib/libcurl.so を見に行ってエラーを吐く場合もあるので、そう言った場合には環境を良く見なおさなければならない。

 具体的に Raspberry Pi 3 上でビルドした curl に rpath があって x86_64 環境の方には何故無いのかという原因はちょっと知識不足で良く分かっていない。そう言う物なのだろうと言う事で深く考えるのは取り敢えず止めておくことに。

 2018/10/11 追記
 どこで設定されたのかと追うのもあれだったから LDFLAGS=”-Wl,-rpath -Wl,/usr/local/curl/lib” と rpath の設定を明示させた。
 configure の prefix に合わせて変更するという手間があるけど、こちらの方が安心かなと思う。

動作確認

 やりたかったことをテストする。
 次の様に curl を用いて HTTP/2 (h2) と TLS 1.3 を同時に指定した当サイトへの接続を試みる。

curl -s -v --http2 --tlsv1.3 https://bucci.bp7.org/ > /dev/null
(snip...
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=bucci.bp7.org
*  start date: Oct  4 19:00:27 2018 GMT
*  expire date: Jan  2 19:00:27 2019 GMT
*  subjectAltName: host "bucci.bp7.org" matched cert's "bucci.bp7.org"
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
(snip...

 そしてもう一つ Brotli を用いた圧縮に対応しているよと教えて上げるとサーバー側も適切に使ってくれた。

curl -I -H "Accept-Encoding:br,gzip,deflate" --http2 --tlsv1.3 https://bucci.bp7.org/
HTTP/2 200 
server: nginx
date: Wed, 10 Oct 2018 06:01:42 GMT
content-type: text/html; charset=UTF-8
vary: Accept-Encoding
x-powered-by: PHP/7.2.10
strict-transport-security: max-age=15768000; preload
x-cache: HIT
x-country: JP
content-encoding: br

おわりに

 そんなわけで一通りというか分からないが、昨今のトレンドに合った cURL をビルドして動作させることが出来た。
 x86_64 アーキの CentOS 7 ならパッケージも豊富だからここまでの苦労はしないので、やはりパッケージが少ない armv7l アーキ版は色々と面倒だし Raspberry Pi 3 の性能も良いわけでは無いから時間も掛かってしまう。
 特にライブラリ類の依存でトライアルアンドエラーを繰り返す時はただの苦痛でしかなかった。
 結果として満足行く物が得られたのでよかったし、多少の勉強にもなったから楽しかった。
 これを機に x86_64 なサーバーとその検証環境両方を本記事と同じ機能を持つようにビルドし直して〆とした。
 以後は Nginx の動作変更を行った後の確認作業で頻繁に活躍してくれるかなと思われる。

スポンサーリンク