diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2012-12-07 01:04:32 -0800 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2012-12-07 01:04:32 -0800 |
| commit | f521738953b9297a4d26e68ec42b7e9a22e5b442 (patch) | |
| tree | c54451f210ebea9233229cc29ad82311e554ff63 /mrbgems | |
| parent | bd3b95cae66bf68a757a0dcdf05bcb05eb177391 (diff) | |
| parent | bef73cc54f044e16caf6bc1ba16ed0bf779c5ade (diff) | |
| download | mruby-f521738953b9297a4d26e68ec42b7e9a22e5b442.tar.gz mruby-f521738953b9297a4d26e68ec42b7e9a22e5b442.zip | |
Merge pull request #479 from bovi/mrbgems
mrbgems
Diffstat (limited to 'mrbgems')
| -rw-r--r-- | mrbgems/GEMS.active | 0 | ||||
| -rw-r--r-- | mrbgems/Makefile | 76 | ||||
| -rw-r--r-- | mrbgems/Makefile4gem | 91 | ||||
| -rw-r--r-- | mrbgems/g/.gitignore | 1 | ||||
| -rw-r--r-- | mrbgems/generator.c | 420 |
5 files changed, 588 insertions, 0 deletions
diff --git a/mrbgems/GEMS.active b/mrbgems/GEMS.active new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/mrbgems/GEMS.active diff --git a/mrbgems/Makefile b/mrbgems/Makefile new file mode 100644 index 000000000..c7d1f577d --- /dev/null +++ b/mrbgems/Makefile @@ -0,0 +1,76 @@ +# makefile description. +# add gems to the ruby library + +ifeq ($(strip $(MRUBY_ROOT)),) + MRUBY_ROOT := $(realpath ..) +endif + +LIBR := ../lib/libmruby.a +RM_F := rm -f +CC_FLAGS := -Wall -Werror-implicit-function-declaration -g -O3 -MMD -I. -I./../include + +export CC = gcc +export LL = gcc +export AR = ar + +GENERATOR := $(MRUBY_ROOT)/mrbgems/generator +ifeq ($(OS),Windows_NT) + GENERATOR_BIN := $(GENERATOR).exe +else + GENERATOR_BIN := $(GENERATOR) +endif +GEM_INIT := gem_init +GEM_MAKEFILE := g/Makefile +GEM_MAKEFILE_LIST := g/MakefileGemList +GEMDLIB := g/mrbgemtest.ctmp + +ifeq ($(strip $(ACTIVE_GEMS)),) + # the default file which contains the active GEMs + ACTIVE_GEMS = GEMS.active +endif + +############################## +# generic build targets, rules + +.PHONY : all +all : all_gems $(GEM_INIT).a + +$(GEM_INIT).a : $(GEM_INIT).o + $(AR) rs gem_init.a $(GEM_INIT).o + +all_gems : $(GENERATOR_BIN) + @echo "Generate Gem List Makefile" + $(GENERATOR_BIN) makefile_list "$(ACTIVE_GEMS)" > $(GEM_MAKEFILE_LIST) + @echo "Generate Gem Makefile" + $(GENERATOR_BIN) makefile "$(ACTIVE_GEMS)" > $(GEM_MAKEFILE) + @echo "Build all gems" + $(MAKE) -C g MRUBY_ROOT='$(MRUBY_ROOT)' ACTIVE_GEMS="$(ACTIVE_GEMS)" + +$(GEM_INIT).c : $(GENERATOR_BIN) + @echo "Generate Gem driver" + $(GENERATOR_BIN) $(GEM_INIT) "$(ACTIVE_GEMS)" > $@ + +$(GEM_INIT).o : $(GEM_INIT).c + @echo "Build the driver which initializes all gems" + $(CC) $(CC_FLAGS) -MMD -c $< -o $@ + +# Generator + +$(GENERATOR_BIN) : $(GENERATOR).o + @echo "Build the generator which creates the driver and Gem Makefile" + $(LL) -o $@ $(CC_FLAGS) $< + +$(GENERATOR).o : $(GENERATOR).c + $(CC) $(CC_FLAGS) -MMD -c $< -o $@ + +.PHONY : prepare-test +prepare-test : + @$(MAKE) prepare-test -C g ACTIVE_GEMS="$(ACTIVE_GEMS)" MRUBY_ROOT='$(MRUBY_ROOT)' + +# clean driver and all gems +.PHONY : clean +clean : $(GENERATOR_BIN) + @echo "Cleanup Gems" + $(GENERATOR_BIN) makefile "$(ACTIVE_GEMS)" > $(GEM_MAKEFILE) + $(MAKE) clean -C g ACTIVE_GEMS="$(ACTIVE_GEMS)" MRUBY_ROOT='$(MRUBY_ROOT)' + -$(RM_F) $(GEM_INIT).c *.o *.d $(GENERATOR_BIN) $(GEM_MAKEFILE) $(GEM_MAKEFILE_LIST) gem_init.a diff --git a/mrbgems/Makefile4gem b/mrbgems/Makefile4gem new file mode 100644 index 000000000..763210659 --- /dev/null +++ b/mrbgems/Makefile4gem @@ -0,0 +1,91 @@ +# This is the default Makefile integrated +# by each Gem. It integrates important constants +# for usage inside of a Gem. + +ifeq ($(strip $(MRUBY_ROOT)),) + # mruby src root + MRUBY_ROOT := $(realpath ../../..) +endif + +# Tools +CC := gcc +RM := rm -f +AR := ar + +SRC_DIR := src +MRB_DIR := mrblib + +INCLUDES := -I$(SRC_DIR) -I$(MRUBY_ROOT)/include -I$(MRUBY_ROOT)/src -I. +CFLAGS := $(INCLUDES) -O3 -g -Wall -Werror-implicit-function-declaration + +# LIBR can be manipulated with command line arguments +ifeq ($(strip $(LIBR)),) + # default mruby library + LIBR := $(MRUBY_ROOT)/lib/libmruby.a +endif + +GEM_PACKAGE := mrb-$(GEM)-gem.a + +ifeq ($(strip $(ACTIVE_GEMS)),) + # the default file which contains the active GEMs + ACTIVE_GEMS = GEMS.active +endif + +# Default rules which are calling the +# gem specific gem-all and gem-clean +# implementations of a gem + +.PHONY : all +all : gem-info gem-all + +gem-info: + @echo "Building Gem '$(GEM)'" + +# Building target for C and Ruby files +gem-c-and-rb-files : gem_mixlib.o + $(AR) rs $(GEM_PACKAGE) $(GEM_OBJECTS) $^ + +gem_mixlib.c : gem_mrblib_header.ctmp gem_mrblib_irep.ctmp gem_mixlib_init.ctmp + cat $^ > $@ + +gem_mixlib_init.ctmp : + $(MRUBY_ROOT)/mrbgems/generator gem_mixlib $(GEM) "$(ACTIVE_GEMS)" > $@ + +# Building target for C files +gem-c-files : gem_srclib.o + $(AR) rs $(GEM_PACKAGE) $(GEM_OBJECTS) $< + +gem_srclib.c : + $(MRUBY_ROOT)/mrbgems/generator gem_srclib $(GEM) "$(ACTIVE_GEMS)" > $@ + +# Building target for Ruby Files +gem-rb-files : gem_mrblib.o + $(AR) rs $(GEM_PACKAGE) $< + +gem_mrblib.c : gem_mrblib_header.ctmp gem_mrblib_irep.ctmp gem_mrblib_init.ctmp + cat $^ > $@ + +gem_mrblib_header.ctmp : + $(MRUBY_ROOT)/mrbgems/generator gem_mrblib "$(ACTIVE_GEMS)" > $@ + +gem_mrblib_init.ctmp : + $(MRUBY_ROOT)/mrbgems/generator gem_mrblib $(GEM) "$(ACTIVE_GEMS)" > $@ + +gem_mrblib_irep.ctmp : gem_mrblib.rbtmp + $(MRUBY_ROOT)/bin/mrbc -Bgem_mrblib_irep_$(GEM) -o$@ $< + +gem_mrblib.rbtmp : + cat $(GEM_RB_FILES) > $@ + +gem-clean-c-and-rb-files : + -$(RM) $(GEM_PACKAGE) gem_mixlib.o gem_mixlib.c gem_mrblib_header.ctmp gem_mrblib_irep.ctmp gem_mixlib_init.ctmp gem_mrblib.rbtmp + +gem-clean-c-files : + -$(RM) $(GEM_PACKAGE) gem_srclib.c gem_srclib.o $(GEM_OBJECTS) + +gem-clean-rb-files : + -$(RM) $(GEM_PACKAGE) gem_mrblib.o gem_mrblib.c gem_mrblib_header.ctmp gem_mrblib_init.ctmp gem_mrblib_irep.ctmp gem_mrblib.rbtmp + +.PHONY : clean +clean : gem-clean + @echo "Gem '$(GEM)' is clean" diff --git a/mrbgems/g/.gitignore b/mrbgems/g/.gitignore new file mode 100644 index 000000000..f935021a8 --- /dev/null +++ b/mrbgems/g/.gitignore @@ -0,0 +1 @@ +!.gitignore diff --git a/mrbgems/generator.c b/mrbgems/generator.c new file mode 100644 index 000000000..dcc9b5e34 --- /dev/null +++ b/mrbgems/generator.c @@ -0,0 +1,420 @@ +/* +** generator.c - Generator for mrbgems +** +** See Copyright Notice in mruby.h +*/ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <mrbconf.h> + +/* + * Get the file name part of *path* + * + * Arguments: + * path: + * String which represents the path + * + */ +static char +*get_file_name(char *path) +{ + char *base = strrchr(path, '/'); + return base ? base+1 : path; +} + +/* + * Search in *s* for *old* and replace with *new*. + * + * Arguments: + * s: + * String in which the the replacement will be done + * old: + * String which will be replaced + * new: + * String which will be the replacement + * + */ +static char +*replace(const char *s, const char *old, const char *new) +{ + char *ret; + int i, count = 0; + size_t newlen = strlen(new); + size_t oldlen = strlen(old); + + for (i = 0; s[i] != '\0'; i++) { + if (strstr(&s[i], old) == &s[i]) { + count++; + i += oldlen - 1; + } + } + + ret = malloc(i + count * (newlen - oldlen)); + if (ret == NULL) + exit(EXIT_FAILURE); + + i = 0; + while (*s) { + if (strstr(s, old) == s) { + strcpy(&ret[i], new); + i += newlen; + s += oldlen; + } + else + ret[i++] = *s++; + } + ret[i] = '\0'; + + return ret; +} + +/* + * Template generator for each active 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 + * full_path + * Should the full path of the GEM be used? + * + */ +static char* +for_each_gem (char before[1024], char after[1024], + char start[1024], char end[1024], + int full_path, char active_gems[1024]) +{ + /* active GEM check */ + FILE *active_gem_file; + char gem_char; + char gem_name[1024] = { 0 }; + int char_index; + char gem_list[1024][1024] = { { 0 }, { 0 } }; + int gem_index; + int i; + + /* return value */ + char* complete_line = malloc(4096 + sizeof(char)); + strcpy(complete_line, ""); + strcat(complete_line, start); + + /* Read out the active GEMs */ + active_gem_file = fopen(active_gems, "r+"); + if (active_gem_file != NULL) { + char_index = 0; + gem_index = 0; + while((gem_char = fgetc(active_gem_file)) != EOF) { + if (gem_char == '\n') { + /* Every line contains one active GEM */ + gem_name[char_index++] = '\0'; + strcpy(gem_list[gem_index++], gem_name); + + gem_name[0] = '\0'; + char_index = 0; + } + else + gem_name[char_index++] = gem_char; + } + + fclose(active_gem_file); + } + else { /* Error: Active GEM list couldn't be loaded */ } + + for(i = 0; i < gem_index; i++) { + strcat(complete_line, before); + if (full_path == TRUE) + strcat(complete_line, gem_list[i]); + else + strcat(complete_line, get_file_name(gem_list[i])); + strcat(complete_line, replace(after, "#GEMNAME#", get_file_name(gem_list[i]))); + } + + strcat(complete_line, end); + return complete_line; +} + +/* + * Gem Makefile Generator + * + * Global Makefile which starts the build process + * for every active GEM. + * + */ +static void +make_gem_makefile(char active_gems[1024]) +{ + char *gem_check = { 0 }; + int gem_empty; + + printf("ifeq ($(strip $(MRUBY_ROOT)),)\n" + " MRUBY_ROOT := $(realpath ../../..)\n" + "endif\n\n" + "MAKEFILE_4_GEM := $(MRUBY_ROOT)/mrbgems/Makefile4gem\n\n" + "CFLAGS := -I. -I$(MRUBY_ROOT)/include -I$(MRUBY_ROOT)/src\n\n" + "ifeq ($(OS),Windows_NT)\n" + " MAKE_FLAGS = --no-print-directory CC=$(CC) LL=$(LL) ALL_CFLAGS='$(ALL_CFLAGS)' MRUBY_ROOT='$(MRUBY_ROOT)' MAKEFILE_4_GEM='$(MAKEFILE_4_GEM)'\n" + "else\n" + " MAKE_FLAGS = --no-print-directory CC='$(CC)' LL='$(LL)' ALL_CFLAGS='$(ALL_CFLAGS)' MRUBY_ROOT='$(MRUBY_ROOT)' MAKEFILE_4_GEM='$(MAKEFILE_4_GEM)'\n" + "endif\n\n"); + + /* is there any GEM available? */ + gem_check = for_each_gem("", "", "", "", TRUE, active_gems); + if (strcmp(gem_check, "") == 0) + gem_empty = TRUE; + else + gem_empty = FALSE; + + /* Makefile Rules to build every single GEM */ + + printf(".PHONY : all\n"); + if (gem_empty) + printf("all :\n\n"); + else { + printf("all : all_gems\n\n"); + + /* Call make for every GEM */ + printf("all_gems :\n%s\n", + for_each_gem("\t@$(MAKE) -C ", " $(MAKE_FLAGS)\n", "", "", TRUE, active_gems) + ); + printf("\n"); + } + + /* Makefile Rules to Test GEMs */ + + printf(".PHONY : prepare-test\n" + "prepare-test :\n" + ); + if (!gem_empty) + printf("%s", + for_each_gem(" ", "/test/*.rb ", "\tcat", " > mrbgemtest.rbtmp", TRUE, active_gems) + ); + else + printf("\t$(MRUBY_ROOT)/mrbgems/generator rbtmp \"%s\"> mrbgemtest.rbtmp", active_gems); + + printf("\n\t$(MRUBY_ROOT)/bin/mrbc -Bmrbgemtest_irep -omrbgemtest.ctmp mrbgemtest.rbtmp\n\n"); + + /* Makefile Rules to Clean GEMs */ + + printf(".PHONY : clean\n" + "clean :\n" + "\t$(RM) *.c *.d *.rbtmp *.ctmp *.o mrbtest\n"); + if (!gem_empty) + printf("%s", + for_each_gem("\t@$(MAKE) clean -C ", " $(MAKE_FLAGS)\n", "", "", TRUE, active_gems) + ); +} + +/* + * Gem Makefile List Generator + * + * Creates a Makefile which will be included by other Makefiles + * which need to know which GEMs are active. + * + */ +static void +make_gem_makefile_list(char active_gems[1024]) +{ + printf("%s", + for_each_gem(" ", "/mrb-#GEMNAME#-gem.a", "GEM_LIST := ", "\n", TRUE, active_gems) + ); + + printf("GEM_ARCHIVE_FILES := $(MRUBY_ROOT)/mrbgems/gem_init.a\n" + "GEM_ARCHIVE_FILES += $(GEM_LIST)\n\n"); +} + +/* + * gem_init.c Generator + * + */ +static void +make_gem_init(char active_gems[1024]) +{ + printf("/*\n" + " * This file contains a list of all\n" + " * initializing methods which are\n" + " * necessary to bootstrap all gems.\n" + " *\n" + " * IMPORTANT:\n" + " * This file was generated!\n" + " * All manual changes will get lost.\n" + " */\n\n" + "#include \"mruby.h\"\n"); + + /* Protoype definition of all initialization methods */ + printf("\n%s", + for_each_gem("void GENERATED_TMP_mrb_", "_gem_init(mrb_state*);\n", "", "", FALSE, active_gems) + ); + printf("\n"); + + /* mrb_init_mrbgems(mrb) method for initialization of all GEMs */ + printf("void\n" + "mrb_init_mrbgems(mrb_state *mrb) {\n"); + printf( "%s", + for_each_gem(" GENERATED_TMP_mrb_", "_gem_init(mrb);\n", "", "", FALSE, active_gems) + ); + printf("}"); +} + +/* + * Empty Generator + * + * Generates a clean file with one new line. + * + */ +static void +make_rbtmp(char active_gems[1024]) +{ + printf("\n"); +} + +/* + * Header Generator + * + * Head of the C Code for loading the GEMs into the interpreter. + * + */ +static void +make_gem_mrblib_header(char active_gems[1024]) +{ + printf("/*\n" + " * This file is loading the irep\n" + " * Ruby GEM code.\n" + " *\n" + " * IMPORTANT:\n" + " * This file was generated!\n" + " * All manual changes will get lost.\n" + " */\n\n" + "#include \"mruby.h\"\n" + "#include \"mruby/irep.h\"\n" + "#include \"mruby/dump.h\"\n" + "#include \"mruby/string.h\"\n" + "#include \"mruby/proc.h\"\n\n"); +} + +/* + * mrblib Generator + * + * Generates the C Code for loading + * the pure Ruby GEMs into the interpreter. + * + */ +static void +make_gem_mrblib(char argv[1024], char active_gems[1024]) +{ + printf("\n" + "void\n" + "GENERATED_TMP_mrb_%s_gem_init(mrb_state *mrb) {\n" + " mrb_load_irep(mrb, gem_mrblib_irep_%s);\n" + " if (mrb->exc) {\n" + " mrb_p(mrb, mrb_obj_value(mrb->exc));\n" + " exit(0);\n" + " }\n" + "}", argv, argv); +} + +/* + * srclib Generator + * + * Generates the C Code for loading + * the pure C GEMs into the interpreter. + * + */ +static void +make_gem_srclib(char argv[1024], char active_gems[1024]) +{ + printf("/*\n" + " * This file is loading the irep\n" + " * Ruby GEM code.\n" + " *\n" + " * IMPORTANT:\n" + " * This file was generated!\n" + " * All manual changes will get lost.\n" + " */\n\n" + "#include \"mruby.h\"\n"); + + printf("\n" + "void mrb_%s_gem_init(mrb_state*);\n", argv); + + printf("\n" + "void\n" + "GENERATED_TMP_mrb_%s_gem_init(mrb_state *mrb) {\n" + " mrb_%s_gem_init(mrb);\n" + "}", argv, argv); +} + +/* + * mixlib Generator + * + * Generates the C Code for loading + * the mixed Ruby and C GEMs + * into the interpreter. + * + */ +static void +make_gem_mixlib(char argv[1024], char active_gems[1024]) +{ + printf("\n" + "void mrb_%s_gem_init(mrb_state*);\n", argv); + + printf("\n" + "void\n" + "GENERATED_TMP_mrb_%s_gem_init(mrb_state *mrb) {\n" + " mrb_%s_gem_init(mrb);\n" + " mrb_load_irep(mrb, gem_mrblib_irep_%s);\n" + " if (mrb->exc) {\n" + " mrb_p(mrb, mrb_obj_value(mrb->exc));\n" + " exit(0);\n" + " }\n" + "}", argv, argv, argv); +} + +/* + * Start the generator and decide what to generate. + * + */ +int +main (int argc, char *argv[]) +{ + const char * argument_info = "Wrong argument! Options: 'makefile', 'gem_init', 'rbtmp', 'gem_mrblib', gem_srclib\n"; + if (argc == 3) { + if (strcmp(argv[1], "makefile") == 0) + make_gem_makefile(argv[2]); + else if (strcmp(argv[1], "makefile_list") == 0) + make_gem_makefile_list(argv[2]); + else if (strcmp(argv[1], "gem_init") == 0) + make_gem_init(argv[2]); + else if (strcmp(argv[1], "rbtmp") == 0) + make_rbtmp(argv[2]); + else if (strcmp(argv[1], "gem_mrblib") == 0) + make_gem_mrblib_header(argv[2]); + else { + printf("%s", argument_info); + return 1; + } + } + else if (argc == 4) { + if (strcmp(argv[1], "gem_mrblib") == 0) + make_gem_mrblib(argv[2], argv[3]); + else if (strcmp(argv[1], "gem_srclib") == 0) + make_gem_srclib(argv[2], argv[3]); + else if (strcmp(argv[1], "gem_mixlib") == 0) + make_gem_mixlib(argv[2], argv[3]); + else { + printf("%s", argument_info); + return 1; + } + } + else { + printf("%s", argument_info); + return 1; + } + + return 0; +} |
