mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Merge pull request #598 from bovi/mrbgems-improve-for-masuidrive
mrbgems - Improvements for masuidrive's mobiruby
This commit is contained in:
+31
-28
@@ -9,13 +9,14 @@ By default mrbgems is currently deactivated. As long as mrbgems is deactivated
|
||||
there is no overhead inside of the mruby interpreter.
|
||||
|
||||
To activate you have to make the following changes:
|
||||
* set *ENABLE_GEMS* to *true* in *$(MRUBY_ROOT)/Makefile*
|
||||
* define *ENABLE_GEMS* in *$(MRUBY_ROOT)/include/mrbconf.h*
|
||||
* set ```ENABLE_GEMS``` to ```true``` in *$(MRUBY_ROOT)/Makefile*
|
||||
* comment out ```DISABLE_GEMS``` in *$(MRUBY_ROOT)/include/mrbconf.h*
|
||||
* activate GEMs in *$(MRUBY_ROOT)/mrbgems/GEMS.active*
|
||||
|
||||
Every activated GEM has to be listed with his absolute path in *GEMS.active*. It
|
||||
is possible to point to an alternative activate file:
|
||||
* set *ACTIVE_GEMS* to your customized GEM list in *$(MRUBY_ROOT)/Makefile*
|
||||
Every activated GEM has to be listed in *GEMS.active*. You have to point to
|
||||
the GEM directory absolute or relative (based on *mrbgems/g*). It is possible
|
||||
to point to an alternative activate file:
|
||||
* set ```ACTIVE_GEMS``` to your customized GEM list in *$(MRUBY_ROOT)/Makefile*
|
||||
|
||||
## GEM Structure
|
||||
|
||||
@@ -23,6 +24,8 @@ The maximal GEM structure looks like this:
|
||||
|
||||
```
|
||||
+- GEM_NAME <- Name of GEM
|
||||
|
|
||||
+- include/ <- Header files for C extension
|
||||
|
|
||||
+- mrblib/ <- Source for Ruby extension
|
||||
|
|
||||
@@ -37,23 +40,23 @@ The maximal GEM structure looks like this:
|
||||
|
||||
The folder *mrblib* contains pure Ruby files to extend mruby. The folder *src*
|
||||
contains C files to extend mruby. The folder *test* contains pure Ruby files
|
||||
for testing purposes which will be used by *mrbtest*. The *Makefile* contains
|
||||
rules to build a *gem.a* file inside of the GEM directory. Which will be used
|
||||
for integration into the normal mruby build process. *README.md* is a short
|
||||
description of your GEM.
|
||||
for testing purposes which will be used by ```mrbtest```. The *Makefile* contains
|
||||
rules to build a *mrb-GEMNAME-gem.a* file inside of the GEM directory. Which
|
||||
will be used for integration into the normal mruby build process. *README.md*
|
||||
is a short description of your GEM.
|
||||
|
||||
## Build process
|
||||
|
||||
mrbgems will call *make* to build and *make clean* to clean your GEM. You
|
||||
mrbgems will call ```make``` to build and *make clean* to clean your GEM. You
|
||||
have to build a *mrb-GEMNAME-gem.a* file during this build process. How you
|
||||
are going to do this is up to you.
|
||||
|
||||
To make your build process more easier and more standardized we suggest
|
||||
to include *mrbgems/Makefile4gem* which defines some helper rules. In
|
||||
case you include this Makefile you have to define specific pre-defined
|
||||
rules like *gem-all* for the build process and *gem-clean* for the clean
|
||||
process. There are additional helper rules for specific GEM examples
|
||||
below.
|
||||
rules like ```gem-all``` for the build process and ```gem-clean``` for
|
||||
the clean process. There are additional helper rules for specific GEM
|
||||
examples below.
|
||||
|
||||
## C Extension
|
||||
|
||||
@@ -61,16 +64,16 @@ mruby can be extended with C. It is possible by using the C API to
|
||||
integrate C libraries into mruby.
|
||||
|
||||
The *Makefile* is used for building a C extension. You should
|
||||
define *GEM* (GEM name), *GEM_C_FILES* (all C files) and
|
||||
*GEM_OBJECTS* (all Object files). Pay also attention that your
|
||||
define ```GEM``` (GEM name), ```GEM_C_FILES``` (all C files) and
|
||||
```GEM_OBJECTS``` (all Object files). Pay also attention that your
|
||||
*Makefile* has to build the object files. You can use
|
||||
*gem-c-files* to build a *mrb-GEMNAME-gem.a* out of your
|
||||
Object code and use *gem-clean-c-files* to clean the object files.
|
||||
```gem-c-files``` to build a *mrb-GEMNAME-gem.a* out of your
|
||||
Object code and use ```gem-clean-c-files``` to clean the object files.
|
||||
|
||||
### Pre-Conditions
|
||||
|
||||
mrbgems expects that you have implemented a C method called
|
||||
*mrb_YOURGEMNAME_gem_init(mrb_state)*. YOURGEMNAME will be replaced
|
||||
```mrb_YOURGEMNAME_gem_init(mrb_state)```. ```YOURGEMNAME``` will be replaced
|
||||
by the name of you GEM. The directory name of your GEM is considered also
|
||||
as the name! If you call your GEM directory *c_extension_example*, your
|
||||
initialisation method could look like this:
|
||||
@@ -111,15 +114,15 @@ classes or add new ones in this way. Put all Ruby files into the *mrblib*
|
||||
folder.
|
||||
|
||||
The *Makefile* is used for building a Ruby extension. You should define
|
||||
*GEM* (GEM name) and *GEM_RB_FILES* (all Ruby files). You can use
|
||||
*gem-rb-files* to build a *mrb-GEMNAME-gem.a* out of your Ruby code and use
|
||||
*gem-clean-rb-files* to clean the generated C files.
|
||||
```GEM``` (GEM name) and *GEM_RB_FILES* (all Ruby files). You can use
|
||||
```gem-rb-files``` to build a *mrb-GEMNAME-gem.a* out of your Ruby code and use
|
||||
```gem-clean-rb-files``` to clean the generated C files.
|
||||
|
||||
### Pre-Conditions
|
||||
|
||||
mrbgems will automatically call the *gem-all* make target of your GEM.
|
||||
mrbgems will automatically call the ```gem-all``` make target of your GEM.
|
||||
|
||||
mrbgems will also use the *gem-clean* make target to clean up your GEM. Implement
|
||||
mrbgems will also use the ```gem-clean``` make target to clean up your GEM. Implement
|
||||
this target with the necessary rules!
|
||||
|
||||
### Example
|
||||
@@ -147,11 +150,11 @@ override existing classes or add new ones in this way. Put all Ruby files
|
||||
into the *mrblib* folder and all C files into the *src* folder.
|
||||
|
||||
The *Makefile* is used for building a C and Ruby extension. You should
|
||||
define *GEM* (GEM name), *GEM_C_FILES* (all C files), *GEM_OBJECTS*
|
||||
(all Object files) and *GEM_RB_FILES* (all Ruby files). You can use
|
||||
*gem-c-and-rb-files* to build a *mrb-GEMNAME-gem.a* out of your Object
|
||||
and Ruby code. Use *gem-clean-c-and-rb-files* to clean the generated
|
||||
C files.
|
||||
define ```GEM``` (GEM name), ```GEM_C_FILES``` (all C files),
|
||||
```GEM_OBJECTS``` (all Object files) and ```GEM_RB_FILES``` (all Ruby
|
||||
files). You can use ```gem-c-and-rb-files``` to build a
|
||||
*mrb-GEMNAME-gem.a* out of your Object and Ruby code. Use
|
||||
```gem-clean-c-and-rb-files``` to clean the generated C files.
|
||||
|
||||
### Pre-Conditions
|
||||
|
||||
|
||||
+2
-2
@@ -42,7 +42,7 @@ 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)
|
||||
$(GENERATOR_BIN) makefile "$(ACTIVE_GEMS)" "$(MRUBY_ROOT)" > $(GEM_MAKEFILE)
|
||||
@echo "Build all gems"
|
||||
$(MAKE) -C g MRUBY_ROOT='$(MRUBY_ROOT)' ACTIVE_GEMS="$(ACTIVE_GEMS)"
|
||||
|
||||
@@ -71,6 +71,6 @@ prepare-test :
|
||||
.PHONY : clean
|
||||
clean : $(GENERATOR_BIN)
|
||||
@echo "Cleanup Gems"
|
||||
$(GENERATOR_BIN) makefile "$(ACTIVE_GEMS)" > $(GEM_MAKEFILE)
|
||||
$(GENERATOR_BIN) makefile "$(ACTIVE_GEMS)" "$(MRUBY_ROOT)" > $(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
|
||||
|
||||
@@ -15,9 +15,6 @@ 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
|
||||
|
||||
+89
-18
@@ -7,6 +7,7 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <mrbconf.h>
|
||||
|
||||
/*
|
||||
@@ -24,6 +25,29 @@ static char
|
||||
return base ? base+1 : path;
|
||||
}
|
||||
|
||||
static char
|
||||
*get_full_path(char *path, char *mruby_root)
|
||||
{
|
||||
char full_path[1024] = { 0 };
|
||||
if (path[0] == '/') {
|
||||
/* An absolute UNIX path starts with a slash */
|
||||
strcpy(full_path, path);
|
||||
}
|
||||
else if (path[1] == ':') {
|
||||
/* An absolute path on WIN32 starts
|
||||
* with a drive like "c://path/to/somewhere"
|
||||
*/
|
||||
strcpy(full_path, path);
|
||||
}
|
||||
else {
|
||||
strcpy(full_path, mruby_root);
|
||||
strcat(full_path, "/mrbgems/g/");
|
||||
strcat(full_path, path);
|
||||
}
|
||||
|
||||
return full_path;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search in *s* for *old* and replace with *new*.
|
||||
*
|
||||
@@ -103,13 +127,20 @@ static char
|
||||
* GEMS.active file location
|
||||
* escape:
|
||||
* Should the gem name be escaped?
|
||||
* check_suffix:
|
||||
* If not empty it will be added to the GEM
|
||||
* path and a check will be performed if this
|
||||
* full path is a directory. Every GEM which
|
||||
* doesn't contain this path will be skipped
|
||||
* in the iteration.
|
||||
*
|
||||
*/
|
||||
static char*
|
||||
for_each_gem (char before[1024], char after[1024],
|
||||
char start[1024], char end[1024],
|
||||
int full_path, char active_gems[1024],
|
||||
int escape)
|
||||
int escape, char check_suffix[1024],
|
||||
char mruby_root[1024])
|
||||
{
|
||||
/* active GEM check */
|
||||
FILE *active_gem_file;
|
||||
@@ -119,6 +150,9 @@ for_each_gem (char before[1024], char after[1024],
|
||||
char gem_list[1024][1024] = { { 0 }, { 0 } };
|
||||
int gem_index;
|
||||
int i;
|
||||
int skip;
|
||||
FILE *check;
|
||||
char check_name[1024] = { 0 };
|
||||
|
||||
/* return value */
|
||||
char* complete_line = malloc(4096 + sizeof(char));
|
||||
@@ -130,6 +164,7 @@ for_each_gem (char before[1024], char after[1024],
|
||||
if (active_gem_file != NULL) {
|
||||
char_index = 0;
|
||||
gem_index = 0;
|
||||
skip = FALSE;
|
||||
while((gem_char = fgetc(active_gem_file)) != EOF) {
|
||||
if (gem_char == '\n') {
|
||||
/* Every line contains one active GEM */
|
||||
@@ -138,7 +173,21 @@ for_each_gem (char before[1024], char after[1024],
|
||||
if (escape == TRUE)
|
||||
strcpy(gem_name, escape_gem_name(gem_name));
|
||||
|
||||
strcpy(gem_list[gem_index++], gem_name);
|
||||
if (strcmp(check_suffix, "") == 0) { /* No suffix passed */ }
|
||||
else {
|
||||
/* Check the path with suffix if it is a directory */
|
||||
|
||||
strcpy(check_name, get_full_path(gem_name, mruby_root));
|
||||
strcat(check_name, check_suffix);
|
||||
check = fopen(check_name, "r+");
|
||||
if (errno == EISDIR)
|
||||
skip = FALSE;
|
||||
else
|
||||
skip = TRUE;
|
||||
}
|
||||
|
||||
if (skip == FALSE)
|
||||
strcpy(gem_list[gem_index++], gem_name);
|
||||
|
||||
gem_name[0] = '\0';
|
||||
char_index = 0;
|
||||
@@ -153,8 +202,12 @@ for_each_gem (char before[1024], char after[1024],
|
||||
|
||||
for(i = 0; i < gem_index; i++) {
|
||||
strcat(complete_line, before);
|
||||
if (full_path == TRUE)
|
||||
strcat(complete_line, gem_list[i]);
|
||||
if (full_path == TRUE) {
|
||||
if (strcmp(mruby_root, "") == 0)
|
||||
strcat(complete_line, get_full_path(gem_list[i], "$(MRUBY_ROOT)"));
|
||||
else
|
||||
strcat(complete_line, get_full_path(gem_list[i], mruby_root));
|
||||
}
|
||||
else
|
||||
strcat(complete_line, get_file_name(gem_list[i]));
|
||||
strcat(complete_line, replace(after, "#GEMNAME#", get_file_name(gem_list[i])));
|
||||
@@ -172,7 +225,7 @@ for_each_gem (char before[1024], char after[1024],
|
||||
*
|
||||
*/
|
||||
static void
|
||||
make_gem_makefile(char active_gems[1024])
|
||||
make_gem_makefile(char active_gems[1024], char mruby_root[1024])
|
||||
{
|
||||
char *gem_check = { 0 };
|
||||
int gem_empty;
|
||||
@@ -180,16 +233,26 @@ make_gem_makefile(char active_gems[1024])
|
||||
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"
|
||||
|
||||
"INCLUDE := ");
|
||||
|
||||
/* collect all GEM include directories if they exist */
|
||||
printf("%s\n",
|
||||
for_each_gem("-I", "/include ", "", "", TRUE, active_gems, FALSE, "/include", mruby_root)
|
||||
);
|
||||
|
||||
printf("CFLAGS := -I. -I$(MRUBY_ROOT)/include -I$(MRUBY_ROOT)/src $(INCLUDE)\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"
|
||||
" MAKE_FLAGS = --no-print-directory CC=$(CC) LL=$(LL) CFLAGS='$(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"
|
||||
" MAKE_FLAGS = --no-print-directory CC='$(CC)' LL='$(LL)' CFLAGS='$(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, FALSE);
|
||||
gem_check = for_each_gem("", "", "", "", TRUE, active_gems, FALSE, "", "");
|
||||
if (strcmp(gem_check, "") == 0)
|
||||
gem_empty = TRUE;
|
||||
else
|
||||
@@ -205,7 +268,7 @@ make_gem_makefile(char active_gems[1024])
|
||||
|
||||
/* Call make for every GEM */
|
||||
printf("all_gems :\n%s\n",
|
||||
for_each_gem("\t@$(MAKE) -C ", " $(MAKE_FLAGS)\n", "", "", TRUE, active_gems, FALSE)
|
||||
for_each_gem("\t$(MAKE) -C ", " $(MAKE_FLAGS)\n", "", "", TRUE, active_gems, FALSE, "", "")
|
||||
);
|
||||
printf("\n");
|
||||
}
|
||||
@@ -217,7 +280,7 @@ make_gem_makefile(char active_gems[1024])
|
||||
);
|
||||
if (!gem_empty)
|
||||
printf("%s",
|
||||
for_each_gem(" ", "/test/*.rb ", "\tcat", " > mrbgemtest.rbtmp", TRUE, active_gems, FALSE)
|
||||
for_each_gem(" ", "/test/*.rb ", "\tcat", " > mrbgemtest.rbtmp", TRUE, active_gems, FALSE, "", "")
|
||||
);
|
||||
else
|
||||
printf("\t$(MRUBY_ROOT)/mrbgems/generator rbtmp> mrbgemtest.rbtmp");
|
||||
@@ -231,7 +294,7 @@ make_gem_makefile(char active_gems[1024])
|
||||
"\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, FALSE)
|
||||
for_each_gem("\t@$(MAKE) clean -C ", " $(MAKE_FLAGS)\n", "", "", TRUE, active_gems, FALSE, "", "")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -246,7 +309,7 @@ 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, FALSE)
|
||||
for_each_gem(" ", "/mrb-#GEMNAME#-gem.a", "GEM_LIST := ", "\n", TRUE, active_gems, FALSE, "", "")
|
||||
);
|
||||
|
||||
printf("GEM_ARCHIVE_FILES := $(MRUBY_ROOT)/mrbgems/gem_init.a\n"
|
||||
@@ -273,7 +336,7 @@ make_gem_init(char active_gems[1024])
|
||||
|
||||
/* Protoype definition of all initialization methods */
|
||||
printf("\n%s",
|
||||
for_each_gem("void GENERATED_TMP_mrb_", "_gem_init(mrb_state*);\n", "", "", FALSE, active_gems, TRUE)
|
||||
for_each_gem("void GENERATED_TMP_mrb_", "_gem_init(mrb_state*);\n", "", "", FALSE, active_gems, TRUE, "", "")
|
||||
);
|
||||
printf("\n");
|
||||
|
||||
@@ -281,7 +344,7 @@ make_gem_init(char active_gems[1024])
|
||||
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, TRUE)
|
||||
for_each_gem(" GENERATED_TMP_mrb_", "_gem_init(mrb);\n", "", "", FALSE, active_gems, TRUE, "", "")
|
||||
);
|
||||
printf("}");
|
||||
}
|
||||
@@ -363,6 +426,7 @@ make_gem_srclib(char gem_name[1024])
|
||||
" */\n\n"
|
||||
"#include \"mruby.h\"\n");
|
||||
|
||||
/* Prototype method for GEM initialization */
|
||||
printf("\n"
|
||||
"void mrb_%s_gem_init(mrb_state*);\n", gem_name);
|
||||
|
||||
@@ -384,6 +448,7 @@ make_gem_srclib(char gem_name[1024])
|
||||
static void
|
||||
make_gem_mixlib(char gem_name[1024])
|
||||
{
|
||||
/* Prototype method for GEM initialization */
|
||||
printf("\n"
|
||||
"void mrb_%s_gem_init(mrb_state*);\n", gem_name);
|
||||
|
||||
@@ -419,9 +484,7 @@ main (int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
else if (argc == 3) {
|
||||
if (strcmp(argv[1], "makefile") == 0)
|
||||
make_gem_makefile(argv[2]);
|
||||
else if (strcmp(argv[1], "makefile_list") == 0)
|
||||
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]);
|
||||
@@ -436,6 +499,14 @@ main (int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (argc == 4) {
|
||||
if (strcmp(argv[1], "makefile") == 0)
|
||||
make_gem_makefile(argv[2], argv[3]);
|
||||
else {
|
||||
printf("%s", argument_info);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("%s", argument_info);
|
||||
return 1;
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ mrb_init_core(mrb_state *mrb)
|
||||
mrb_init_math(mrb); DONE;
|
||||
#endif
|
||||
mrb_init_mrblib(mrb); DONE;
|
||||
#ifdef ENABLE_GEMS
|
||||
#ifndef DISABLE_GEMS
|
||||
mrb_init_mrbgems(mrb); DONE;
|
||||
#endif
|
||||
}
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ void
|
||||
mrb_init_mrbtest(mrb_state *mrb)
|
||||
{
|
||||
mrb_load_irep(mrb, mrbtest_irep);
|
||||
#ifdef ENABLE_GEMS
|
||||
#ifndef DISABLE_GEMS
|
||||
mrb_load_irep(mrb, mrbgemtest_irep);
|
||||
#endif
|
||||
if (mrb->exc) {
|
||||
|
||||
+1
-1
@@ -226,7 +226,7 @@ mrb_init_mrblib(mrb_state *mrb)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef ENABLE_GEMS
|
||||
#ifndef DISABLE_GEMS
|
||||
void
|
||||
mrb_init_mrbgems(mrb_state *mrb)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user