blurhash v0.1.2 コンパイルエラー調査

2019/05/06

何が起こったか

Mastodon v2.8.1において、特定の環境でgem install blurhashに失敗する不具合が発生した。この問題はv2.8.2で修正されている。

https://mstdn.jp/@yi0713/102008223252331858

CentOS勢、masterに追加された blurhash というgemのインストールでコケると思います。原因は gcc が 4.8.5 と古いためのようです

https://mastodon.social/@Mastodon/102044104623035256

Some people have reported problems installing Mastodon v2.8.1 due to gem compilation.
This and a few other small bugs have been fixed in #Mastodon v2.8.2

不具合の再現

$ cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC)
$ gem install blurhash -v 0.1.2
Building native extensions.  This could take a while...
ERROR:  Error installing blurhash:
        ERROR: Failed to build gem native extension.

    /usr/bin/ruby extconf.rb
creating Makefile

make "DESTDIR="
gcc -I. -I/usr/include -I/usr/include/ruby/backward -I/usr/include -I.   -fPIC -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -mtune=generic -fPIC -m64 -o encode.o -c encode.c
encode.c: In function 'blurHashForPixels':
encode.c:28:2: error: 'for' loop initial declarations are only allowed in C99 mode
  for(int y = 0; y < yComponents; y++) {
  ^
encode.c:28:2: note: use option -std=c99 or -std=gnu99 to compile your code
encode.c:29:3: error: 'for' loop initial declarations are only allowed in C99 mode
   for(int x = 0; x < xComponents; x++) {
   ^
encode.c:48:3: error: 'for' loop initial declarations are only allowed in C99 mode
   for(int i = 0; i < acCount * 3; i++) {
   ^
encode.c:62:2: error: 'for' loop initial declarations are only allowed in C99 mode
  for(int i = 0; i < acCount; i++) {
  ^
encode.c: In function 'multiplyBasisFunction':
encode.c:75:2: error: 'for' loop initial declarations are only allowed in C99 mode
  for(int y = 0; y < height; y++) {
  ^
encode.c:76:3: error: 'for' loop initial declarations are only allowed in C99 mode
   for(int x = 0; x < width; x++) {
   ^
encode.c: In function 'encode_int':
encode.c:129:2: error: 'for' loop initial declarations are only allowed in C99 mode
  for(int i = 0; i < length - 1; i++) divisor *= 83;
  ^
encode.c:131:10: error: redefinition of 'i'
  for(int i = 0; i < length; i++) {
          ^
encode.c:129:10: note: previous definition of 'i' was here
  for(int i = 0; i < length - 1; i++) divisor *= 83;
          ^
encode.c:131:2: error: 'for' loop initial declarations are only allowed in C99 mode
  for(int i = 0; i < length; i++) {
  ^
make: *** [encode.o] Error 1


Gem files will remain installed in /usr/local/share/gems/gems/blurhash-0.1.2 for inspection.
Results logged to /usr/local/share/gems/gems/blurhash-0.1.2/ext/blurhash/gem_make.out

原因

再現時のエラーにある通り、for文内でint iと宣言しているため。これはC99から導入された仕様であり、コンパイル時に-std=c99を指定する必要がある。

Mastodon v2.8.2ではblurhashをv0.1.2からv0.1.3に上げる対応1を、blurhash v0.1.3ではコンパイル時に$CFLAGS += ' -std=c99 -lm'を指定する対応2を行っている。

問題の背景

今回の問題はCentOS 7で発生し、Ubuntu 16.04では発生しなかった。これはパッケージ管理システムでインストールするgccのバージョンに差があるためである。

CentOS 7では4.8.5 20150623 (Red Hat 4.8.5-36)、Ubuntuでは5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.10)がインストールされる。

gcc 5系からstd optionのデフォルトがgnu11に変更された。これはc11を拡張したものであり、c11はc99より新しいため上記の仕様を含む。よって-std=c99を指定する必要がなくなる。

https://www.gnu.org/software/gcc/gcc-5/changes.html

The default mode for C is now -std=gnu11 instead of -std=gnu89.

余談

cflagsはgem install実行時に指定可能。

$ gem install blurhash -v 0.1.2 -- --with-cflags="-std=c99"
Building native extensions with: '--with-cflags=-std=c99'
This could take a while...
Successfully installed blurhash-0.1.2
Parsing documentation for blurhash-0.1.2
Installing ri documentation for blurhash-0.1.2
1 gem installed

  1. Bump blurhash from 0.1.2 to 0.1.3 by Gargron · Pull Request #10700 · tootsuite/mastodon
  2. Fix compile flags · Gargron/blurhash@97b8b37