Mae向きなブログ

Mae向きな日記のブログ版。ようやくこちらに移行してきました。

Interactive Programming in Cの簡易化

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