From d6f2f55b46ceddd986e7ba42fb8269aef0ca8e77 Mon Sep 17 00:00:00 2001 From: Daniel Bovensiepen Date: Fri, 21 Sep 2012 19:56:28 +0800 Subject: Add Support for Ruby Extensions, C Extensions and Test Integration --- mrbgems/Makefile | 28 +++--- mrbgems/g/clib_example/Makefile | 12 +++ mrbgems/g/clib_example/README.md | 4 + mrbgems/g/clib_example/src/clib_example.c | 17 ++++ mrbgems/g/clib_example/test/clib_example.rb | 3 + mrbgems/g/hello_world/Makefile | 12 --- mrbgems/g/hello_world/README.md | 4 - mrbgems/g/hello_world/src/hello_world.c | 17 ---- mrbgems/g/hello_world/test/hello_world.rb | 3 - mrbgems/g/mrblib_example/Makefile | 7 ++ mrbgems/g/mrblib_example/README.md | 4 + mrbgems/g/mrblib_example/mrblib/mrblib_example.rb | 5 + mrbgems/g/mrblib_example/test/mrblib_example.rb | 3 + mrbgems/gem_helper.c | 108 +++++++++++++++++++--- 14 files changed, 166 insertions(+), 61 deletions(-) create mode 100644 mrbgems/g/clib_example/Makefile create mode 100644 mrbgems/g/clib_example/README.md create mode 100644 mrbgems/g/clib_example/src/clib_example.c create mode 100644 mrbgems/g/clib_example/test/clib_example.rb delete mode 100644 mrbgems/g/hello_world/Makefile delete mode 100644 mrbgems/g/hello_world/README.md delete mode 100644 mrbgems/g/hello_world/src/hello_world.c delete mode 100644 mrbgems/g/hello_world/test/hello_world.rb create mode 100644 mrbgems/g/mrblib_example/Makefile create mode 100644 mrbgems/g/mrblib_example/README.md create mode 100644 mrbgems/g/mrblib_example/mrblib/mrblib_example.rb create mode 100644 mrbgems/g/mrblib_example/test/mrblib_example.rb diff --git a/mrbgems/Makefile b/mrbgems/Makefile index 0f2908ab9..1cb5b8a83 100644 --- a/mrbgems/Makefile +++ b/mrbgems/Makefile @@ -17,29 +17,31 @@ export AR = ar .PHONY : all all : $(INIT).o all_gems -$(MMAKER_BIN) : $(MMAKER).o - @echo "Build the generator which creates the driver and Gem Makefile" - $(LL) -o $@ $(CC_FLAGS) $< +all_gems : g/Makefile + @echo "Build all gems" + $(MAKE) -C g -$(MMAKER).o : $(MMAKER).c - $(CC) $(CC_FLAGS) -MMD -c $< -o $@ +g/Makefile : $(MMAKER_BIN) + @echo "Generate Gem Makefile" + $(MMAKER_BIN) makefile > $@ $(INIT).c : $(MMAKER_BIN) @echo "Generate Gem driver" $(MMAKER_BIN) $(INIT) > $@ $(INIT).o : $(INIT).c - @echo "Build the driver which initiailizes all gems" - gcc $(CC_FLAGS) -c $< -o $@ + @echo "Build the driver which initializes all gems" + $(CC) $(CC_FLAGS) -MMD -c $< -o $@ $(AR) rs $(LIBR) $@ -g/Makefile : - @echo "Generate Gem Makefile" - $(MMAKER_BIN) makefile > $@ +# Generator -all_gems : $(MMAKER_BIN) g/Makefile - @echo "Build all gems" - $(MAKE) -C g +$(MMAKER_BIN) : $(MMAKER).o + @echo "Build the generator which creates the driver and Gem Makefile" + $(LL) -o $@ $(CC_FLAGS) $< + +$(MMAKER).o : $(MMAKER).c + $(CC) $(CC_FLAGS) -MMD -c $< -o $@ test : @$(MAKE) test -C g diff --git a/mrbgems/g/clib_example/Makefile b/mrbgems/g/clib_example/Makefile new file mode 100644 index 000000000..2cd523905 --- /dev/null +++ b/mrbgems/g/clib_example/Makefile @@ -0,0 +1,12 @@ +include ../../Makefile4gem + +GEM := clib_example + +GEM_C_FILES := $(wildcard $(SRC_DIR)/*.c) +GEM_OBJECTS := $(patsubst %.c, %.o, $(GEM_C_FILES)) + +gem-all : $(GEM_OBJECTS) + $(AR) rs $(LIBR) $< + +gem-clean : + -$(RM) $(GEM_OBJECTS) diff --git a/mrbgems/g/clib_example/README.md b/mrbgems/g/clib_example/README.md new file mode 100644 index 000000000..289f6635d --- /dev/null +++ b/mrbgems/g/clib_example/README.md @@ -0,0 +1,4 @@ +CLib Extension Example +========= + +This is an example gem which implements a C extension. diff --git a/mrbgems/g/clib_example/src/clib_example.c b/mrbgems/g/clib_example/src/clib_example.c new file mode 100644 index 000000000..2ab8682b2 --- /dev/null +++ b/mrbgems/g/clib_example/src/clib_example.c @@ -0,0 +1,17 @@ +#include +#include + +static struct RClass *_class_clib; + +static mrb_value +mrb_clib_example(mrb_state *mrb, mrb_value self) +{ + puts("A C Extension"); + return self; +} + +void +mrb_clib_example_gem_init(mrb_state* mrb) { + _class_clib = mrb_define_module(mrb, "CLib"); + mrb_define_class_method(mrb, _class_clib, "clib_method", mrb_clib_example, ARGS_NONE()); +} diff --git a/mrbgems/g/clib_example/test/clib_example.rb b/mrbgems/g/clib_example/test/clib_example.rb new file mode 100644 index 000000000..348b9271d --- /dev/null +++ b/mrbgems/g/clib_example/test/clib_example.rb @@ -0,0 +1,3 @@ +assert('CLib Extension') do + CLib.respond_to? :clib_method +end diff --git a/mrbgems/g/hello_world/Makefile b/mrbgems/g/hello_world/Makefile deleted file mode 100644 index c03910bf6..000000000 --- a/mrbgems/g/hello_world/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../../Makefile4gem - -GEM := hello_world - -GEM_C_FILES := $(wildcard $(SRC_DIR)/*.c) -GEM_OBJECTS := $(patsubst %.c, %.o, $(GEM_C_FILES)) - -gem-all : $(GEM_OBJECTS) - $(AR) rs $(LIBR) $< - -gem-clean : - -$(RM) $(GEM_OBJECTS) diff --git a/mrbgems/g/hello_world/README.md b/mrbgems/g/hello_world/README.md deleted file mode 100644 index 42792567f..000000000 --- a/mrbgems/g/hello_world/README.md +++ /dev/null @@ -1,4 +0,0 @@ -hello world -========= - -This is an example gem which implements just one method +HW.say+ in a C extension. diff --git a/mrbgems/g/hello_world/src/hello_world.c b/mrbgems/g/hello_world/src/hello_world.c deleted file mode 100644 index 75d353542..000000000 --- a/mrbgems/g/hello_world/src/hello_world.c +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include - -static struct RClass *_class_hw; - -static mrb_value -mrb_hello_world(mrb_state *mrb, mrb_value self) -{ - puts("Hello World"); - return self; -} - -void -mrb_hello_world_gem_init(mrb_state* mrb) { - _class_hw = mrb_define_module(mrb, "HW"); - mrb_define_class_method(mrb, _class_hw, "say", mrb_hello_world, ARGS_NONE()); -} diff --git a/mrbgems/g/hello_world/test/hello_world.rb b/mrbgems/g/hello_world/test/hello_world.rb deleted file mode 100644 index 2d8c335db..000000000 --- a/mrbgems/g/hello_world/test/hello_world.rb +++ /dev/null @@ -1,3 +0,0 @@ -assert('Hello World') do - HW.respond_to? :say -end diff --git a/mrbgems/g/mrblib_example/Makefile b/mrbgems/g/mrblib_example/Makefile new file mode 100644 index 000000000..a43677842 --- /dev/null +++ b/mrbgems/g/mrblib_example/Makefile @@ -0,0 +1,7 @@ +include ../../Makefile4gem + +GEM := mrblib_example + +gem-all : + +gem-clean : diff --git a/mrbgems/g/mrblib_example/README.md b/mrbgems/g/mrblib_example/README.md new file mode 100644 index 000000000..42792567f --- /dev/null +++ b/mrbgems/g/mrblib_example/README.md @@ -0,0 +1,4 @@ +hello world +========= + +This is an example gem which implements just one method +HW.say+ in a C extension. diff --git a/mrbgems/g/mrblib_example/mrblib/mrblib_example.rb b/mrbgems/g/mrblib_example/mrblib/mrblib_example.rb new file mode 100644 index 000000000..444f32236 --- /dev/null +++ b/mrbgems/g/mrblib_example/mrblib/mrblib_example.rb @@ -0,0 +1,5 @@ +class MRBLib + def MRBLib.mrblib_method + puts "A Ruby Extension" + end +end diff --git a/mrbgems/g/mrblib_example/test/mrblib_example.rb b/mrbgems/g/mrblib_example/test/mrblib_example.rb new file mode 100644 index 000000000..40189ffdd --- /dev/null +++ b/mrbgems/g/mrblib_example/test/mrblib_example.rb @@ -0,0 +1,3 @@ +assert('MRBLib extension') do + MRBLib.respond_to? :mrblib_method +end diff --git a/mrbgems/gem_helper.c b/mrbgems/gem_helper.c index dd19ea2d0..24b959df9 100644 --- a/mrbgems/gem_helper.c +++ b/mrbgems/gem_helper.c @@ -1,22 +1,61 @@ #include #include #include +#include +#include #include - +#include + static int one (const struct dirent *unused) { return 1; } +/* + * Does a directory exist? + * yes => TRUE + * no => FALSE + * fs error => FALSE + * + */ +static int +directory_exists(char path[4096]) { + DIR* dir = opendir(path); + if (dir) + return TRUE; + else + return FALSE; +} + +/* + * Template generator for each GEM + * + * Arguments: + * before: + * String before each GEM template + * after: + * String after each GEM template + * start: + * String at the start of the template + * end: + * String at the end of the template + * skip_if_src_not_exist: + * TRUE => skip template for GEMs with SRC directory + * FALSE => template for all GEMs + * + */ void -dir_list (char before[1024], char after[1024], char start[1024], char end[1024]) +for_each_gem (char before[1024], char after[1024], + char start[1024], char end[1024], + char dir_to_skip[1024]) { struct dirent **eps; int n; char gemname[1024] = ""; char gemname_path[4096] = ""; char complete_line[4096] = ""; + char src_path[4096] = ""; struct stat attribut; strcat(complete_line, start); @@ -28,6 +67,8 @@ dir_list (char before[1024], char after[1024], char start[1024], char end[1024]) strcpy(gemname, eps[cnt]->d_name); strcpy(gemname_path, "./g/"); strcat(gemname_path, gemname); + strcpy(src_path, gemname_path); + strcat(src_path, "/src"); if (strcmp(gemname, ".") == 0) continue; @@ -35,13 +76,22 @@ dir_list (char before[1024], char after[1024], char start[1024], char end[1024]) continue; stat(gemname_path, &attribut); - if (S_ISDIR(attribut.st_mode) == 0) + if (S_ISDIR(attribut.st_mode) == 0) { continue; + } + + if (strcmp(dir_to_skip, "") != 0) { + strcpy(src_path, gemname_path); + strcat(src_path, "/"); + strcat(src_path, dir_to_skip); + + if (directory_exists(src_path) != TRUE) + continue; + } strcat(complete_line, before); strcat(complete_line, gemname); strcat(complete_line, after); - } } else { @@ -65,8 +115,28 @@ make_gem_makefile() puts(""); puts(".PHONY : all"); - puts("all :"); - dir_list("\t@$(MAKE) -C ", " $(MAKE_FLAGS)\n", "", ""); + puts("all : all_gems mrblib_gem.o"); + puts("\t$(AR) rs ../../lib/libmruby.a mrblib_gem.o"); + puts(""); + + puts("all_gems :"); + for_each_gem("\t@$(MAKE) -C ", " $(MAKE_FLAGS)\n", "", "", ""); + puts(""); + + puts("mrblib_gem.o : mrblib_gem.c"); + puts(""); + + puts("mrblib_gem.c : mrblib_gem.ctmp"); + puts("\tcat $< > $@"); + puts(""); + + puts("mrblib_gem.ctmp : mrblib_gem.rbtmp"); + puts("\t../../bin/mrbc -Bmrblib_gem_irep -o$@ $<"); + puts(""); + + puts("mrblib_gem.rbtmp :"); + for_each_gem(" ", "/mrblib/*.rb", "\tcat", "> mrblib_gem.rbtmp", "mrblib"); + puts(""); puts(".PHONY : test"); puts("test : mrbtest"); @@ -93,13 +163,13 @@ make_gem_makefile() puts(""); puts("mrbtest.rbtmp :"); - dir_list("", "/test/*.rb ", "\tcat ../../test/assert.rb ", "> mrbtest.rbtmp"); + for_each_gem("", "/test/*.rb ", "\tcat ../../test/assert.rb ", "> mrbtest.rbtmp", ""); puts(""); puts(".PHONY : clean"); puts("clean :"); puts("\t$(RM) *.c *.d *.rbtmp *.ctmp *.o mrbtest"); - dir_list("\t@$(MAKE) clean -C ", " $(MAKE_FLAGS)\n", "", ""); + for_each_gem("\t@$(MAKE) clean -C ", " $(MAKE_FLAGS)\n", "", "", ""); } void @@ -117,14 +187,28 @@ make_init_gems() puts(""); puts("#include \"mruby.h\""); + puts("#include \"mruby/irep.h\""); + puts("#include \"mruby/dump.h\""); + puts("#include \"mruby/string.h\""); + puts("#include \"mruby/proc.h\""); puts(""); - dir_list("void mrb_", "_gem_init(mrb_state*);\n", "", ""); + for_each_gem("void mrb_", "_gem_init(mrb_state*);\n", "", "", "src"); + + puts("extern const char mrblib_gem_irep[];"); + puts(""); puts("void"); - puts("mrb_init_mrbgems(mrb_state *mrb)"); - puts("{"); - dir_list(" mrb_", "_gem_init(mrb);\n", "", ""); + puts("mrb_init_mrbgems(mrb_state *mrb) {"); + + for_each_gem(" mrb_", "_gem_init(mrb);\n", "", "", "src"); + + puts(" int n = mrb_read_irep(mrb, mrblib_gem_irep);"); + puts(" mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_top_self(mrb));"); + puts(" if (mrb->exc) {"); + puts(" mrb_p(mrb, mrb_obj_value(mrb->exc));"); + puts(" exit(0);"); + puts(" }"); puts("}"); } -- cgit v1.2.3