guile-2.0がリリースされたので入れるだけ入れてみた

http://www.gnu.org/software/guile/news.html
去る2月16日に、GNUのGuile version 2.0がリリースされたのでそれのインストールメモというだけです。

http://lwn.net/Articles/428288/

近いうちに、Guile 2.0 Crashやりたいですね。近いうちっていうか本当は今月が良かったのですが今月ってあと一週間そこいらですし来週は色々イベントあるのと仕事で無理ですね。

FFIというよりもCとの双方向の色々がやり易いらしくて、そうすると色々実装どうなってるのかなーというのはかなり気になる所です。

環境

Darwin ranha-macbook.local 10.6.0 Darwin Kernel Version 10.6.0のi386とかそんなんです

gitから引っ張ってくる

http://www.gnu.org/software/guile/download.html#git
えっいきなり ftp://ftp.gnu.org/pub/gnu/guile/ じゃなくてgitリポジトリから取ってくるんですか?というのは、まぁ色々あったからですというか、gitリポジトリから取って来たヤツだと動いたって言うそれだけです。
普通にcloneすれば良いと思います。

autoreconf

gitから取って来たものにはconfigure入っていませんから、

autoreconf -i --verbose

などやって色々生成します。

AM_GNU_GETTEXTが無い、でもgettext-develとかは入れてるという場合は、aclocal --print-ac-dirなど見て、ちゃんとgettext.m4とか見付けられるか調べてあげてください。

configure

今回は特にくくらずに、

configure

とします。configureで失敗する場合は、C_INCLUDE_PATHとかで必要なものちゃんと見付けられているかっていういつものお話です。
それかconfigureデバッグをして切り抜けるかです。

makeすると失敗する

すくなくとも私の環境では、libguile.dylibとかそういうのを生成するタイミングで失敗します。エラー内容は多分

  1. rpl_putenvがundefined
  2. _environがundefined

とかそんな感じになると思います。

rpl_putenvについて

結論から言うと、C_INCLUDE_PATHで/usr/local/includeとか/usr/includeに通してる場合そっちを見に行ってしまうので困るよねとかそんなです多分。
まず1つ目のrpl_putenvですが、これはlib/stdlib.hを見ると740行あたりに

#if 1
# if 1
#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
#   undef putenv
#   define putenv rpl_putenv
#  endif
_GL_FUNCDECL_RPL (putenv, int, (char *string) _GL_ARG_NONNULL ((1)));
_GL_CXXALIAS_RPL (putenv, int, (char *string));
# else
_GL_CXXALIAS_SYS (putenv, int, (char *string));
# endif
_GL_CXXALIASWARN (putenv);
#endif

と書いています。libguile以下ではgcc -I../libなどしているので、libguileでのstdlib includeはlib/stdlib.hを指す事になります。で、configureで何もしなかったので_cplusplusがdefinedではないですから、putenvがrpl_putenvとなってしまうわけです。

いや、でもlib/putenv.cがあってそこで多分上手く動くだろうから大丈夫なのでは?というのは実は残念なことになってしまっていて…例えば次のCプログラム

/* test.c */
#include <stdlib.h> /* stdlib.hはカレントディレクトリに存在するとする */
int main()
{
    return 0;
}

%gcc -E test.c -I. | grep stdlib.h <- gcc -I$(pwd)などとしても意味ない
# 1 "/usr/include/stdlib.h" 1 3
# 61 "/usr/include/stdlib.h" 3
# 62 "/usr/include/stdlib.h" 2 3
# 64 "/usr/include/stdlib.h" 2 3
# 66 "/usr/include/stdlib.h" 2 3
# 68 "/usr/include/stdlib.h" 2 3
# 81 "/usr/include/stdlib.h" 3
# 134 "/usr/include/stdlib.h" 3
# 144 "/usr/include/stdlib.h" 3
# 256 "/usr/include/stdlib.h" 2 3

これがlibディレクトリ以下で起こってしまうので、lib/putenv.c自体はシステムのstdlib.hを見に行ってしまってrpl_putenvが定義されなくなるとかそんなのです。

