mini_racer 0.1.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.dockerignore +12 -0
- data/.github/workflows/ci.yml +78 -0
- data/.gitignore +2 -0
- data/.travis.yml +18 -11
- data/CHANGELOG +230 -2
- data/Dockerfile +21 -0
- data/LICENSE.txt +1 -1
- data/README.md +325 -23
- data/Rakefile +42 -0
- data/ext/mini_racer_extension/extconf.rb +47 -8
- data/ext/mini_racer_extension/mini_racer_extension.cc +1631 -264
- data/ext/mini_racer_loader/extconf.rb +8 -0
- data/ext/mini_racer_loader/mini_racer_loader.c +123 -0
- data/lib/mini_racer/version.rb +4 -1
- data/lib/mini_racer.rb +385 -16
- data/mini_racer.gemspec +14 -8
- metadata +42 -19
data/README.md
CHANGED
@@ -1,14 +1,20 @@
|
|
1
1
|
# MiniRacer
|
2
2
|
|
3
|
-
[![Build Status](https://travis-ci.org/
|
3
|
+
[![Build Status](https://travis-ci.org/rubyjs/mini_racer.svg?branch=master)](https://travis-ci.org/rubyjs/mini_racer)
|
4
4
|
|
5
5
|
Minimal, modern embedded V8 for Ruby.
|
6
6
|
|
7
7
|
MiniRacer provides a minimal two way bridge between the V8 JavaScript engine and Ruby.
|
8
8
|
|
9
|
-
It was created as an alternative to the excellent [therubyracer](https://github.com/cowboyd/therubyracer). Unlike therubyracer, mini_racer only implements a minimal bridge. This reduces the surface area making upgrading v8 much simpler and
|
9
|
+
It was created as an alternative to the excellent [therubyracer](https://github.com/cowboyd/therubyracer). Unlike therubyracer, mini_racer only implements a minimal bridge. This reduces the surface area making upgrading v8 much simpler and exhaustive testing simpler.
|
10
10
|
|
11
|
-
MiniRacer has an adapter for [execjs](https://github.com/
|
11
|
+
MiniRacer has an adapter for [execjs](https://github.com/rails/execjs) so it can be used directly with Rails projects to minify assets, run babel or compile CoffeeScript.
|
12
|
+
|
13
|
+
### A note about Ruby version Support
|
14
|
+
|
15
|
+
MiniRacer only supports non-EOL versions of Ruby. See [Ruby](https://www.ruby-lang.org/en/downloads) to see the list of non-EOL Rubies.
|
16
|
+
|
17
|
+
If you require support for older versions of Ruby install an older version of the gem.
|
12
18
|
|
13
19
|
## Features
|
14
20
|
|
@@ -29,11 +35,18 @@ You can attach one or many ruby proc that can be accessed via JavaScript
|
|
29
35
|
|
30
36
|
```ruby
|
31
37
|
context = MiniRacer::Context.new
|
32
|
-
context.attach("adder", proc{|a,b| a+b})
|
33
|
-
puts context.eval 'adder(20,22)'
|
38
|
+
context.attach("math.adder", proc{|a,b| a+b})
|
39
|
+
puts context.eval 'math.adder(20,22)'
|
34
40
|
# => 42
|
35
41
|
```
|
36
42
|
|
43
|
+
```ruby
|
44
|
+
context = MiniRacer::Context.new
|
45
|
+
context.attach("array_and_hash", proc{{a: 1, b: [1, {a: 1}]}})
|
46
|
+
puts context.eval 'array_and_hash()'
|
47
|
+
# => {"a" => 1, "b" => [1, {"a" => 1}]}
|
48
|
+
```
|
49
|
+
|
37
50
|
### GIL free JavaScript execution
|
38
51
|
|
39
52
|
The Ruby Global interpreter lock is released when scripts are executing
|
@@ -61,6 +74,64 @@ context.eval 'while(true){}'
|
|
61
74
|
# => exception is raised
|
62
75
|
```
|
63
76
|
|
77
|
+
### Memory softlimit support
|
78
|
+
|
79
|
+
Contexts can specify a memory softlimit for scripts
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
# terminates script if heap usage exceeds 200mb after V8 garbage collection has run
|
83
|
+
context = MiniRacer::Context.new(max_memory: 200000000)
|
84
|
+
context.eval 'var a = new Array(10000); while(true) {a = a.concat(new Array(10000)); print("loop " + a.length);}'
|
85
|
+
# => V8OutOfMemoryError is raised
|
86
|
+
```
|
87
|
+
|
88
|
+
### Object marshal max stackdepth support
|
89
|
+
|
90
|
+
Contexts can specify a stack depth limit for object marshalling. Max depth is unbounded by default.
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
# terminates script if stack depth exceeds max during marshal
|
94
|
+
context = MiniRacer::Context.new(marshal_stack_depth: 500)
|
95
|
+
context.attach("a", proc{|a| a})
|
96
|
+
|
97
|
+
context.eval("let arr = []; arr.push(arr); a(arr)")
|
98
|
+
# => RuntimeError is raised
|
99
|
+
```
|
100
|
+
|
101
|
+
### Rich debugging with "filename" support
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
|
105
|
+
context = MiniRacer::Context.new
|
106
|
+
context.eval('var foo = function() {bar();}', filename: 'a/foo.js')
|
107
|
+
context.eval('bar()', filename: 'a/bar.js')
|
108
|
+
|
109
|
+
# MiniRacer::RuntimeError is raised containing the filenames you specified for evals in backtrace
|
110
|
+
|
111
|
+
```
|
112
|
+
|
113
|
+
### Fork safety
|
114
|
+
|
115
|
+
Some Ruby web servers employ forking (for example unicorn or puma in clustered mode). V8 is not fork safe.
|
116
|
+
Sadly Ruby does not have support for fork notifications per [#5446](https://bugs.ruby-lang.org/issues/5446).
|
117
|
+
|
118
|
+
If you want to ensure your application does not leak memory after fork either:
|
119
|
+
|
120
|
+
1. Ensure no MiniRacer::Context objects are created in the master process
|
121
|
+
|
122
|
+
Or
|
123
|
+
|
124
|
+
2. Dispose manually of all MiniRacer::Context objects prior to forking
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
# before fork
|
128
|
+
|
129
|
+
require 'objspace'
|
130
|
+
ObjectSpace.each_object(MiniRacer::Context){|c| c.dispose}
|
131
|
+
|
132
|
+
# fork here
|
133
|
+
```
|
134
|
+
|
64
135
|
### Threadsafe
|
65
136
|
|
66
137
|
Context usage is threadsafe
|
@@ -81,28 +152,239 @@ puts context.eval("counter")
|
|
81
152
|
|
82
153
|
```
|
83
154
|
|
155
|
+
### Snapshots
|
156
|
+
|
157
|
+
Contexts can be created with pre-loaded snapshots:
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
|
161
|
+
snapshot = MiniRacer::Snapshot.new('function hello() { return "world!"; }')
|
162
|
+
|
163
|
+
context = MiniRacer::Context.new(snapshot: snapshot)
|
164
|
+
|
165
|
+
context.eval("hello()")
|
166
|
+
# => "world!"
|
167
|
+
|
168
|
+
```
|
169
|
+
|
170
|
+
Snapshots can come in handy for example if you want your contexts to be pre-loaded for effiency. It uses [V8 snapshots](http://v8project.blogspot.com/2015/09/custom-startup-snapshots.html) under the hood; see [this link](http://v8project.blogspot.com/2015/09/custom-startup-snapshots.html) for caveats using these, in particular:
|
171
|
+
|
172
|
+
```
|
173
|
+
There is an important limitation to snapshots: they can only capture V8’s
|
174
|
+
heap. Any interaction from V8 with the outside is off-limits when creating the
|
175
|
+
snapshot. Such interactions include:
|
176
|
+
|
177
|
+
* defining and calling API callbacks (i.e. functions created via v8::FunctionTemplate)
|
178
|
+
* creating typed arrays, since the backing store may be allocated outside of V8
|
179
|
+
|
180
|
+
And of course, values derived from sources such as `Math.random` or `Date.now`
|
181
|
+
are fixed once the snapshot has been captured. They are no longer really random
|
182
|
+
nor reflect the current time.
|
183
|
+
```
|
184
|
+
|
185
|
+
Also note that snapshots can be warmed up, using the `warmup!` method, which allows you to call functions which are otherwise lazily compiled to get them to compile right away; any side effect of your warm up code being then dismissed. [More details on warming up here](https://github.com/electron/electron/issues/169#issuecomment-76783481), and a small example:
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
|
189
|
+
snapshot = MiniRacer::Snapshot.new('var counter = 0; function hello() { counter++; return "world! "; }')
|
190
|
+
|
191
|
+
snapshot.warmup!('hello()')
|
192
|
+
|
193
|
+
context = MiniRacer::Context.new(snapshot: snapshot)
|
194
|
+
|
195
|
+
context.eval('hello()')
|
196
|
+
# => "world! 1"
|
197
|
+
context.eval('counter')
|
198
|
+
# => 1
|
199
|
+
|
200
|
+
```
|
201
|
+
|
202
|
+
### Shared isolates
|
203
|
+
|
204
|
+
By default, MiniRacer's contexts each have their own isolate (V8 runtime). For efficiency, it is possible to re-use an isolate across contexts:
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
|
208
|
+
isolate = MiniRacer::Isolate.new
|
209
|
+
|
210
|
+
context1 = MiniRacer::Context.new(isolate: isolate)
|
211
|
+
context2 = MiniRacer::Context.new(isolate: isolate)
|
212
|
+
|
213
|
+
context1.isolate == context2.isolate
|
214
|
+
# => true
|
215
|
+
```
|
216
|
+
|
217
|
+
The main benefit of this is avoiding creating/destroying isolates when not needed (for example if you use a lot of contexts).
|
218
|
+
|
219
|
+
The caveat with this is that a given isolate can only execute one context at a time, so don't share isolates across contexts that you want to run concurrently.
|
220
|
+
|
221
|
+
Also, note that if you want to use shared isolates together with snapshots, you need to first create an isolate with that snapshot, and then create contexts from that isolate:
|
222
|
+
|
223
|
+
```ruby
|
224
|
+
snapshot = MiniRacer::Snapshot.new('function hello() { return "world!"; }')
|
225
|
+
|
226
|
+
isolate = MiniRacer::Isolate.new(snapshot)
|
227
|
+
|
228
|
+
context = MiniRacer::Context.new(isolate: isolate)
|
229
|
+
|
230
|
+
context.eval("hello()")
|
231
|
+
# => "world!"
|
232
|
+
```
|
233
|
+
|
234
|
+
Re-using the same isolate over and over again means V8's garbage collector will have to run to clean it up every now and then; it's possible to trigger a _blocking_ V8 GC run inside your isolate by running the `idle_notification` method on it, which takes a single argument: the amount of time (in milliseconds) that V8 should use at most for garbage collecting:
|
235
|
+
|
236
|
+
```ruby
|
237
|
+
isolate = MiniRacer::Isolate.new
|
238
|
+
|
239
|
+
context = MiniRacer::Context.new(isolate: isolate)
|
240
|
+
|
241
|
+
# do stuff with that context...
|
242
|
+
|
243
|
+
# give up to 100ms for V8 garbage collection
|
244
|
+
isolate.idle_notification(100)
|
245
|
+
|
246
|
+
# force V8 to perform a full GC
|
247
|
+
isolate.low_memory_notification
|
248
|
+
|
249
|
+
```
|
250
|
+
|
251
|
+
This can come in handy to force V8 GC runs for example in between requests if you use MiniRacer on a web application.
|
252
|
+
|
253
|
+
Note that this method maps directly to [`v8::Isolate::IdleNotification`](http://bespin.cz/~ondras/html/classv8_1_1Isolate.html#aea16cbb2e351de9a3ae7be2b7cb48297), and that in particular its return value is the same (true if there is no further garbage to collect, false otherwise) and the same caveats apply, in particular that `there is no guarantee that the [call will return] within the time limit.`
|
254
|
+
|
255
|
+
Additionally you may automate this process on a context by defining it with `MiniRacer::Content.new(ensure_gc_after_idle: 1000)`. Using this will ensure V8 will run a full GC using `context.isolate.low_memory_notification` 1 second after the last eval on the context. Low memory notification is both slower and more aggressive than an idle_notification and will ensure long living isolates use minimal amounts of memory.
|
256
|
+
|
257
|
+
### V8 Runtime flags
|
258
|
+
|
259
|
+
It is possible to set V8 Runtime flags:
|
260
|
+
|
261
|
+
```ruby
|
262
|
+
MiniRacer::Platform.set_flags! :noconcurrent_recompilation, max_inlining_levels: 10
|
263
|
+
```
|
264
|
+
|
265
|
+
This can come in handy if you want to use MiniRacer with Unicorn, which doesn't seem to always appreciate V8's liberal use of threading:
|
266
|
+
```ruby
|
267
|
+
MiniRacer::Platform.set_flags! :noconcurrent_recompilation, :noconcurrent_sweeping
|
268
|
+
```
|
269
|
+
|
270
|
+
Or else to unlock experimental features in V8, for example tail recursion optimization:
|
271
|
+
```ruby
|
272
|
+
MiniRacer::Platform.set_flags! :harmony
|
273
|
+
|
274
|
+
js = <<-JS
|
275
|
+
'use strict';
|
276
|
+
var f = function f(n){
|
277
|
+
if (n <= 0) {
|
278
|
+
return 'foo';
|
279
|
+
}
|
280
|
+
return f(n - 1);
|
281
|
+
}
|
282
|
+
|
283
|
+
f(1e6);
|
284
|
+
JS
|
285
|
+
|
286
|
+
context = MiniRacer::Context.new
|
287
|
+
|
288
|
+
context.eval js
|
289
|
+
# => "foo"
|
290
|
+
```
|
291
|
+
The same code without the harmony runtime flag results in a `MiniRacer::RuntimeError: RangeError: Maximum call stack size exceeded` exception.
|
292
|
+
Please refer to http://node.green/ as a reference on other harmony features.
|
293
|
+
|
294
|
+
A list of all V8 runtime flags can be found using `node --v8-options`, or else by perusing [the V8 source code for flags (make sure to use the right version of V8)](https://github.com/v8/v8/blob/master/src/flags/flag-definitions.h).
|
295
|
+
|
296
|
+
Note that runtime flags must be set before any other operation (e.g. creating a context, a snapshot or an isolate), otherwise an exception will be thrown.
|
297
|
+
|
298
|
+
Flags:
|
299
|
+
|
300
|
+
- :expose_gc : Will expose `gc()` which you can run in JavaScript to issue a gc
|
301
|
+
- :max_old_space_size : defaults to 1400 (megs) on 64 bit, you can restric memory usage by limiting this.
|
302
|
+
- **NOTE TO READER** our documentation could be awesome we could be properly documenting all the flags, they are hugely useful, if you feel like documenting a few more, PLEASE DO, PRs are welcome.
|
303
|
+
|
304
|
+
## Controlling memory
|
305
|
+
|
306
|
+
When hosting v8 you may want to keep track of memory usage, use #heap_stats to get memory usage:
|
307
|
+
|
308
|
+
```ruby
|
309
|
+
context = MiniRacer::Context.new(timeout: 5)
|
310
|
+
context.eval("let a='testing';")
|
311
|
+
p context.heap_stats
|
312
|
+
# {:total_physical_size=>1280640,
|
313
|
+
# :total_heap_size_executable=>4194304,
|
314
|
+
# :total_heap_size=>3100672,
|
315
|
+
# :used_heap_size=>1205376,
|
316
|
+
# :heap_size_limit=>1501560832}
|
317
|
+
```
|
318
|
+
|
319
|
+
If you wish to dispose of a context before waiting on the GC use
|
320
|
+
|
321
|
+
```ruby
|
322
|
+
context = MiniRacer::Context.new(timeout: 5)
|
323
|
+
context.eval("let a='testing';")
|
324
|
+
context.dispose
|
325
|
+
context.eval("a = 2")
|
326
|
+
# MiniRacer::ContextDisposedError
|
327
|
+
|
328
|
+
# nothing works on the context from now on, its a shell waiting to be disposed
|
329
|
+
```
|
330
|
+
|
331
|
+
A MiniRacer context can also be dumped in a heapsnapshot file using `#write_heap_snapshot(file_or_io)`
|
332
|
+
|
333
|
+
```ruby
|
334
|
+
context = MiniRacer::Context.new(timeout: 5)
|
335
|
+
context.eval("let a='testing';")
|
336
|
+
context.write_heap_snapshot("test.heapsnapshot")
|
337
|
+
```
|
338
|
+
|
339
|
+
This file can then be loaded in the memory tab of the chrome dev console.
|
340
|
+
|
341
|
+
### Function call
|
342
|
+
|
343
|
+
This calls the function passed as first argument:
|
344
|
+
|
345
|
+
```ruby
|
346
|
+
context = MiniRacer::Context.new
|
347
|
+
context.eval('function hello(name) { return "Hello, " + name + "!" }')
|
348
|
+
context.call('hello', 'George')
|
349
|
+
# "Hello, George!"
|
350
|
+
```
|
351
|
+
|
352
|
+
Performance is slightly better than running `eval('hello("George")')` since:
|
353
|
+
|
354
|
+
- compilation of eval'd string is avoided
|
355
|
+
- function arguments don't need to be converted to JSON
|
356
|
+
|
84
357
|
## Performance
|
85
358
|
|
86
359
|
The `bench` folder contains benchmark.
|
87
360
|
|
88
361
|
### Benchmark minification of Discourse application.js (both minified and unminified)
|
89
362
|
|
90
|
-
|
363
|
+
MiniRacer outperforms node when minifying assets via execjs.
|
364
|
+
|
365
|
+
- MiniRacer version 0.1.9
|
366
|
+
- node version 6.10
|
91
367
|
- therubyracer version 0.12.2
|
92
368
|
|
93
|
-
```
|
94
|
-
$ ruby bench_uglify.rb
|
95
|
-
Benching with MiniRacer
|
96
|
-
MiniRacer minify discourse_app.js 13813.36ms
|
97
|
-
MiniRacer minify discourse_app_minified.js 18271.19ms
|
98
|
-
MiniRacer minify discourse_app.js twice (2 threads) 13587.21ms
|
99
369
|
```
|
100
370
|
|
101
|
-
|
371
|
+
$ bundle exec ruby bench.rb mini_racer
|
372
|
+
Benching with mini_racer
|
373
|
+
mini_racer minify discourse_app.js 9292.72063ms
|
374
|
+
mini_racer minify discourse_app_minified.js 11799.850171ms
|
375
|
+
mini_racer minify discourse_app.js twice (2 threads) 10269.570797ms
|
376
|
+
|
377
|
+
sam@ubuntu exec_js_uglify % bundle exec ruby bench.rb node
|
378
|
+
Benching with node
|
379
|
+
node minify discourse_app.js 13302.715484ms
|
380
|
+
node minify discourse_app_minified.js 18100.761243ms
|
381
|
+
node minify discourse_app.js twice (2 threads) 14383.600207000001ms
|
382
|
+
|
383
|
+
sam@ubuntu exec_js_uglify % bundle exec ruby bench.rb therubyracer
|
102
384
|
Benching with therubyracer
|
103
|
-
|
104
|
-
|
105
|
-
|
385
|
+
therubyracer minify discourse_app.js 171683.01867700001ms
|
386
|
+
therubyracer minify discourse_app_minified.js 143138.88492ms
|
387
|
+
therubyracer minify discourse_app.js twice (2 threads) NEVER FINISH
|
106
388
|
|
107
389
|
Killed: 9
|
108
390
|
```
|
@@ -111,6 +393,12 @@ The huge performance disparity (MiniRacer is 10x faster) is due to MiniRacer run
|
|
111
393
|
|
112
394
|
Note how the global interpreter lock release leads to 2 threads doing the same work taking the same wall time as 1 thread.
|
113
395
|
|
396
|
+
As a rule MiniRacer strives to always support and depend on the latest stable version of libv8.
|
397
|
+
|
398
|
+
## Source Maps
|
399
|
+
|
400
|
+
MiniRacer can fully support source maps but must be configured correctly to do so. [Check out this example](./examples/source-map-support/) for a working implementation.
|
401
|
+
|
114
402
|
## Installation
|
115
403
|
|
116
404
|
Add this line to your application's Gemfile:
|
@@ -128,18 +416,32 @@ Or install it yourself as:
|
|
128
416
|
$ gem install mini_racer
|
129
417
|
|
130
418
|
|
131
|
-
**Note** using v8.h and compiling MiniRacer requires a C++11 standard compiler, more specifically clang 3.5 (or later) or
|
419
|
+
**Note** using v8.h and compiling MiniRacer requires a C++11 standard compiler, more specifically clang 3.5 (or later) or GCC 6.3 (or later).
|
420
|
+
|
421
|
+
|
422
|
+
## Travis-ci
|
423
|
+
|
424
|
+
To install `mini-racer` you will need a version of GCC that supports C++11 (GCC 6.3) this is included by default in ubuntu trusty based images.
|
425
|
+
|
426
|
+
Travis today ships by default with a precise based image. Precise Pangolin (12.04 LTS) was first released in August 2012. Even though you can install GCC 6.3 on precise the simpler approach is to opt for the trusty based image.
|
427
|
+
|
428
|
+
Add this to your .travis.yml file:
|
429
|
+
|
430
|
+
```
|
431
|
+
- sudo: required
|
432
|
+
- dist: trusty
|
433
|
+
```
|
132
434
|
|
133
435
|
## Similar Projects
|
134
436
|
|
135
|
-
###therubyracer
|
437
|
+
### therubyracer
|
136
438
|
|
137
439
|
- https://github.com/cowboyd/therubyracer
|
138
440
|
- Most comprehensive bridge available
|
139
441
|
- Provides the ability to "eval" JavaScript
|
140
442
|
- Provides the ability to invoke Ruby code from JavaScript
|
141
|
-
- Hold
|
142
|
-
- Hold
|
443
|
+
- Hold references to JavaScript objects and methods in your Ruby code
|
444
|
+
- Hold references to Ruby objects and methods in JavaScript code
|
143
445
|
- Uses libv8, so installation is fast
|
144
446
|
- Supports timeouts for JavaScript execution
|
145
447
|
- Does not release global interpreter lock, so performance is constrained to a single thread
|
@@ -147,7 +449,7 @@ Or install it yourself as:
|
|
147
449
|
- Supports execjs
|
148
450
|
|
149
451
|
|
150
|
-
###v8eval
|
452
|
+
### v8eval
|
151
453
|
|
152
454
|
- https://github.com/sony/v8eval
|
153
455
|
- Provides the ability to "eval" JavaScript using the latest V8 engine
|
@@ -160,7 +462,7 @@ Or install it yourself as:
|
|
160
462
|
- No support for execjs (can not be used with Rails uglifier and coffeescript gems)
|
161
463
|
|
162
464
|
|
163
|
-
###therubyrhino
|
465
|
+
### therubyrhino
|
164
466
|
|
165
467
|
- https://github.com/cowboyd/therubyrhino
|
166
468
|
- API compatible with therubyracer
|
@@ -173,7 +475,7 @@ Or install it yourself as:
|
|
173
475
|
|
174
476
|
## Contributing
|
175
477
|
|
176
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
478
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/rubyjs/mini_racer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
177
479
|
|
178
480
|
|
179
481
|
## License
|
data/Rakefile
CHANGED
@@ -11,11 +11,28 @@ end
|
|
11
11
|
task :default => [:compile, :test]
|
12
12
|
|
13
13
|
gem = Gem::Specification.load( File.dirname(__FILE__) + '/mini_racer.gemspec' )
|
14
|
+
Rake::ExtensionTask.new( 'mini_racer_loader', gem )
|
14
15
|
Rake::ExtensionTask.new( 'mini_racer_extension', gem )
|
15
16
|
|
16
17
|
|
17
18
|
# via http://blog.flavorjon.es/2009/06/easily-valgrind-gdb-your-ruby-c.html
|
18
19
|
namespace :test do
|
20
|
+
desc "run test suite with Address Sanitizer"
|
21
|
+
task :asan do
|
22
|
+
ENV["CONFIGURE_ARGS"] = [ENV["CONFIGURE_ARGS"], '--enable-asan'].compact.join(' ')
|
23
|
+
Rake::Task['compile'].invoke
|
24
|
+
|
25
|
+
asan_path = `ldconfig -N -p |grep libasan | grep -v 32 | sed 's/.* => \\(.*\\)$/\\1/'`.chomp.split("\n")[-1]
|
26
|
+
|
27
|
+
|
28
|
+
cmdline = "env LD_PRELOAD=\"#{asan_path}\" ruby test/test_leak.rb"
|
29
|
+
puts cmdline
|
30
|
+
system cmdline
|
31
|
+
|
32
|
+
cmdline = "env LD_PRELOAD=\"#{asan_path}\" rake test"
|
33
|
+
puts cmdline
|
34
|
+
system cmdline
|
35
|
+
end
|
19
36
|
# partial-loads-ok and undef-value-errors necessary to ignore
|
20
37
|
# spurious (and eminently ignorable) warnings from the ruby
|
21
38
|
# interpreter
|
@@ -52,3 +69,28 @@ namespace :test do
|
|
52
69
|
end
|
53
70
|
end
|
54
71
|
end
|
72
|
+
|
73
|
+
desc 'run clang-tidy linter on mini_racer_extension.cc'
|
74
|
+
task :lint do
|
75
|
+
require 'mkmf'
|
76
|
+
require 'libv8'
|
77
|
+
|
78
|
+
Libv8.configure_makefile
|
79
|
+
|
80
|
+
conf = RbConfig::CONFIG.merge('hdrdir' => $hdrdir.quote, 'srcdir' => $srcdir.quote,
|
81
|
+
'arch_hdrdir' => $arch_hdrdir.quote,
|
82
|
+
'top_srcdir' => $top_srcdir.quote)
|
83
|
+
if $universal and (arch_flag = conf['ARCH_FLAG']) and !arch_flag.empty?
|
84
|
+
conf['ARCH_FLAG'] = arch_flag.gsub(/(?:\G|\s)-arch\s+\S+/, '')
|
85
|
+
end
|
86
|
+
|
87
|
+
checks = %W(bugprone-*
|
88
|
+
cert-*
|
89
|
+
cppcoreguidelines-*
|
90
|
+
clang-analyzer-*
|
91
|
+
performance-*
|
92
|
+
portability-*
|
93
|
+
readability-*).join(',')
|
94
|
+
|
95
|
+
sh RbConfig::expand("clang-tidy -checks='#{checks}' ext/mini_racer_extension/mini_racer_extension.cc -- #$INCFLAGS #$CPPFLAGS", conf)
|
96
|
+
end
|
@@ -1,32 +1,71 @@
|
|
1
1
|
require 'mkmf'
|
2
|
-
|
2
|
+
require_relative '../../lib/mini_racer/version'
|
3
|
+
gem 'libv8-node', MiniRacer::LIBV8_NODE_VERSION
|
4
|
+
require 'libv8-node'
|
5
|
+
|
6
|
+
IS_DARWIN = RUBY_PLATFORM =~ /darwin/
|
3
7
|
|
4
8
|
have_library('pthread')
|
5
|
-
have_library('objc') if
|
9
|
+
have_library('objc') if IS_DARWIN
|
6
10
|
$CPPFLAGS += " -Wall" unless $CPPFLAGS.split.include? "-Wall"
|
7
11
|
$CPPFLAGS += " -g" unless $CPPFLAGS.split.include? "-g"
|
8
12
|
$CPPFLAGS += " -rdynamic" unless $CPPFLAGS.split.include? "-rdynamic"
|
9
|
-
$CPPFLAGS += " -fPIC" unless $CPPFLAGS.split.include? "-rdynamic" or
|
10
|
-
$CPPFLAGS += " -std=c++
|
13
|
+
$CPPFLAGS += " -fPIC" unless $CPPFLAGS.split.include? "-rdynamic" or IS_DARWIN
|
14
|
+
$CPPFLAGS += " -std=c++14"
|
11
15
|
$CPPFLAGS += " -fpermissive"
|
16
|
+
#$CPPFLAGS += " -DV8_COMPRESS_POINTERS"
|
17
|
+
$CPPFLAGS += " -fvisibility=hidden "
|
18
|
+
|
19
|
+
$CPPFLAGS += " -Wno-reserved-user-defined-literal" if IS_DARWIN
|
12
20
|
|
13
|
-
$LDFLAGS.insert
|
21
|
+
$LDFLAGS.insert(0, " -stdlib=libc++ ") if IS_DARWIN
|
22
|
+
|
23
|
+
# check for missing symbols at link time
|
24
|
+
# $LDFLAGS += " -Wl,--no-undefined " unless IS_DARWIN
|
25
|
+
# $LDFLAGS += " -Wl,-undefined,error " if IS_DARWIN
|
14
26
|
|
15
27
|
if ENV['CXX']
|
16
28
|
puts "SETTING CXX"
|
17
29
|
CONFIG['CXX'] = ENV['CXX']
|
18
30
|
end
|
19
31
|
|
20
|
-
|
32
|
+
CXX11_TEST = <<EOS
|
33
|
+
#if __cplusplus <= 199711L
|
34
|
+
# error A compiler that supports at least C++11 is required in order to compile this project.
|
35
|
+
#endif
|
36
|
+
EOS
|
37
|
+
|
38
|
+
`echo "#{CXX11_TEST}" | #{CONFIG['CXX']} -std=c++0x -x c++ -E -`
|
39
|
+
unless $?.success?
|
40
|
+
warn <<EOS
|
41
|
+
|
42
|
+
|
43
|
+
WARNING: C++11 support is required for compiling mini_racer. Please make sure
|
44
|
+
you are using a compiler that supports at least C++11. Examples of such
|
45
|
+
compilers are GCC 4.7+ and Clang 3.2+.
|
46
|
+
|
47
|
+
If you are using Travis, consider either migrating your build to Ubuntu Trusty or
|
48
|
+
installing GCC 4.8. See mini_racer's README.md for more information.
|
49
|
+
|
50
|
+
|
51
|
+
EOS
|
52
|
+
end
|
53
|
+
|
54
|
+
CONFIG['LDSHARED'] = '$(CXX) -shared' unless IS_DARWIN
|
21
55
|
if CONFIG['warnflags']
|
22
56
|
CONFIG['warnflags'].gsub!('-Wdeclaration-after-statement', '')
|
23
57
|
CONFIG['warnflags'].gsub!('-Wimplicit-function-declaration', '')
|
24
58
|
end
|
25
59
|
|
26
|
-
if enable_config('debug')
|
60
|
+
if enable_config('debug') || enable_config('asan')
|
27
61
|
CONFIG['debugflags'] << ' -ggdb3 -O0'
|
28
62
|
end
|
29
63
|
|
30
|
-
Libv8.configure_makefile
|
64
|
+
Libv8::Node.configure_makefile
|
65
|
+
|
66
|
+
if enable_config('asan')
|
67
|
+
$CPPFLAGS.insert(0, " -fsanitize=address ")
|
68
|
+
$LDFLAGS.insert(0, " -fsanitize=address ")
|
69
|
+
end
|
31
70
|
|
32
71
|
create_makefile 'mini_racer_extension'
|