[439] | 1 | # mrbgems
|
---|
| 2 |
|
---|
| 3 | mrbgems is a library manager to integrate C and Ruby extension in an easy and
|
---|
| 4 | standardised way into mruby.
|
---|
| 5 |
|
---|
| 6 | ## Usage
|
---|
| 7 |
|
---|
| 8 | By default mrbgems is currently deactivated. As soon as you add a GEM to your
|
---|
| 9 | build configuration (i.e. *build_config.rb*), mrbgems will be activated and the
|
---|
| 10 | extension integrated.
|
---|
| 11 |
|
---|
| 12 | To add a GEM into the *build_config.rb* add the following line for example:
|
---|
| 13 | ```ruby
|
---|
| 14 | conf.gem '/path/to/your/gem/dir'
|
---|
| 15 | ```
|
---|
| 16 |
|
---|
| 17 | You can also use a relative path which would be relative from the mruby root:
|
---|
| 18 | ```ruby
|
---|
| 19 | conf.gem 'examples/mrbgems/ruby_extension_example'
|
---|
| 20 | ```
|
---|
| 21 |
|
---|
| 22 | A remote GIT repository location for a GEM is also supported:
|
---|
| 23 | ```ruby
|
---|
| 24 | conf.gem :git => 'https://github.com/masuidrive/mrbgems-example.git', :branch => 'master'
|
---|
| 25 | conf.gem :github => 'masuidrive/mrbgems-example', :branch => 'master'
|
---|
| 26 | conf.gem :bitbucket => 'mruby/mrbgems-example', :branch => 'master'
|
---|
| 27 | ```
|
---|
| 28 |
|
---|
| 29 | You can specify the sub directory of the repository with `:path` option:
|
---|
| 30 | ```ruby
|
---|
| 31 | conf.gem github: 'mruby/mruby', path: 'mrbgems/mruby-socket'
|
---|
| 32 | ```
|
---|
| 33 |
|
---|
| 34 | To use mrbgem from [mgem-list](https://github.com/mruby/mgem-list) use `:mgem` option:
|
---|
| 35 | ```ruby
|
---|
| 36 | conf.gem :mgem => 'mruby-yaml'
|
---|
| 37 | conf.gem :mgem => 'yaml' # 'mruby-' prefix could be omitted
|
---|
| 38 | ```
|
---|
| 39 |
|
---|
| 40 | For specifying commit hash to checkout use `:checksum_hash` option:
|
---|
| 41 | ```ruby
|
---|
| 42 | conf.gem mgem: 'mruby-redis', checksum_hash: '3446d19fc4a3f9697b5ddbf2a904f301c42f2f4e'
|
---|
| 43 | ```
|
---|
| 44 |
|
---|
| 45 | If there is missing dependencies, mrbgem dependencies solver will reference
|
---|
| 46 | mrbgem from core or mgem-list.
|
---|
| 47 |
|
---|
| 48 | To pull all gems from remote GIT repository on build, call ```rake -p```,
|
---|
| 49 | or ```rake --pull-gems```.
|
---|
| 50 |
|
---|
| 51 | NOTE: `:bitbucket` option supports only git. Hg is unsupported in this version.
|
---|
| 52 |
|
---|
| 53 | ## GemBox
|
---|
| 54 |
|
---|
| 55 | There are instances when you wish to add a collection of mrbgems into mruby at
|
---|
| 56 | once, or be able to substitute mrbgems based on configuration, without having to
|
---|
| 57 | add each gem to the *build_config.rb* file. A packaged collection of mrbgems
|
---|
| 58 | is called a GemBox. A GemBox is a file that contains a list of mrbgems to load
|
---|
| 59 | into mruby, in the same format as if you were adding them to *build_config.rb*
|
---|
| 60 | via `config.gem`, but wrapped in an `MRuby::GemBox` object. GemBoxes are
|
---|
| 61 | loaded into mruby via `config.gembox 'boxname'`.
|
---|
| 62 |
|
---|
| 63 | Below we have created a GemBox containing *mruby-time* and *mrbgems-example*:
|
---|
| 64 | ```ruby
|
---|
| 65 | MRuby::GemBox.new do |conf|
|
---|
| 66 | conf.gem "#{root}/mrbgems/mruby-time"
|
---|
| 67 | conf.gem :github => 'masuidrive/mrbgems-example'
|
---|
| 68 | end
|
---|
| 69 | ```
|
---|
| 70 |
|
---|
| 71 | As mentioned, the GemBox uses the same conventions as `MRuby::Build`. The GemBox
|
---|
| 72 | must be saved with a *.gembox* extension inside the *mrbgems* directory to to be
|
---|
| 73 | picked up by mruby.
|
---|
| 74 |
|
---|
| 75 | To use this example GemBox, we save it as `custom.gembox` inside the *mrbgems*
|
---|
| 76 | directory in mruby, and add the following to our *build_config.rb* file inside
|
---|
| 77 | the build block:
|
---|
| 78 | ```ruby
|
---|
| 79 | conf.gembox 'custom'
|
---|
| 80 | ```
|
---|
| 81 | This will cause the *custom* GemBox to be read in during the build process,
|
---|
| 82 | adding *mruby-time* and *mrbgems-example* to the build.
|
---|
| 83 |
|
---|
| 84 | If you want, you can put GemBox outside of mruby directory. In that case you must
|
---|
| 85 | specify an absolute path like below.
|
---|
| 86 | ```ruby
|
---|
| 87 | conf.gembox "#{ENV["HOME"]}/mygemboxes/custom"
|
---|
| 88 | ```
|
---|
| 89 |
|
---|
| 90 | There are two GemBoxes that ship with mruby: [default](../../mrbgems/default.gembox)
|
---|
| 91 | and [full-core](../../mrbgems/full-core.gembox). The [default](../../mrbgems/default.gembox) GemBox
|
---|
| 92 | contains several core components of mruby, and [full-core](../../mrbgems/full-core.gembox)
|
---|
| 93 | contains every gem found in the *mrbgems* directory.
|
---|
| 94 |
|
---|
| 95 | ## GEM Structure
|
---|
| 96 |
|
---|
| 97 | The maximal GEM structure looks like this:
|
---|
| 98 |
|
---|
| 99 | +- GEM_NAME <- Name of GEM
|
---|
| 100 | |
|
---|
| 101 | +- include/ <- Header for Ruby extension (will exported)
|
---|
| 102 | |
|
---|
| 103 | +- mrblib/ <- Source for Ruby extension
|
---|
| 104 | |
|
---|
| 105 | +- src/ <- Source for C extension
|
---|
| 106 | |
|
---|
| 107 | +- test/ <- Test code (Ruby)
|
---|
| 108 | |
|
---|
| 109 | +- mrbgem.rake <- GEM Specification
|
---|
| 110 | |
|
---|
| 111 | +- README.md <- Readme for GEM
|
---|
| 112 |
|
---|
| 113 | The folder *mrblib* contains pure Ruby files to extend mruby. The folder *src*
|
---|
| 114 | contains C/C++ files to extend mruby. The folder *include* contains C/C++ header
|
---|
| 115 | files. The folder *test* contains C/C++ and pure Ruby files for testing purposes
|
---|
| 116 | which will be used by `mrbtest`. *mrbgem.rake* contains the specification
|
---|
| 117 | to compile C and Ruby files. *README.md* is a short description of your GEM.
|
---|
| 118 |
|
---|
| 119 | ## Build process
|
---|
| 120 |
|
---|
| 121 | mrbgems expects a specification file called *mrbgem.rake* inside of your
|
---|
| 122 | GEM directory. A typical GEM specification could look like this for example:
|
---|
| 123 | ```ruby
|
---|
| 124 | MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec|
|
---|
| 125 | spec.license = 'MIT'
|
---|
| 126 | spec.author = 'mruby developers'
|
---|
| 127 | spec.summary = 'Example mrbgem using C and ruby'
|
---|
| 128 | end
|
---|
| 129 | ```
|
---|
| 130 |
|
---|
| 131 | The mrbgems build process will use this specification to compile Object and Ruby
|
---|
| 132 | files. The compilation results will be added to *lib/libmruby.a*. This file exposes
|
---|
| 133 | the GEM functionality to tools like `mruby` and `mirb`.
|
---|
| 134 |
|
---|
| 135 | The following properties can be set inside of your `MRuby::Gem::Specification` for
|
---|
| 136 | information purpose:
|
---|
| 137 |
|
---|
| 138 | * `spec.license` or `spec.licenses` (A single license or a list of them under which this GEM is licensed)
|
---|
| 139 | * `spec.author` or `spec.authors` (Developer name or a list of them)
|
---|
| 140 | * `spec.version` (Current version)
|
---|
| 141 | * `spec.description` (Detailed description)
|
---|
| 142 | * `spec.summary`
|
---|
| 143 | * One line short description of mrbgem.
|
---|
| 144 | * Printed in build summary of rake when set.
|
---|
| 145 | * `spec.homepage` (Homepage)
|
---|
| 146 | * `spec.requirements` (External requirements as information for user)
|
---|
| 147 |
|
---|
| 148 | The `license` and `author` properties are required in every GEM!
|
---|
| 149 |
|
---|
| 150 | In case your GEM is depending on other GEMs please use
|
---|
| 151 | `spec.add_dependency(gem, *requirements[, default_get_info])` like:
|
---|
| 152 | ```ruby
|
---|
| 153 | MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec|
|
---|
| 154 | spec.license = 'MIT'
|
---|
| 155 | spec.author = 'mruby developers'
|
---|
| 156 |
|
---|
| 157 | # Add GEM dependency mruby-parser.
|
---|
| 158 | # The version must be between 1.0.0 and 1.5.2 .
|
---|
| 159 | spec.add_dependency('mruby-parser', '>= 1.0.0', '<= 1.5.2')
|
---|
| 160 |
|
---|
| 161 | # Use any version of mruby-uv from github.
|
---|
| 162 | spec.add_dependency('mruby-uv', '>= 0.0.0', :github => 'mattn/mruby-uv')
|
---|
| 163 |
|
---|
| 164 | # Use latest mruby-onig-regexp from github. (version requirements can be omitted)
|
---|
| 165 | spec.add_dependency('mruby-onig-regexp', :github => 'mattn/mruby-onig-regexp')
|
---|
| 166 |
|
---|
| 167 | # You can add extra mgems active only on test
|
---|
| 168 | spec.add_test_dependency('mruby-process', :github => 'iij/mruby-process')
|
---|
| 169 | end
|
---|
| 170 | ```
|
---|
| 171 |
|
---|
| 172 | The version requirements and default gem information are optional.
|
---|
| 173 |
|
---|
| 174 | Version requirement supports following operators:
|
---|
| 175 | * '=': is equal
|
---|
| 176 | * '!=': is not equal
|
---|
| 177 | * '>': is greater
|
---|
| 178 | * '<': is lesser
|
---|
| 179 | * '>=': is equal or greater
|
---|
| 180 | * '<=': is equal or lesser
|
---|
| 181 | * '~>': is equal or greater and is lesser than the next major version
|
---|
| 182 | * example 1: '~> 2.2.2' means '>= 2.2.2' and '< 2.3.0'
|
---|
| 183 | * example 2: '~> 2.2' means '>= 2.2.0' and '< 3.0.0'
|
---|
| 184 |
|
---|
| 185 | When more than one version requirements is passed, the dependency must satisfy all of it.
|
---|
| 186 |
|
---|
| 187 | You can have default gem to use as dependency when it's not defined in *build_config.rb*.
|
---|
| 188 | When the last argument of `add_dependency` call is `Hash`, it will be treated as default gem information.
|
---|
| 189 | Its format is same as argument of method `MRuby::Build#gem`, expect that it can't be treated as path gem location.
|
---|
| 190 |
|
---|
| 191 | When a special version of dependency is required,
|
---|
| 192 | use `MRuby::Build#gem` in *build_config.rb* to override default gem.
|
---|
| 193 |
|
---|
| 194 | If you have conflicting GEMs use the following method:
|
---|
| 195 | * `spec.add_conflict(gem, *requirements)`
|
---|
| 196 | * The `requirements` argument is same as in `add_dependency` method.
|
---|
| 197 |
|
---|
| 198 | like following code:
|
---|
| 199 | ```ruby
|
---|
| 200 | MRuby::Gem::Specification.new 'some-regexp-binding' do |spec|
|
---|
| 201 | spec.license = 'BSD'
|
---|
| 202 | spec.author = 'John Doe'
|
---|
| 203 |
|
---|
| 204 | spec.add_conflict 'mruby-onig-regexp', '> 0.0.0'
|
---|
| 205 | spec.add_conflict 'mruby-hs-regexp'
|
---|
| 206 | spec.add_conflict 'mruby-pcre-regexp'
|
---|
| 207 | spec.add_conflict 'mruby-regexp-pcre'
|
---|
| 208 | end
|
---|
| 209 | ```
|
---|
| 210 |
|
---|
| 211 | In case your GEM has more complex build requirements you can use
|
---|
| 212 | the following options additionally inside of your GEM specification:
|
---|
| 213 |
|
---|
| 214 | * `spec.cc.flags` (C compiler flags)
|
---|
| 215 | * `spec.cc.defines` (C compiler defines)
|
---|
| 216 | * `spec.cc.include_paths` (C compiler include paths)
|
---|
| 217 | * `spec.linker.flags` (Linker flags)
|
---|
| 218 | * `spec.linker.libraries` (Linker libraries)
|
---|
| 219 | * `spec.linker.library_paths` (Linker additional library path)
|
---|
| 220 | * `spec.bins` (Generate binary file)
|
---|
| 221 | * `spec.rbfiles` (Ruby files to compile)
|
---|
| 222 | * `spec.objs` (Object files to compile)
|
---|
| 223 | * `spec.test_rbfiles` (Ruby test files for integration into mrbtest)
|
---|
| 224 | * `spec.test_objs` (Object test files for integration into mrbtest)
|
---|
| 225 | * `spec.test_preload` (Initialization files for mrbtest)
|
---|
| 226 |
|
---|
| 227 | You also can use `spec.mruby.cc` and `spec.mruby.linker` to add extra global parameters for compiler and linker.
|
---|
| 228 |
|
---|
| 229 | ### include_paths and dependency
|
---|
| 230 |
|
---|
| 231 | Your GEM can export include paths to another GEMs that depends on your GEM.
|
---|
| 232 | By default, `/...absolute path.../{GEM_NAME}/include` will be exported.
|
---|
| 233 | So it is recommended not to put GEM's local header files on include/.
|
---|
| 234 |
|
---|
| 235 | These exports are retroactive.
|
---|
| 236 | For example: when B depends to C and A depends to B, A will get include paths exported by C.
|
---|
| 237 |
|
---|
| 238 | Exported include_paths are automatically appended to GEM local include_paths by rake.
|
---|
| 239 | You can use `spec.export_include_paths` accessor if you want more complex build.
|
---|
| 240 |
|
---|
| 241 |
|
---|
| 242 | ## C Extension
|
---|
| 243 |
|
---|
| 244 | mruby can be extended with C. This is possible by using the C API to
|
---|
| 245 | integrate C libraries into mruby.
|
---|
| 246 |
|
---|
| 247 | ### Preconditions
|
---|
| 248 |
|
---|
| 249 | mrbgems expects that you have implemented a C method called
|
---|
| 250 | `mrb_YOURGEMNAME_gem_init(mrb_state)`. `YOURGEMNAME` will be replaced
|
---|
| 251 | by the name of your GEM. If you call your GEM *c_extension_example*, your
|
---|
| 252 | initialisation method could look like this:
|
---|
| 253 | ```C
|
---|
| 254 | void
|
---|
| 255 | mrb_c_extension_example_gem_init(mrb_state* mrb) {
|
---|
| 256 | struct RClass *class_cextension = mrb_define_module(mrb, "CExtension");
|
---|
| 257 | mrb_define_class_method(mrb, class_cextension, "c_method", mrb_c_method, MRB_ARGS_NONE());
|
---|
| 258 | }
|
---|
| 259 | ```
|
---|
| 260 |
|
---|
| 261 | ### Finalize
|
---|
| 262 |
|
---|
| 263 | mrbgems expects that you have implemented a C method called
|
---|
| 264 | `mrb_YOURGEMNAME_gem_final(mrb_state)`. `YOURGEMNAME` will be replaced
|
---|
| 265 | by the name of your GEM. If you call your GEM *c_extension_example*, your
|
---|
| 266 | finalizer method could look like this:
|
---|
| 267 |
|
---|
| 268 | ```C
|
---|
| 269 | void
|
---|
| 270 | mrb_c_extension_example_gem_final(mrb_state* mrb) {
|
---|
| 271 | free(someone);
|
---|
| 272 | }
|
---|
| 273 | ```
|
---|
| 274 |
|
---|
| 275 | ### Example
|
---|
| 276 |
|
---|
| 277 | +- c_extension_example/
|
---|
| 278 | |
|
---|
| 279 | +- src/
|
---|
| 280 | | |
|
---|
| 281 | | +- example.c <- C extension source
|
---|
| 282 | |
|
---|
| 283 | +- test/
|
---|
| 284 | | |
|
---|
| 285 | | +- example.rb <- Test code for C extension
|
---|
| 286 | |
|
---|
| 287 | +- mrbgem.rake <- GEM specification
|
---|
| 288 | |
|
---|
| 289 | +- README.md
|
---|
| 290 |
|
---|
| 291 | ## Ruby Extension
|
---|
| 292 |
|
---|
| 293 | mruby can be extended with pure Ruby. It is possible to override existing
|
---|
| 294 | classes or add new ones in this way. Put all Ruby files into the *mrblib*
|
---|
| 295 | folder.
|
---|
| 296 |
|
---|
| 297 |
|
---|
| 298 | ### Pre-Conditions
|
---|
| 299 |
|
---|
| 300 | none
|
---|
| 301 |
|
---|
| 302 | ### Example
|
---|
| 303 |
|
---|
| 304 | +- ruby_extension_example/
|
---|
| 305 | |
|
---|
| 306 | +- mrblib/
|
---|
| 307 | | |
|
---|
| 308 | | +- example.rb <- Ruby extension source
|
---|
| 309 | |
|
---|
| 310 | +- test/
|
---|
| 311 | | |
|
---|
| 312 | | +- example.rb <- Test code for Ruby extension
|
---|
| 313 | |
|
---|
| 314 | +- mrbgem.rake <- GEM specification
|
---|
| 315 | |
|
---|
| 316 | +- README.md
|
---|
| 317 |
|
---|
| 318 | ## C and Ruby Extension
|
---|
| 319 |
|
---|
| 320 | mruby can be extended with C and Ruby at the same time. It is possible to
|
---|
| 321 | override existing classes or add new ones in this way. Put all Ruby files
|
---|
| 322 | into the *mrblib* folder and all C files into the *src* folder.
|
---|
| 323 |
|
---|
| 324 | mruby codes under *mrblib* directory would be executed after gem init C
|
---|
| 325 | function is called. Make sure *mruby script* depends on *C code* and
|
---|
| 326 | *C code* doesn't depend on *mruby script*.
|
---|
| 327 |
|
---|
| 328 | ### Pre-Conditions
|
---|
| 329 |
|
---|
| 330 | See C and Ruby example.
|
---|
| 331 |
|
---|
| 332 | ### Example
|
---|
| 333 |
|
---|
| 334 | +- c_and_ruby_extension_example/
|
---|
| 335 | |
|
---|
| 336 | +- mrblib/
|
---|
| 337 | | |
|
---|
| 338 | | +- example.rb <- Ruby extension source
|
---|
| 339 | |
|
---|
| 340 | +- src/
|
---|
| 341 | | |
|
---|
| 342 | | +- example.c <- C extension source
|
---|
| 343 | |
|
---|
| 344 | +- test/
|
---|
| 345 | | |
|
---|
| 346 | | +- example.rb <- Test code for C and Ruby extension
|
---|
| 347 | |
|
---|
| 348 | +- mrbgem.rake <- GEM specification
|
---|
| 349 | |
|
---|
| 350 | +- README.md
|
---|