事象
M1 Mac 上の Docker で MeCab 含む DockerFile のビルドを行なってきたところ configure: error: cannot guess build type; you must specify one
と怒られてしまった。
configure: error: cannot guess build type; you must specify one
解決策
configure さんが aarch64
なにそれ?おいしいの?っていってるから、 arm
さんだよ〜。って教えてあげる
## --build=arm を追加する ("--build=arm" だけではその後の mecab-python3 の python setup.py install でコケた(後述))
# ./configure --enable-utf8-only --with-charset=utf8 --build=arm
# アーキテクチャを指定する
./configure --enable-utf8-only --with-charset=utf8 --build=arm-unknown-linux-gnu --host=arm-unknown-linux-gnu --target=arm-unknown-linux-gnu
AppleSilicon や ARM 版 Windows が普及してくると開発メンバで複数のアーキテクチャが混在する状況も増えてくると思う。
少なくともベストプラクティスではないと思っているが、 aarch64
とそれ以外 ( amd64
) に対応した、 Dockerfile の一例を載せておく。
FROM python:3.9.5-alpine3.13
ARG _ARM_ARCH="arm-unknown-linux-gnu"
RUN apk add --update bash git curl swig gfortran openssl perl
RUN apk add gcc g++ build-base linux-headers
RUN git clone --depth 1 https://github.com/taku910/mecab.git \
&& cd ./mecab/mecab \
&& if [ `uname -m` = "aarch64" ]; then \
./configure --enable-utf8-only --with-charset=utf8 --build=${_ARM_ARCH} --host=${_ARM_ARCH} --target=${_ARM_ARCH}; \
else \
./configure --enable-utf8-only --with-charset=utf8; \
fi \
&& make \
&& make install
...
長くなるので、全体は GitHub で公開します。
setup.py がコケる原因について
--build=arm
で MeCab のビルドが通って安心していたが、 pip install mecab-python3
でビルドエラーが発生した。
g++ -pthread -shared build/temp.linux-aarch64-3.9/src/MeCab/MeCab_wrap.o -L/usr/local/lib -lmecab -lstdc++ -o build/lib.linux-aarch64-3.9/MeCab/_MeCab.cpython-39-aarch64-linux-gnu.so
/usr/bin/ld: /usr/local/lib/libmecab.a(char_property.o): relocation R_AARCH64_ADR_PREL_PG_HI21 against symbol `_ZSt4cerr@@GLIBCXX_3.4' which may bind externally can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: /usr/local/lib/libmecab.a(char_property.o)(.text+0x3b0): unresolvable R_AARCH64_ADR_PREL_PG_HI21 relocation against symbol `_ZSt4cerr@@GLIBCXX_3.4'
/usr/bin/ld: final link failed: Bad value
mecab-python3 側のコードを確認したが、原因となりそうな箇所は見当たらなかったので、 mecab 本体のビルドオプションにアタリをつけて調査。
結果、動かせたわけだが、正直、何が作用して動いたのかはわからない(爆)
恐らく、 "arm" と指定するだけでは古い ARM 用のファイルが吐かれて、それをリンクしようとしてエラーになったものと推測される。
詳しく書くと、動的リンクを行う際には、メモリアドレスのオフセットを行う。 (「ぼた餅は上から5番目の棚にあるよ」と指定するところを、「ぼた餅は上から3番目の棚の2つ下の棚にあるよ」と相対的に指定するイメージ。棚ぼたを期待して間違った棚を手をかけると後ろに死神が立っていることになるのだが、この話は別の記事でします。)
これを実現する仕組みを GOT (Global Offset Table) と呼ぶ。
x86/x64 では GOT のサイズ制限が無制限らしい(らしい)が、 単に "arm" と指定された場合、 GOT の制限に引っかかるタイプの ELF が吐き出されるんだと思う(適当)
recompile with -fPIC
エラー内で -fPIC
を指定しろと言っているように --build
--host
--target
のいずれかに arm-unknown-linux-gnu
が指定されたことで、 新しめの ARM に対応した ELF が吐かれたか -fPIC
オプションが適用されたかのいずれかの理由でうまく動いたんだと思う。
さいごに
arm64
と amd64
見分けづらいよね。