summaryrefslogtreecommitdiffstats
path: root/web/server/h2o/libh2o/deps/mruby/doc/guides/mrbgems.md
blob: 258f405b5ef3996d53915ae9637eb53b5f75225a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# mrbgems

mrbgems is a library manager to integrate C and Ruby extension in an easy and
standardised way into mruby.

## Usage

By default mrbgems is currently deactivated. As soon as you add a GEM to your
build configuration (i.e. *build_config.rb*), mrbgems will be activated and the
extension integrated.

To add a GEM into the *build_config.rb* add the following line for example:
```ruby
conf.gem '/path/to/your/gem/dir'
```

You can also use a relative path which would be relative from the mruby root:
```ruby
conf.gem 'examples/mrbgems/ruby_extension_example'
```

A remote GIT repository location for a GEM is also supported:
```ruby
conf.gem :git => 'https://github.com/masuidrive/mrbgems-example.git', :branch => 'master'
conf.gem :github => 'masuidrive/mrbgems-example', :branch => 'master'
conf.gem :bitbucket => 'mruby/mrbgems-example', :branch => 'master'
```

To use mrbgem from [mgem-list](https://github.com/mruby/mgem-list) use `:mgem` option:
```ruby
conf.gem :mgem => 'mruby-yaml'
conf.gem :mgem => 'yaml' # 'mruby-' prefix could be omitted
```

If there is missing dependencies, mrbgem dependencies solver will reference
mrbgem from core or mgem-list.

To pull all gems from remote GIT repository on build, call ```./minirake -p```,
or ```./minirake --pull-gems```.

NOTE: `:bitbucket` option supports only git. Hg is unsupported in this version.

## GemBox

There are instances when you wish to add a collection of mrbgems into mruby at
once, or be able to substitute mrbgems based on configuration, without having to
add each gem to the *build_config.rb* file.  A packaged collection of mrbgems
is called a GemBox.  A GemBox is a file that contains a list of mrbgems to load
into mruby, in the same format as if you were adding them to *build_config.rb*
via `config.gem`, but wrapped in an `MRuby::GemBox` object.  GemBoxes are
loaded into mruby via `config.gembox 'boxname'`.

Below we have created a GemBox containing *mruby-time* and *mrbgems-example*:
```ruby
MRuby::GemBox.new do |conf|
  conf.gem "#{root}/mrbgems/mruby-time"
  conf.gem :github => 'masuidrive/mrbgems-example'
end
```

As mentioned, the GemBox uses the same conventions as `MRuby::Build`.  The GemBox
must be saved with a *.gembox* extension inside the *mrbgems* directory to to be
picked up by mruby.

To use this example GemBox, we save it as `custom.gembox` inside the *mrbgems*
directory in mruby, and add the following to our *build_config.rb* file inside
the build block:
```ruby
conf.gembox 'custom'
```
This will cause the *custom* GemBox to be read in during the build process,
adding *mruby-time* and *mrbgems-example* to the build.

If you want, you can put GemBox outside of mruby directory. In that case you must
specify an absolute path like below.
```ruby
conf.gembox "#{ENV["HOME"]}/mygemboxes/custom"
```

There are two GemBoxes that ship with mruby: [default](../../mrbgems/default.gembox)
and [full-core](../../mrbgems/full-core.gembox). The [default](../../mrbgems/default.gembox) GemBox
contains several core components of mruby, and [full-core](../../mrbgems/full-core.gembox)
contains every gem found in the *mrbgems* directory.

## GEM Structure

The maximal GEM structure looks like this:

	+- GEM_NAME         <- Name of GEM
	   |
	   +- include/      <- Header for Ruby extension (will exported)
	   |
	   +- mrblib/       <- Source for Ruby extension
	   |
	   +- src/          <- Source for C extension
	   |
	   +- test/         <- Test code (Ruby)
	   |
	   +- mrbgem.rake   <- GEM Specification
	   |
	   +- README.md     <- Readme for GEM

The folder *mrblib* contains pure Ruby files to extend mruby. The folder *src*
contains C/C++ files to extend mruby. The folder *include* contains C/C++ header
files. The folder *test* contains C/C++ and pure Ruby files for testing purposes
which will be used by `mrbtest`. *mrbgem.rake* contains the specification
to compile C and Ruby files. *README.md* is a short description of your GEM.

## Build process

mrbgems expects a specification file called *mrbgem.rake* inside of your
GEM directory. A typical GEM specification could look like this for example:
```ruby
MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec|
  spec.license = 'MIT'
  spec.author  = 'mruby developers'
  spec.summary = 'Example mrbgem using C and ruby'
end
```

The mrbgems build process will use this specification to compile Object and Ruby
files. The compilation results will be added to *lib/libmruby.a*. This file exposes
the GEM functionality to tools like `mruby` and `mirb`.

The following properties can be set inside of your `MRuby::Gem::Specification` for
information purpose:

* `spec.license` or `spec.licenses` (A single license or a list of them under which this GEM is licensed)
* `spec.author` or `spec.authors` (Developer name or a list of them)
* `spec.version` (Current version)
* `spec.description` (Detailed description)
* `spec.summary`
  * One line short description of mrbgem.
  * Printed in build summary of rake when set.
* `spec.homepage` (Homepage)
* `spec.requirements` (External requirements as information for user)

The `license` and `author` properties are required in every GEM!

In case your GEM is depending on other GEMs please use
`spec.add_dependency(gem, *requirements[, default_get_info])` like:
```ruby
MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec|
  spec.license = 'MIT'
  spec.author  = 'mruby developers'

  # Add GEM dependency mruby-parser.
  # The version must be between 1.0.0 and 1.5.2 .
  spec.add_dependency('mruby-parser', '>= 1.0.0', '<= 1.5.2')

  # Use any version of mruby-uv from github.
  spec.add_dependency('mruby-uv', '>= 0.0.0', :github => 'mattn/mruby-uv')

  # Use latest mruby-onig-regexp from github. (version requirements can be omitted)
  spec.add_dependency('mruby-onig-regexp', :github => 'mattn/mruby-onig-regexp')

  # You can add extra mgems active only on test
  spec.add_test_dependency('mruby-process', :github => 'iij/mruby-process')
end
```

The version requirements and default gem information are optional.

Version requirement supports following operators:
* '=': is equal
* '!=': is not equal
* '>': is greater
* '<': is lesser
* '>=': is equal or greater
* '<=': is equal or lesser
* '~>': is equal or greater and is lesser than the next major version
    * example 1: '~> 2.2.2' means '>= 2.2.2' and '< 2.3.0'
    * example 2: '~> 2.2'   means '>= 2.2.0' and '< 3.0.0'

When more than one version requirements is passed, the dependency must satisfy all of it.

You can have default gem to use as depedency when it's not defined in *build_config.rb*.
When the last argument of `add_dependency` call is `Hash`, it will be treated as default gem information.
Its format is same as argument of method `MRuby::Build#gem`, expect that it can't be treated as path gem location.

When a special version of depedency is required,
use `MRuby::Build#gem` in *build_config.rb* to override default gem.

If you have conflicting GEMs use the following method:
* `spec.add_conflict(gem, *requirements)`
    * The `requirements` argument is same as in `add_dependency` method.

like following code:
```ruby
MRuby::Gem::Specification.new 'some-regexp-binding' do |spec|
  spec.license = 'BSD'
  spec.author = 'John Doe'

  spec.add_conflict 'mruby-onig-regexp', '> 0.0.0'
  spec.add_conflict 'mruby-hs-regexp'
  spec.add_conflict 'mruby-pcre-regexp'
  spec.add_conflict 'mruby-regexp-pcre'
end
```

In case your GEM has more complex build requirements you can use
the following options additionally inside of your GEM specification:

* `spec.cc.flags` (C compiler flags)
* `spec.cc.defines` (C compiler defines)
* `spec.cc.include_paths` (C compiler include paths)
* `spec.linker.flags` (Linker flags)
* `spec.linker.libraries` (Linker libraries)
* `spec.linker.library_paths` (Linker additional library path)
* `spec.bins` (Generate binary file)
* `spec.rbfiles` (Ruby files to compile)
* `spec.objs` (Object files to compile)
* `spec.test_rbfiles` (Ruby test files for integration into mrbtest)
* `spec.test_objs` (Object test files for integration into mrbtest)
* `spec.test_preload` (Initialization files for mrbtest)

You also can use `spec.mruby.cc` and `spec.mruby.linker` to add extra global parameters for compiler and linker.

### include_paths and dependency

Your GEM can export include paths to another GEMs that depends on your GEM.
By default, `/...absolute path.../{GEM_NAME}/include` will be exported.
So it is recommended not to put GEM's local header files on include/.

These exports are retroactive.
For example: when B depends to C and A depends to B, A will get include paths exported by C.

Exported include_paths are automatically appended to GEM local include_paths by Minirake.
You can use `spec.export_include_paths` accessor if you want more complex build.


## C Extension

mruby can be extended with C. This is possible by using the C API to
integrate C libraries into mruby.

### Preconditions

mrbgems expects that you have implemented a C method called
`mrb_YOURGEMNAME_gem_init(mrb_state)`. `YOURGEMNAME` will be replaced
by the name of your GEM. If you call your GEM *c_extension_example*, your
initialisation method could look like this:
```C
void
mrb_c_extension_example_gem_init(mrb_state* mrb) {
  struct RClass *class_cextension = mrb_define_module(mrb, "CExtension");
  mrb_define_class_method(mrb, class_cextension, "c_method", mrb_c_method, MRB_ARGS_NONE());
}
```

### Finalize

mrbgems expects that you have implemented a C method called
`mrb_YOURGEMNAME_gem_final(mrb_state)`. `YOURGEMNAME` will be replaced
by the name of your GEM. If you call your GEM *c_extension_example*, your
finalizer method could look like this:

```C
void
mrb_c_extension_example_gem_final(mrb_state* mrb) {
  free(someone);
}
```

### Example

	+- c_extension_example/
	   |
	   +- src/
	   |  |
	   |  +- example.c         <- C extension source
	   |
	   +- test/
	   |  |
	   |  +- example.rb        <- Test code for C extension
	   |
	   +- mrbgem.rake          <- GEM specification
	   |
	   +- README.md

## Ruby Extension

mruby can be extended with pure Ruby. It is possible to override existing
classes or add new ones in this way. Put all Ruby files into the *mrblib*
folder.


### Pre-Conditions

none

### Example

	+- ruby_extension_example/
	   |
	   +- mrblib/
	   |  |
	   |  +- example.rb        <- Ruby extension source
	   |
	   +- test/
	   |  |
	   |  +- example.rb        <- Test code for Ruby extension
	   |
	   +- mrbgem.rake          <- GEM specification
	   |
	   +- README.md

## C and Ruby Extension

mruby can be extended with C and Ruby at the same time. It is possible to
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.

mruby codes under *mrblib* directory would be executed after gem init C
function is called. Make sure *mruby script* depends on *C code* and
*C code* doesn't depend on *mruby script*.

### Pre-Conditions

See C and Ruby example.

### Example

	+- c_and_ruby_extension_example/
	   |
	   +- mrblib/
	   |  |
	   |  +- example.rb        <- Ruby extension source
	   |
	   +- src/
	   |  |
	   |  +- example.c         <- C extension source
	   |
	   +- test/
	   |  |
	   |  +- example.rb        <- Test code for C and Ruby extension
	   |
	   +- mrbgem.rake          <- GEM specification
	   |
	   +- README.md