どう解消するのかというのはまぁ好きにしてくださいって感じだと思うのですが、putenv.cで

/* #include <stdlib.h> /* こっちをコメントアウト */
#include "stdlib.h"

とすれば「取りあえず」動くのでそれで良いと思います。

_environについて

これも結論を言うと、Darwin ldにあるundefinedオプションでdynamic_lookup付けて動的にシンボル解決するようにしろという話です。
_environはcrt1.oでdefinedだというので問題無いと思うのですが、普通このcrt1.oは明示的に渡したりしませんgccが勝手に寄越してくれるので。

まぁつまり

/* env.c */
#include <stdio.h>

void punya(void)
{
    extern char **environ;
    char **strs;
    
    for (strs = environ; *strs != NULL; ++strs)
        printf("%s\n",*strs);
}

/* main.c */
extern void punya(void);

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

% gcc -c env.c main.c
% gcc -v main.o env.o
...
 /usr/local/libexec/gcc/x86_64-apple-darwin10/4.6.0/collect2 -dynamic -arch x86_64 -macosx_version_min 10.6.6 -weak_reference_mismatches non-weak -o a.out -lcrt1.10.5.o -L/usr/local/lib -L/opt/local/lib -L. -L/usr/local/lib/gcc/x86_64-apple-darwin10/4.6.0 -L/usr/local/lib/gcc/x86_64-apple-darwin10/4.6.0/../../.. main.o env.o -lgcc_s.10.5 -lgcc_ext.10.5 -lgcc -no_compact_unwind -lSystem
...

% nm /usr/lib/crt1.10.5.o|grep environ 
00000000000000a0 D _environ

ところがMacでdynamic library(つまりdylib)を作る場合は、作る「タイミング」で全シンボルの解決がされないといけないわけなのですが

% gcc -c -fPIC env.c -o env.o
% gcc -v -dynamiclib env.o -o libpunya.dylib
...
/usr/local/libexec/gcc/x86_64-apple-darwin10/4.6.0/collect2 -dynamic -dylib -arch x86_64 -macosx_version_min 10.6.6 -weak_reference_mismatches non-weak -o libpunya.dylib -ldylib1.10.5.o -L/usr/local/lib -L/opt/local/lib -L. -L/usr/local/lib/gcc/x86_64-apple-darwin10/4.6.0 -L/usr/local/lib/gcc/x86_64-apple-darwin10/4.6.0/../../.. env.o -lgcc_s.10.5 -lgcc_ext.10.5 -lgcc -no_compact_unwind -lSystem
...

Undefined symbols:
  "_environ", referenced from:
      _punya in env.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

とcrt1.o渡ってこずにenvironがシンボル解決出来ないので文句を言われます。どうするねんという話なのですが、Darwin ldにはundefinedオプションというものがあり
http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/ld.1.html

-undefined treatment
                 Specifies how undefined symbols are to be treated. Options are: error, warning, suppress,
                 or dynamic_lookup.  The default is error.
(http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/ld.1.html より抜粋)

従って

% gcc -dynamiclib env.o -o libpunya.dylib -Wl,-undefined,dynamic_lookup
% gcc main.o libpunya.dylib

と出来ます。

で具体的にguileの場合はどこを弄れば良いのかですけど、libtoolで

# Commands used to build a shared archive.
archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring \$single_module~\$DSYMUTIL \$lib || :"

という部分があるので

archive_cmds="\$CC -dynamiclib  -Wl,-undefined,dynamic_lookup \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring \$single_module~\$DSYMUTIL \$lib || :"

とかすると良いと思います。

パッチ貼付けた方が良かったですけど元ファイル残してないのでまぁ御免なさいって感じですね。

多分コレで通る

とかそんな感じです。あとはmake checkするなりmake installするなりなんなりと。
ただ、make checkでは幾つかで転けました。

gnuftpサーバから取って来たguile 2.0ではどうもおかしなエラーが出まくって1日無駄に使ったので避けたとかそんな感じです。