「Interactive Programming in C « null program」では、実行中のプログラムを止めることなく、読み込んだ共有ライブラリに変更があったとき、ロードし直す方法が、ライフゲームを題材にして説明してあります。実際、やってみましたが、ライフゲームの実行中にプログラムの変更結果が反映されるのでとても興味深いと思いました。ソースも読んでみたのですが、自分の理解を深めるために`Helloもの'を作って確かめてみました。
間違いなどあると思います。コメントなどいただければありがたいです。
hello.h
#include <stdio.h> void hello(void);
hello.c
実行中に、文字列の末尾に'!'を追加していきました。
#include "hello.h" void hello(void) { printf("Hello World\n"); }
main.c
#include <unistd.h> #include <sys/stat.h> #include <dlfcn.h> #include "hello.h" const char *HELLO_LIBRARY = "./libhello.so"; int main(void) { void *handle; void (*func)(void); struct stat attr; ino_t before_id; for(;;){ /* libhello.so の inode番号に変化があったとき */ if ((stat(HELLO_LIBRARY, &attr) == 0) && (before_id != attr.st_ino)) { if (handle) { dlclose(handle); } handle = dlopen(HELLO_LIBRARY, RTLD_NOW); if (handle) { before_id = attr.st_ino; func = dlsym(handle, "hello"); } } func(); usleep(1000000); } dlclose(handle); return 0; }
Makefile
CFLAGS = -std=c99 -pedantic -Wall -O2 -fPIC LDLIBS = -ldl all : hello libhello.so hello : main.c hello.h $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS) libhello.so : hello.c hello.h $(CC) $(CFLAGS) -shared $(LDFLAGS) -o $@ $< $(LDLIBS) test : main libhello.so ./$< clean : $(RM) *.o *.so hello
Guardfile
guard :shell do watch(/(.*).[c|h]/) {|m| `make` } end
実行
makeを実行すると、helloという実行コマンドが出来上がります。ターミナルで、helloを実行させ、別ターミナルでhello.cに変更を加えると、helloの実行中に出力に変化が現れました。今回は、Guardというファイル変更を検出して動作するRuby製のツールも使用しました。
- ターミナル(その1)
$ guard init $ guard
- ターミナル(その2)
$ ./hello Hello World Hello World Hello World Hello World Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!!! Hello World!!! Hello World!!! Hello World!!! Hello World!!!!!! Hello World!!!!!! Hello World!!!!!! ^C