2001/01/18    libdl on MacOS X

g77 が、多少の難があるとはいえ、実用上は問題なさそうなので、いよいよ大物 CERNLIB に挑戦。tcl/tk をコンパイルしたときに --enalble-shared にしたのにもかかわらず共有ライブラリーができなかったので怪しんではいたのだが、これは dlopen、dlsym、dlclose などの関数を提供する libdl がサポートされていなかったのが原因。CERNLIB では(あまり使われていないとはいえ)Paw の中でコマンドラインから入力した FORTRAN プログラムを on-the-fly でロードして実行することができるが、そのためには、モジュールの dynamic loading は必要。また、次に挑戦すべき ROOT ではこれができないとほとんど使いものにならない。そこでまず、libdl を用意し、それから、CERNLIB を build することに。
libdl に関しては、実は、標準開発環境ではインストールされないとはいえ、cctools-6-1 に dlopen.c および dlfcn.h のソースが含まれることが判明。これを使わせてもらうことにした。cctools のコンパイルには、Libstreams と Libc、また、CERNLIB が cuserid() を要求するので Libcompat もついでに入れておく。
 

[1] Libcompat

コンパイルは、
$ export RC_ARCHS=ppc
$ export RC_CFLAGS='-arch ppc'
$ export RC_OS='Darwin'
$ export SRCROOT=`pwd`
$ export TARGETS=ppc
$ export HOSTS=ppc
$ export MAKEFILEPATH=/Developer/Makefiles
程度の環境変数を設定しておけば、手でもできるが、せっかくの GUI なので ProjectBuilderWO を使ってやった。使い方はほとんど説明をするまでもなく、make のターゲットを指定し、build ボタンを押すだけである。
# tar -zxvf Libcomapt-14-1-bin.tar.gz -C /
で、/usr/locall/lib/system 以下に libcompat.a を入れておく。
 

[2] Libstreams

これも同様。
# tar -zxvf Libstreams-21-1-bin.tar.gz -C /
で、./System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders/ 以下に streams/*.h を、また、/usr/locall/lib/system 以下に libstreams.a を入れておく。
 

[3] Csu

crt0.o(C startup utility)がないと ilbc のコンパイルがこけたので、これも ProjectBuilderWO で作って、
# tar -zxvf Csu-35-bin.tar.gz -C /
で入れておく。ただし、この際、cctools に含まれる indr が必要だったのでちょっと手間取った。
 

[4] Libc

Libc-149/sys.subproj/ppc.subproj/processor_facilities.h を /System/Library/Frameworks/System.framework/Headers/architecture/ppc/ 以下においておく。
# tar -zxvf Libc-149-bin.tar.gz -C /
で、/usr/local/lib/system/libc.a もインストールされるが、実は libc の内容は、/System/Library/Frameworks/System.framework/Versions/Current/System に含まれており、これが自動的にリンクされるようである。
 

[5] dlopen in cctools

libdl の build は
$ cctools-6-1/libdyld/
$ make dlopen.o
$ libtool -static -o libdl.a dlopen.o
てな感じ。
# tar -zxvf  libdl-cctools-6-1-bin.tar.gz -C /
で、/usr/local/include/ に dlfcn.h が、また、/usr/local/lib/system/ に libdl.a と libdyld.a がインストールされる。

一応、非常に簡単ではあるが、テストプログラムを作ってテストしておく。

$ cat main.c
#include <dlfcn.h>
#include <stdio.h>
int main() {
        void *handle;
        void (*hw)(void);
        void (*hh)(void);

        printf("Loading \"libhello.dylib\" .....\n");
        handle = dlopen("/Users/fujiik/sandbox/mypkg/src/libdl/test/libhello.dylib",RTLD_LAZY);

        hw = dlsym(handle,"_helloworld");
        (*hw)();
        hh = dlsym(handle,"_hellohoge");
        (*hh)();

        dlclose(handle);

        return 0;
}

$ cat hw.c
#include <stdio.h>
void helloworld() {
        printf("Hello World\n");
}
$ cat hh.c
#include <stdio.h>
void hellohoge() {
        printf("Hello Hoge\n");
}

$ cat Makefile
CC              = cc
CFLAGS          = -O2 -fPIC
DYLIBFLAGS      = -bundle -undefined suppress
LDFLAGS         = -L/usr/local/lib/system -ldl -ldyld

PROGRAM         = hello
DYLIBNAME       = libhello.dylib
DYLIBOBJS       = hh.o hw.o

all: $(PROGRAM)

$(DYLIBNAME): $(DYLIBOBJS)
        $(CC) $(DYLIBFLAGS) -o $@ $(DYLIBOBJS)

$(PROGRAM): main.c $(DYLIBNAME)
        $(CC) main.c -o $@ $(LDFLAGS)

clean:
        $(RM) *.o *.dylib *~ $(PROGRAM)

$ make
cc -O2 -fPIC -c -o hh.o hh.c
cc -O2 -fPIC -c -o hw.o hw.c
cc -bundle -undefined suppress -o libhello.dylib hh.o hw.o
cc main.c -o hello -L/usr/local/lib/system -ldl -ldyld
$ ./hello
Loading "libhello.dylib" .....
Hello World
Hello Hoge

と、一応動いているようである。Daynamically Loadable Module を作るには -bundle を使うこと。
 
 

今までにコンパイルしたもののソースおよびパッチは macosx/src に、またバイナリーの tar ball は macosx/tgz または macosx/darwin.tgz にそれぞれ置いてある。いつものように使う場合は自己責任で。
 


Back to Keisuke Fujii's MkLinux/LinuxPPC Life