GLib2のインストールに失敗した話

Mac OS X 10.11.6, GCC 6.3.0, GLib 2.52.1

ご存知のようにGLibとpkg-configは相互依存している。願わくば、次に生まれる時には基盤となるようなツールやライブラリーに、相互依存関係というものが存在しない世の中に生まれたい。

結論から言えば、どちらも存在しない状態からpkg-configを入れたいのであれば、以下のように --with-internal-glib オプションを付ければ良い。

# Install pkg-config.
# https://www.freedesktop.org/wiki/Software/pkg-config/
$ cd $MY_PROJECT_ROOT/download
$ wget https://pkg-config.freedesktop.org/releases/pkg-config-0.29.2.tar.gz
$ tar xf pkg-config-0.29.2.tar.gz
$ cd pkg-config-0.29.2
$ mkdir work
$ cd work
$ ../configure --prefix=$MY_PROJECT_ROOT --with-internal-glib
$ make -j8
$ make install

では例えば、pkg-configをインストールせずに、GLibだけインストールしたいとしたらどうするか。

結果負けたけど、途中までは以下の手順で行けていた。

# Install libffi. (that is necessary to build GLib2)
# https://sourceware.org/libffi/
$ cd $MY_PROJECT_ROOT/download
$ wget ftp://sourceware.org/pub/libffi/libffi-3.2.1.tar.gz
$ tar xf libffi-3.2.1.tar.gz
$ mkdir work
$ cd work
$ ../configure --prefix=$MY_PROJECT_ROOT
$ make -j8
$ make install

# Install PCRE - Perl Compatible Regular Expressions. (that is necessary to build GLib2)
# http://www.pcre.org
$ cd $MY_PROJECT_ROOT/download
$ wget https://ftp.pcre.org/pub/pcre/pcre-8.40.tar.gz
$ tar xf pcre-8.40.tar.gz
$ cd pcre-8.40
$ mkdir work
$ cd work
$ ../configure --prefix=$MY_PROJECT_ROOT
$ make -j8
$ make install

# Install gettext. (that is necessary to build GLib2)
# http://www.gnu.org/software/gettext/
$ cd $MY_PROJECT_ROOT/download
$ wget https://ftp.gnu.org/pub/gnu/gettext/gettext-0.19.8.1.tar.xz
$ tar xf gettext-0.19.8.1.tar.xz
$ cd gettext-0.19.8.1
$ mkdir work
$ cd work
$ ../configure --prefix=$MY_PROJECT_ROOT
$ make -j8
$ make install
$ gettext --version
gettext (GNU gettext-runtime) 0.19.8.1

# Install GLib2. (that is necessary to build pkg-config)
# https://developer.gnome.org/glib/
$ cd $MY_PROJECT_ROOT/download
$ wget http://ftp.gnome.org/pub/gnome/sources/glib/2.52/glib-2.52.1.tar.xz
$ tar xf glib-2.52.1.tar.xz
$ cd glib-2.52.1
$ mkdir work
$ cd work
$ LIBFFI_CFLAGS=-I$MY_PROJECT_ROOT/lib/libffi-3.2.1/include LIBFFI_LIBS="-L$MY_PROJECT_ROOT/lib -lffi" PCRE_CFLAGS=-I$MY_PROJECT_ROOT/include PCRE_LIBS="-L$MY_PROJECT_ROOT/lib -lpcre" ../configure --prefix=$MY_PROJECT_ROOT --with-pcre=internal
$ make -j8

# Compile error.

オープンソースソフトウェアを使うなら、当然Cのソースくらい読めないとね。

さて、問題。

gdummymyfile.c内の下記unescape_string関数がコンパイルエラーになるわけだが、これがなぜだか分かるだろうか?

static char*
unescape_string (const gchar *escaped_string,
         const gchar *escaped_string_end,
         const gchar *illegal_characters)
{
  const gchar *in;
  gchar *out, *result;
  gint character;
  
  if (escaped_string == NULL)
    return NULL;

  if (escaped_string_end == NULL)
    escaped_string_end = escaped_string + strlen (escaped_string);
  
  result = g_malloc (escaped_string_end - escaped_string + 1); 
    
  out = result;
  for (in = escaped_string; in < escaped_string_end; in++) 
    {   
      character = *in;
      if (*in == '%') 
        {   
          in++;
          if (escaped_string_end - in < 2)
        {   
          g_free (result);
          return NULL;
        }   
    
          character = unescape_character (in);
    
          /* Check for an illegal character. We consider '\0' illegal here. */
          if (character <= 0 ||
          (illegal_characters != NULL &&
           strchr (illegal_characters, (char)character) != NULL))
        {   
          g_free (result);
          return NULL;
        }   
          in++; /* The other char will be eaten in the loop header */
        }   
      *out++ = (char)character;
    }   
  
  *out = '\0';
  g_warn_if_fail (out - result <= strlen (escaped_string));
  return result;
}

まあ、どう見ても間違えてないよね。

こちらの方の記事に問題の原因と解決方法が示されていた。
http://d-alchemy.xyz/tips/qemu_on_snow_leopard.html

要するに、.cファイルなのに無理矢理Objective-Cとしてコンパイルさせようとしているのが問題というわけだ。

実際、上記の問題の関数を抽出し、一部修正してtest.cとしてgccコンパイルしたらコンパイルできた。全く同じ内容で、test.mとしてgccコンパイルするとエラーになった。


え? でもObjective-CってCのスーパーセットだよね?


そう、そんなことは本来あってはならない。

ということで、Xcode 7.2で同じことをしてみた。
結果、test.cもtest.mもコンパイルできた。

どゆこと?

どうやら問題は、変数inをforループ内で使った時に、Xcodeはきちんと構文を解釈できる。GCCはfor〜in文として見てしまうのでエラーになってしまう。ということらしい。


【問題を局所化した検証コード】
test.m

#include <stdio.h>
#include <string.h>

void func()
{
    const char* psz = "Lorem ipsum dolor sit amet";
    const char* in;
	
    /* for の in = のところでコンパイルエラー */
    for (in = psz + strlen(psz); in >= psz; -- in) {
        printf("%c", *in);
    }
}

int main()
{
    func();
    return 0;
}

なぁんだかねぇ…


この件は誰が悪いの?

  • inなんていう汎用的な語句を予約語にしたObjective-Cが悪い
  • Cocoaが内部のコアなところでObjective-Cなんて使ってるのが悪い
  • .cファイルをObjective-Cコンパイルさせんのやめえや
  • Objective-Cが絡むプロジェクトで変数名 in を使うな? いやいや
  • GCCちゃんってそんなのも構文解析できないの? プークスクス
  • そもそもGLibとpkg-configの相互依存やめろしいややめてくださいお願いします


私が言いたいのは、「時間を返せ」、ということだけだ。