diff options
| -rw-r--r-- | doc/compile/README.md | 212 | ||||
| -rw-r--r-- | doc/mrbgems/README.md | 45 | ||||
| -rw-r--r-- | src/class.c | 43 | ||||
| -rw-r--r-- | tasks/libmruby.rake | 2 | ||||
| -rw-r--r-- | tasks/mruby_gem_spec.rake | 10 | ||||
| -rw-r--r-- | tasks/rules.rake | 2 | ||||
| -rw-r--r-- | test/t/module.rb | 24 |
7 files changed, 310 insertions, 28 deletions
diff --git a/doc/compile/README.md b/doc/compile/README.md new file mode 100644 index 000000000..e68c0d6f1 --- /dev/null +++ b/doc/compile/README.md @@ -0,0 +1,212 @@ +# Compile + +mruby is using Rake to compile and cross-compile all libraries and +binaries. + +## Prerequisites + +To compile mruby out of the source code you need the following tools: +* C Compiler (i.e. ```gcc```) +* Linker (i.e. ```gcc```) +* Archive utility (i.e. ```ar```) +* Parser generator (i.e. ```bison```) +* Ruby 1.8 or 1.9 + +Optional: +* GIT (to update mruby source and integrate mrbgems easier) +* C++ compiler (to use GEMs which include *.cpp) +* Assembler (to use GEMs which include *.asm) + +## Usage + +Inside of the root directory of the mruby source exist a file +called *build_config.rb*. This file contains the build configuration +of mruby and looks like this for example: + +``` +MRuby::Build.new do |conf| + conf.cc = ENV['CC'] || 'gcc' + conf.ld = ENV['LD'] || 'gcc' + conf.ar = ENV['AR'] || 'ar' + + conf.cflags << (ENV['CFLAGS'] || %w(-g -O3 -Wall -Werror-implicit-function-declaration)) + conf.ldflags << (ENV['LDFLAGS'] || %w(-lm)) +end +``` + +All tools necessary to compile mruby can be set or modified here. +The following options can be configurated: + +* conf.cc (C compiler) +* conf.ld (Linker) +* conf.ar (Archive utility) +* conf.cxx (C++ compiler) +* conf.objcc (Object compiler) +* conf.asm (Assembler) +* conf.yacc (Parser Generator) +* conf.gperf (Hash function Generator) +* conf.cat (Concatenate utility) +* conf.git (GIT content tracker) +* conf.cflags (C compiler flags) +* conf.ldflags (Linker flags) +* conf.cxxflags (C++ compiler flags) +* conf.objccflags (Object compiler flags) +* conf.asmflags (Assembler flags) +* conf.gem (A GEM which should be integrated - can be set several times) + +To compile just call ```./minirake``` inside of the mruby source root. To +generate the test tool environment call ```./minirake test```. To clean +all build files call ```./minirake clean```. + +### Cross-Compilation + +mruby can also be cross-compiled from one platform to another. To +achive this the *build_config.rb* needs to contain an instance of +```MRuby::CrossBuild```. This instance defines the compilation +tools and flags for the target platform. An example could look +like this for example: + +``` +MRuby::CrossBuild.new('i386') do |conf| + conf.cc = ENV['CC'] || 'gcc' + conf.ld = ENV['LD'] || 'gcc' + conf.ar = ENV['AR'] || 'ar' + + if ENV['OS'] == 'Windows_NT' # MinGW + conf.cflags = %w(-g -O3 -Wall -Werror-implicit-function-declaration -Di386_MARK) + conf.ldflags = %w(-s -static) + else + conf.cflags << %w(-g -O3 -Wall -Werror-implicit-function-declaration -arch i386) + conf.ldflags << %w(-arch i386) + end +end +``` + +You can configurate the same options as for a normal build. + +## Build process + +During the build process the directory *build* will be created. The +directory structure will look like this: + +``` ++- build + | + +- host + | + +- bin <- Binaries (mirb, mrbc and mruby) + | + +- lib <- Libraries (libmruby.a and libmruby_core.a) + | + +- mrblib + | + +- src + | + +- test <- mrbtest tool + | + +- tools + | + +- mirb + | + +- mrbc + | + +- mruby +``` + +The compilation workflow will look like this: +* compile all files under *src* (object files will be stored +in *build/host/src* +* generate parser grammar out of *src/parse.y* (generated +result will be stored in *build/host/src/y.tab.c* +* compile *build/host/src/y.tab.c* to *build/host/src/y.tab.o* +* create *build/host/lib/libmruby_core.a* out of all object files (C only) +* create ```build/host/bin/mrbc``` by compile *tools/mrbc/mrbc.c* and +link with *build/host/lib/libmruby_core.a* +* create *build/host/mrblib/mrblib.c* by compiling all *.rb files +under *mrblib* with ```build/host/bin/mrbc``` +* compile *build/host/mrblib/mrblib.c* to *build/host/mrblib/mrblib.o* +* create *build/host/lib/libmruby.a* out of all object files (C and Ruby) +* create ```build/host/bin/mruby``` by compile *tools/mruby/mruby.c* and +link with *build/host/lib/libmruby.a* +* create ```build/host/bin/mirb``` by compile *tools/mirb/mirb.c* and +link with *build/host/lib/libmruby.a* + +### Cross-Compilation + +In case of a cross-compilation to *i386* the *build* directory structure looks +like this: + +``` ++- build + | + +- host + | | + | +- bin <- Native Binaries + | | + | +- lib <- Native Libraries + | | + | +- mrblib + | | + | +- src + | | + | +- test <- Native mrbtest tool + | | + | +- tools + | | + | +- mirb + | | + | +- mrbc + | | + | +- mruby + +- i386 + | + +- bin <- Cross-compiled Binaries + | + +- lib <- Cross-compiled Libraries + | + +- mrblib + | + +- src + | + +- test <- Cross-compiled mrbtest tool + | + +- tools + | + +- mirb + | + +- mrbc + | + +- mruby +``` + +An extra directory is created for the target platform. In case you +compile for *i386* a directory called *i386* is created under the +build direcotry. + +The cross compilation workflow starts in the same way as the normal +compilation by compiling all *native* libraries and binaries. +Aftwards the cross compilation process proceeds like this: +* cross-compile all files under *src* (object files will be stored +in *build/i386/src* +* generate parser grammar out of *src/parse.y* (generated +result will be stored in *build/i386/src/y.tab.c* +* cross-compile *build/i386/src/y.tab.c* to *build/i386/src/y.tab.o* +* create *build/i386/mrblib/mrblib.c* by compiling all *.rb files +under *mrblib* with the native ```build/host/bin/mrbc``` +* cross-compile *build/host/mrblib/mrblib.c* to *build/host/mrblib/mrblib.o* +* create *build/i386/lib/libmruby.a* out of all object files (C and Ruby) +* create ```build/i386/bin/mruby``` by cross-compile *tools/mruby/mruby.c* and +link with *build/i386/lib/libmruby.a* +* create ```build/i386/bin/mirb``` by cross-compile *tools/mirb/mirb.c* and +link with *build/i386/lib/libmruby.a* +* create *build/i386/lib/libmruby_core.a* out of all object files (C only) +* create ```build/i386/bin/mrbc``` by cross-compile *tools/mrbc/mrbc.c* and +link with *build/i386/lib/libmruby_core.a* + +## Test Environment + +mruby's build process includes a test environment. In case you start the testing +of mruby, a native binary called ```mrbtest``` will be generated and executed. +This binary contains all test cases which are defined under *test/t*. In case +of a cross-compilation an additional cross-compiled *mrbtest* binary is +generated. This binary you can copy and run on your target system. diff --git a/doc/mrbgems/README.md b/doc/mrbgems/README.md index 6d5a023bc..cc28f48f8 100644 --- a/doc/mrbgems/README.md +++ b/doc/mrbgems/README.md @@ -5,11 +5,11 @@ standardised way into mruby. ## Usage -By default mrbgems is currently deactivated. As soon as you add a GEM to the -build configuration (build_config.rb), mrbgems will be activated and the -extension will be integrated. +By default mrbgems is currently deactivated. As soon as you add a GEM to your +build configuration (*build_config.rb*), mrbgems will be activated and the +extension integrated. -To add a GEM into the build_config.rb add the following line: +To add a GEM into the build_config.rb add the following line for example: ``` conf.gem '/path/to/your/gem/dir' @@ -49,14 +49,13 @@ 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 C and pure Ruby files for testing purposes which will be used by ```mrbtest```. *mrbgem.rake* contains -rules to build a *libmrb-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. +the specification to compile C and Ruby files. *README.md* is a short description +of your GEM. ## Build process -mrbgems expects a file called *mrbgem.rake* inside of your GEM directory. A -typical file could for example look like this: +mrbgems expects a specifcation file called *mrbgem.rake* inside of your +GEM direcotry. A typical GEM specification could look like this for example: ``` MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec| @@ -65,35 +64,35 @@ MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec| end ``` -The mrbgems build process will use this file to create a archive file -*libmrb-GEMNAME-gem.a* during the build process. This file will be used -by tools like *mruby* and *mirb* to integrate the GEM functionality. +The mrbgems build process will use this specification to compile Object and Ruby +files. The compilation results will be add to *lib/libmruby.a*. This file is used +by tools like ```mruby``` and ```mirb``` to empower the GEM functionality. -In case your GEM has more complex build requirements you can empower +In case your GEM has more complex build requirements you can use the following options additionally inside of your GEM specification: -* spec.cflags (flags for the C compiler) -* spec.mruby_cflags (flags for the C compiler) -* spec.mruby_ldflags (flags for the linker) -* spec.mruby_libs (Libraries to include) -* spec.mruby_includes (Directories for include) +* spec.cflags (C compiler flags for this GEM) +* spec.mruby_cflags (global C compiler flags for everything) +* spec.mruby_ldflags (global linker flags for everything) +* spec.mruby_libs (global libraries for everything) +* spec.mruby_includes (global includes for everything) * spec.rbfiles (Ruby files to compile) -* spec.objs +* spec.objs (Object files to compile) * spec.test_rbfiles (Ruby test files for integration into mrbtest) -* spec.test_objs +* spec.test_objs (Object test files for integration into mrbtest) * spec.test_preload (Initialization files for mrbtest) ## C Extension -mruby can be extended with C. It is possible by using the C API to +mruby can be extended with C. This is possible by using the C API to integrate C libraries into mruby. ### Pre-Conditions mrbgems expects that you have implemented a C method called ```mrb_YOURGEMNAME_gem_init(mrb_state)```. ```YOURGEMNAME``` will be replaced -by the name of you GEM. If you call your GEM directory *c_extension_example*, -your initialisation method could look like this: +by the name of your GEM. If you call your GEM *c_extension_example*, your +initialisation method could look like this: ``` void diff --git a/src/class.c b/src/class.c index ace34eb34..ea0db2bdc 100644 --- a/src/class.c +++ b/src/class.c @@ -1595,6 +1595,48 @@ mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } +/* 15.2.2.4.34 */ +/* + * call-seq: + * mod.method_defined?(symbol) -> true or false + * + * Returns +true+ if the named method is defined by + * _mod_ (or its included modules and, if _mod_ is a class, + * its ancestors). Public and protected methods are matched. + * + * module A + * def method1() end + * end + * class B + * def method2() end + * end + * class C < B + * include A + * def method3() end + * end + * + * A.method_defined? :method1 #=> true + * C.method_defined? "method1" #=> true + * C.method_defined? "method2" #=> true + * C.method_defined? "method3" #=> true + * C.method_defined? "method4" #=> false + */ + +static mrb_value +mrb_mod_method_defined(mrb_state *mrb, mrb_value mod) +{ + mrb_value sym; + mrb_sym id; + + mrb_get_args(mrb, "o", &sym); + id = mrb_sym_value(mrb,sym); + + if (mrb_obj_respond_to(mrb_class_ptr(mod), id)) { + return mrb_true_value(); + } + return mrb_false_value(); +} + static void remove_method(mrb_state *mrb, struct RClass *c, mrb_sym mid) { @@ -1750,6 +1792,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "included", mrb_bob_init, ARGS_REQ(1)); /* 15.2.2.4.29 */ mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, ARGS_NONE()); /* 15.2.2.4.30 */ mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, ARGS_ANY()); /* 15.2.2.4.33 */ + mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "module_eval", mrb_mod_module_eval, ARGS_ANY()); /* 15.2.2.4.35 */ mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, ARGS_REQ(1)); /* 15.2.2.4.39 */ mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, ARGS_ANY()); /* 15.2.2.4.41 */ diff --git a/tasks/libmruby.rake b/tasks/libmruby.rake index 5b785d208..1c68aa5e4 100644 --- a/tasks/libmruby.rake +++ b/tasks/libmruby.rake @@ -1,4 +1,4 @@ - MRuby.each_target do +MRuby.each_target do file "#{build_dir}/lib/libmruby.a" => libmruby.flatten do |t| archive t.name, 'r', t.prerequisites end diff --git a/tasks/mruby_gem_spec.rake b/tasks/mruby_gem_spec.rake index ae6d46b95..9f28b2b6a 100644 --- a/tasks/mruby_gem_spec.rake +++ b/tasks/mruby_gem_spec.rake @@ -33,7 +33,7 @@ module MRuby @name = name @build = MRuby.build @dir = Gem.processing_path - @cflags = [] + @cflags, @cxxflags, @objcflags, @asmflags = [], [], [], [] @mruby_cflags, @mruby_ldflags, @mruby_libs = [], [], [] @mruby_includes = ["#{dir}/include"] @rbfiles = Dir.glob("#{dir}/mrblib/*.rb") @@ -113,9 +113,11 @@ __EOF__ obj_matcher = Regexp.new("^#{build_dir}/(.*)\\.o$") { '.c' => proc { |t| build.compile_c t.name, t.prerequisites.first, cflags }, - '.cpp' => proc { |t| build.compile_cxx t.name, t.prerequisites.first, cflags }, - '.m' => proc { |t| build.compile_objc t.name, t.prerequisites.first, cflags }, - '.S' => proc { |t| build.compile_asm t.name, t.prerequisites.first, cflags } + '.cpp' => proc { |t| build.compile_cxx t.name, t.prerequisites.first, cxxflags }, + '.cxx' => proc { |t| build.compile_cxx t.name, t.prerequisites.first, cxxflags }, + '.cc' => proc { |t| build.compile_cxx t.name, t.prerequisites.first, cxxflags }, + '.m' => proc { |t| build.compile_objc t.name, t.prerequisites.first, objcflags }, + '.S' => proc { |t| build.compile_asm t.name, t.prerequisites.first, asmflags } }.each do |ext, compile| rule obj_matcher => [ proc { |file| diff --git a/tasks/rules.rake b/tasks/rules.rake index f53f3bccd..7d988cde3 100644 --- a/tasks/rules.rake +++ b/tasks/rules.rake @@ -12,6 +12,8 @@ MRuby.each_target do |t| { '.c' => proc { |t| compile_c t.name, t.prerequisites.first }, '.cpp' => proc { |t| compile_cxx t.name, t.prerequisites.first }, + '.cxx' => proc { |t| compile_cxx t.name, t.prerequisites.first }, + '.cc' => proc { |t| compile_cxx t.name, t.prerequisites.first }, '.m' => proc { |t| compile_objc t.name, t.prerequisites.first }, '.S' => proc { |t| compile_asm t.name, t.prerequisites.first } }.each do |ext, compile| diff --git a/test/t/module.rb b/test/t/module.rb index bf9626c2d..286c2c085 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -199,6 +199,30 @@ assert('Module#instance_methods', '15.2.2.4.33') do r.class == Array and r.include?(:method3) and r.include?(:method2) end +assert('Module#method_defined?', '15.2.2.4.34') do + module Test4MethodDefined + module A + def method1() end + end + + class B + def method2() end + end + + class C < B + include A + def method3() end + end + end + + Test4MethodDefined::A.method_defined? :method1 and + Test4MethodDefined::C.method_defined? :method1 and + Test4MethodDefined::C.method_defined? "method2" and + Test4MethodDefined::C.method_defined? "method3" and + not Test4MethodDefined::C.method_defined? "method4" +end + + assert('Module#module_eval', '15.2.2.4.35') do module Test4ModuleEval @a = 11 |
