ruby_wasm 2.5.0-arm64-darwin
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.clang-format +8 -0
- data/CONTRIBUTING.md +126 -0
- data/Gemfile +17 -0
- data/LICENSE +21 -0
- data/NOTICE +1293 -0
- data/README.md +153 -0
- data/Rakefile +163 -0
- data/Steepfile +24 -0
- data/benchmarks/vm_deep_call.rb +55 -0
- data/builders/wasm32-unknown-emscripten/Dockerfile +43 -0
- data/builders/wasm32-unknown-emscripten/entrypoint.sh +7 -0
- data/builders/wasm32-unknown-wasi/Dockerfile +47 -0
- data/builders/wasm32-unknown-wasi/entrypoint.sh +7 -0
- data/docs/api.md +2 -0
- data/docs/cheat_sheet.md +195 -0
- data/docs/faq.md +25 -0
- data/exe/rbwasm +7 -0
- data/ext/.gitignore +2 -0
- data/ext/README.md +11 -0
- data/ext/extinit.c.erb +32 -0
- data/lib/ruby_wasm/3.0/ruby_wasm.bundle +0 -0
- data/lib/ruby_wasm/3.1/ruby_wasm.bundle +0 -0
- data/lib/ruby_wasm/3.2/ruby_wasm.bundle +0 -0
- data/lib/ruby_wasm/build/build_params.rb +3 -0
- data/lib/ruby_wasm/build/downloader.rb +18 -0
- data/lib/ruby_wasm/build/executor.rb +187 -0
- data/lib/ruby_wasm/build/product/baseruby.rb +37 -0
- data/lib/ruby_wasm/build/product/crossruby.rb +330 -0
- data/lib/ruby_wasm/build/product/libyaml.rb +68 -0
- data/lib/ruby_wasm/build/product/openssl.rb +88 -0
- data/lib/ruby_wasm/build/product/product.rb +39 -0
- data/lib/ruby_wasm/build/product/ruby_source.rb +103 -0
- data/lib/ruby_wasm/build/product/wasi_vfs.rb +45 -0
- data/lib/ruby_wasm/build/product/zlib.rb +68 -0
- data/lib/ruby_wasm/build/product.rb +8 -0
- data/lib/ruby_wasm/build/toolchain/wit_bindgen.rb +31 -0
- data/lib/ruby_wasm/build/toolchain.rb +193 -0
- data/lib/ruby_wasm/build.rb +88 -0
- data/lib/ruby_wasm/cli.rb +217 -0
- data/lib/ruby_wasm/packager/core.rb +156 -0
- data/lib/ruby_wasm/packager/file_system.rb +158 -0
- data/lib/ruby_wasm/packager.rb +159 -0
- data/lib/ruby_wasm/rake_task.rb +59 -0
- data/lib/ruby_wasm/util.rb +15 -0
- data/lib/ruby_wasm/version.rb +3 -0
- data/lib/ruby_wasm.rb +33 -0
- data/package-lock.json +9500 -0
- data/package.json +12 -0
- data/rakelib/check.rake +37 -0
- data/rakelib/ci.rake +152 -0
- data/rakelib/doc.rake +29 -0
- data/rakelib/format.rake +35 -0
- data/rakelib/gem.rake +22 -0
- data/rakelib/packaging.rake +151 -0
- data/rakelib/version.rake +40 -0
- data/sig/open_uri.rbs +4 -0
- data/sig/ruby_wasm/build.rbs +318 -0
- data/sig/ruby_wasm/cli.rbs +27 -0
- data/sig/ruby_wasm/ext.rbs +13 -0
- data/sig/ruby_wasm/packager.rbs +91 -0
- data/sig/ruby_wasm/util.rbs +5 -0
- data/tools/clang-format-diff.sh +18 -0
- data/tools/exe/rbminify +12 -0
- data/tools/lib/syntax_tree/minify_ruby.rb +63 -0
- metadata +114 -0
data/docs/cheat_sheet.md
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
[[**Cheat Sheet**]](./cheat_sheet.md)
|
2
|
+
[[**FAQ**]](./faq.md)
|
3
|
+
[[**API Reference**]](./api.md)
|
4
|
+
[[**Complete Examples**]](https://github.com/ruby/ruby.wasm/tree/main/packages/npm-packages/ruby-wasm-wasi/example)
|
5
|
+
[[**Community Showcase**]](https://github.com/ruby/ruby.wasm/wiki/Showcase)
|
6
|
+
|
7
|
+
# ruby.wasm Cheat Sheet
|
8
|
+
|
9
|
+
## Node.js
|
10
|
+
|
11
|
+
To install the package, install `@ruby/3.3-wasm-wasi` and `@ruby/wasm-wasi` from npm:
|
12
|
+
|
13
|
+
```console
|
14
|
+
npm install --save @ruby/3.3-wasm-wasi @ruby/wasm-wasi
|
15
|
+
```
|
16
|
+
|
17
|
+
Then instantiate a Ruby VM by the following code:
|
18
|
+
|
19
|
+
```javascript
|
20
|
+
import fs from "fs/promises";
|
21
|
+
import { DefaultRubyVM } from "@ruby/wasm-wasi/dist/node";
|
22
|
+
|
23
|
+
const binary = await fs.readFile("./node_modules/@ruby/3.3-wasm-wasi/dist/ruby.wasm");
|
24
|
+
const module = await WebAssembly.compile(binary);
|
25
|
+
const { vm } = await DefaultRubyVM(module);
|
26
|
+
vm.eval(`puts "hello world"`);
|
27
|
+
```
|
28
|
+
|
29
|
+
Then run the example code with `--experimental-wasi-unstable-preview1` flag to enable WASI support:
|
30
|
+
|
31
|
+
```console
|
32
|
+
$ node --experimental-wasi-unstable-preview1 index.mjs
|
33
|
+
```
|
34
|
+
|
35
|
+
## Browser
|
36
|
+
|
37
|
+
The easiest way to run Ruby on browser is to use `browser.script.iife.js` script from CDN:
|
38
|
+
|
39
|
+
```html
|
40
|
+
<html>
|
41
|
+
<script src="https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.5.0/dist/browser.script.iife.js"></script>
|
42
|
+
<script type="text/ruby">
|
43
|
+
require "js"
|
44
|
+
JS.global[:document].write "Hello, world!"
|
45
|
+
</script>
|
46
|
+
</html>
|
47
|
+
```
|
48
|
+
|
49
|
+
If you want to control Ruby VM from JavaScript, you can use `@ruby/wasm-wasi` package API:
|
50
|
+
|
51
|
+
```html
|
52
|
+
<html>
|
53
|
+
<script type="module">
|
54
|
+
import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.5.0/dist/browser/+esm";
|
55
|
+
const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.5.0/dist/ruby+stdlib.wasm");
|
56
|
+
const module = await WebAssembly.compileStreaming(response);
|
57
|
+
const { vm } = await DefaultRubyVM(module);
|
58
|
+
|
59
|
+
vm.eval(`
|
60
|
+
require "js"
|
61
|
+
JS.global[:document].write "Hello, world!"
|
62
|
+
`);
|
63
|
+
</script>
|
64
|
+
</html>
|
65
|
+
```
|
66
|
+
|
67
|
+
<details>
|
68
|
+
<summary>Alternative: Without ES Modules</summary>
|
69
|
+
|
70
|
+
```html
|
71
|
+
<html>
|
72
|
+
<script src="https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.5.0/dist/browser.umd.js"></script>
|
73
|
+
<script>
|
74
|
+
const main = async () => {
|
75
|
+
const { DefaultRubyVM } = window["ruby-wasm-wasi"];
|
76
|
+
const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.5.0/dist/ruby+stdlib.wasm");
|
77
|
+
const module = await WebAssembly.compileStreaming(response);
|
78
|
+
const { vm } = await DefaultRubyVM(module);
|
79
|
+
|
80
|
+
vm.eval(`
|
81
|
+
require "js"
|
82
|
+
JS.global[:document].write "Hello, world!"
|
83
|
+
`);
|
84
|
+
}
|
85
|
+
main()
|
86
|
+
</script>
|
87
|
+
</html>
|
88
|
+
```
|
89
|
+
</details>
|
90
|
+
|
91
|
+
## Use JavaScript from Ruby
|
92
|
+
|
93
|
+
### Get/set JavaScript variables from Ruby
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
require "js"
|
97
|
+
|
98
|
+
document = JS.global[:document]
|
99
|
+
document[:title] = "Hello, world!"
|
100
|
+
```
|
101
|
+
|
102
|
+
### Call JavaScript methods from Ruby
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
require "js"
|
106
|
+
|
107
|
+
JS.global[:document].createElement("div")
|
108
|
+
|
109
|
+
JS.global[:document].call(:createElement, "div".to_js) # same as above
|
110
|
+
```
|
111
|
+
|
112
|
+
### Pass Ruby `Proc` to JavaScript (Callback to Ruby)
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
require "js"
|
116
|
+
|
117
|
+
JS.global.setTimeout(proc { puts "Hello, world!" }, 1000)
|
118
|
+
|
119
|
+
input = JS.global[:document].querySelector("input")
|
120
|
+
input.addEventListener("change") do |event|
|
121
|
+
puts event[:target][:value].to_s
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
### `await` JavaScript `Promise` from Ruby
|
126
|
+
|
127
|
+
`data-eval="async"` attribute is required to use `await` in `<script>` tag:
|
128
|
+
|
129
|
+
```html
|
130
|
+
<html>
|
131
|
+
<script src="https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.5.0/dist/browser.script.iife.js"></script>
|
132
|
+
<script type="text/ruby" data-eval="async">
|
133
|
+
require "js"
|
134
|
+
|
135
|
+
response = JS.global.fetch("https://www.ruby-lang.org/").await
|
136
|
+
puts response[:status]
|
137
|
+
</script>
|
138
|
+
</html>
|
139
|
+
```
|
140
|
+
|
141
|
+
Or using `@ruby/wasm-wasi` package API `RubyVM#evalAsync`:
|
142
|
+
|
143
|
+
```html
|
144
|
+
<html>
|
145
|
+
<script type="module">
|
146
|
+
import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.5.0/dist/browser/+esm";
|
147
|
+
const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.3-wasm-wasi@2.5.0/dist/ruby+stdlib.wasm");
|
148
|
+
const module = await WebAssembly.compileStreaming(response);
|
149
|
+
const { vm } = await DefaultRubyVM(module);
|
150
|
+
|
151
|
+
vm.evalAsync(`
|
152
|
+
require "js"
|
153
|
+
|
154
|
+
response = JS.global.fetch("https://www.ruby-lang.org/").await
|
155
|
+
puts response[:status]
|
156
|
+
`);
|
157
|
+
</script>
|
158
|
+
</html>
|
159
|
+
```
|
160
|
+
|
161
|
+
### `new` JavaScript instance from Ruby
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
require "js"
|
165
|
+
|
166
|
+
JS.global[:Date].new(2000, 9, 13)
|
167
|
+
```
|
168
|
+
|
169
|
+
### Convert returned JavaScript `String` value to Ruby `String`
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
require "js"
|
173
|
+
|
174
|
+
title = JS.global[:document].title # => JS::Object("Hello, world!")
|
175
|
+
title.to_s # => "Hello, world!"
|
176
|
+
```
|
177
|
+
|
178
|
+
### Convert JavaScript `Boolean` value to Ruby `true`/`false`
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
require "js"
|
182
|
+
|
183
|
+
JS.global[:document].hasFocus? # => true
|
184
|
+
JS.global[:document].hasFocus # => JS::Object(true)
|
185
|
+
```
|
186
|
+
|
187
|
+
### Convert JavaScript `Number` value to Ruby `Integer`/`Float`
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
require "js"
|
191
|
+
|
192
|
+
rand = JS.global[:Math].random # JS::Object(0.123456789)
|
193
|
+
rand.to_i # => 0
|
194
|
+
rand.to_f # => 0.123456789
|
195
|
+
```
|
data/docs/faq.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
[[**Cheat Sheet**]](./cheat_sheet.md)
|
2
|
+
[[**FAQ**]](./faq.md)
|
3
|
+
[[**API Reference**]](./api.md)
|
4
|
+
[[**Complete Examples**]](https://github.com/ruby/ruby.wasm/tree/main/packages/npm-packages/ruby-wasm-wasi/example)
|
5
|
+
[[**Community Showcase**]](https://github.com/ruby/ruby.wasm/wiki/Showcase)
|
6
|
+
|
7
|
+
# FAQ
|
8
|
+
|
9
|
+
## Where my `puts` output goes?
|
10
|
+
|
11
|
+
By default, `puts` output goes to `STDOUT` which is a JavaScript `console.log` function. You can override it by setting `$stdout` to a Ruby object which has `write` method.
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
$stdout = Object.new.tap do |obj|
|
15
|
+
def obj.write(str)
|
16
|
+
JS.global[:document].write(str)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
puts "Hello, world!" # => Prints "Hello, world!" to the HTML document
|
21
|
+
```
|
22
|
+
|
23
|
+
## How to run WebAssembly in Ruby
|
24
|
+
|
25
|
+
Use [`wasmtime` Ruby gem](https://rubygems.org/gems/wasmtime).
|
data/exe/rbwasm
ADDED
data/ext/.gitignore
ADDED
data/ext/README.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Ruby extensions
|
2
|
+
`ruby.wasm` uses two C extensions to turn Ruby in to a guest module.
|
3
|
+
The `js` extension enables Ruby to use JavaScript APIs.
|
4
|
+
The `witapi` extension exports Ruby's interpreter interface to allow the host to use the Ruby interpreter.
|
5
|
+
In other words, `js` allows Ruby to talk to Javascript and `witapi` allows a host to talk to Ruby.
|
6
|
+
|
7
|
+
Under each subdirectory, there is a `bindgen/*.wit` file outlining the interfaces for each form of communication.
|
8
|
+
Specifically, `bindgen/rb-js-abi-host.wit` describes embedder's requirements and `bindgen/rb-js-abi-guest.wit` describes exported API from Ruby interpreter.
|
9
|
+
The `.c` and `.h` files are autogenerated from [wit-bindgen](https://github.com/bytecodealliance/wit-bindgen#host-runtimes-for-components).
|
10
|
+
You can read more about it in the [contributing guide](/CONTRIBUTING.md#re-bindgen-from-wit-files).
|
11
|
+
Note that we currently do not use the latest version of wit-bindgen because of how fast it is changing, with features being changed or even [removed](https://github.com/bytecodealliance/wit-bindgen/pull/346) at times.
|
data/ext/extinit.c.erb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "erb"
|
2
|
+
require "optparse"
|
3
|
+
|
4
|
+
opts = OptionParser.new
|
5
|
+
opts.on("--cc CC") {|cc| @cc = cc }
|
6
|
+
opts.on("--output FILE") {|o| @o = o }
|
7
|
+
|
8
|
+
opts.parse!(ARGV)
|
9
|
+
if @cc.nil? || @o.nil?
|
10
|
+
puts opts.help
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
exts = ARGV
|
15
|
+
|
16
|
+
c_src = ERB.new(DATA.read).result
|
17
|
+
IO.popen([@cc, "-c", "-xc", "-", "-o", @o], "w") {|f| f << c_src }
|
18
|
+
exit $?.exitstatus
|
19
|
+
|
20
|
+
__END__
|
21
|
+
#define init(func, name) { \
|
22
|
+
extern void func(void); \
|
23
|
+
ruby_init_ext(name".so", func); \
|
24
|
+
}
|
25
|
+
|
26
|
+
void ruby_init_ext(const char *name, void (*init)(void));
|
27
|
+
|
28
|
+
void Init_extra_exts(void) {
|
29
|
+
<% exts.each do |ext| %>
|
30
|
+
init(<%= "Init_#{File.basename ext}" %>, "<%= ext %>");
|
31
|
+
<% end %>
|
32
|
+
}
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module RubyWasm
|
2
|
+
class Downloader
|
3
|
+
def download(url, dest, message)
|
4
|
+
require "open-uri"
|
5
|
+
content_length = 0
|
6
|
+
uri = URI.parse(url)
|
7
|
+
OpenURI.open_uri(
|
8
|
+
uri,
|
9
|
+
content_length_proc: ->(len) { content_length = len },
|
10
|
+
progress_proc: ->(size) do
|
11
|
+
print "\r#{message} (#{SizeFormatter.format(content_length)}) %.2f%%" %
|
12
|
+
(size.to_f / content_length * 100)
|
13
|
+
end
|
14
|
+
) { |f| File.open(dest, "wb") { |out| out.write f.read } }
|
15
|
+
puts "\r"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
module RubyWasm
|
2
|
+
# Build executor to run the actual build commands.
|
3
|
+
class BuildExecutor
|
4
|
+
attr_reader :process_count
|
5
|
+
|
6
|
+
def initialize(verbose: false, process_count: nil)
|
7
|
+
@verbose = verbose
|
8
|
+
@github_actions_markup = ENV["ENABLE_GITHUB_ACTIONS_MARKUP"] != nil
|
9
|
+
__skip__ =
|
10
|
+
begin
|
11
|
+
require "etc"
|
12
|
+
@process_count = process_count || Etc.nprocessors
|
13
|
+
rescue LoadError
|
14
|
+
@process_count = process_count || 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def system(*args, chdir: nil, env: nil)
|
19
|
+
require "open3"
|
20
|
+
|
21
|
+
_print_command(args, env)
|
22
|
+
|
23
|
+
# @type var kwargs: Hash[Symbol, untyped]
|
24
|
+
kwargs = {}
|
25
|
+
kwargs[:chdir] = chdir if chdir
|
26
|
+
|
27
|
+
args = args.to_a.map(&:to_s)
|
28
|
+
# TODO: Remove __skip__ once we have open3 RBS definitions.
|
29
|
+
__skip__ =
|
30
|
+
if @verbose || !$stdout.tty?
|
31
|
+
kwargs[:exception] = true
|
32
|
+
if env
|
33
|
+
Kernel.system(env, *args, **kwargs)
|
34
|
+
else
|
35
|
+
Kernel.system(*args, **kwargs)
|
36
|
+
end
|
37
|
+
else
|
38
|
+
printer = StatusPrinter.new
|
39
|
+
block =
|
40
|
+
proc do |stdin, stdout, stderr, wait_thr|
|
41
|
+
mux = Mutex.new
|
42
|
+
out = String.new
|
43
|
+
err = String.new
|
44
|
+
readers =
|
45
|
+
[
|
46
|
+
[stdout, :stdout, out],
|
47
|
+
[stderr, :stderr, err]
|
48
|
+
].map do |io, name, str|
|
49
|
+
reader =
|
50
|
+
Thread.new do
|
51
|
+
while (line = io.gets)
|
52
|
+
mux.synchronize do
|
53
|
+
printer.send(name, line)
|
54
|
+
str << line
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
reader.report_on_exception = false
|
59
|
+
reader
|
60
|
+
end
|
61
|
+
|
62
|
+
readers.each(&:join)
|
63
|
+
|
64
|
+
[out, err, wait_thr.value]
|
65
|
+
end
|
66
|
+
begin
|
67
|
+
stdout, stderr, status =
|
68
|
+
if env
|
69
|
+
Open3.popen3(env, *args, **kwargs, &block)
|
70
|
+
else
|
71
|
+
Open3.popen3(*args, **kwargs, &block)
|
72
|
+
end
|
73
|
+
unless status.success?
|
74
|
+
$stderr.puts stdout
|
75
|
+
$stderr.puts stderr
|
76
|
+
cmd_to_print = args.map { |a| "'#{a}'" }.join(" ")
|
77
|
+
raise "Command failed with status (#{status.exitstatus}): #{cmd_to_print}"
|
78
|
+
end
|
79
|
+
ensure
|
80
|
+
printer.done
|
81
|
+
end
|
82
|
+
end
|
83
|
+
return
|
84
|
+
rescue => e
|
85
|
+
$stdout.flush
|
86
|
+
$stderr.puts "Try running with `rake --verbose` for more complete output."
|
87
|
+
raise e
|
88
|
+
end
|
89
|
+
|
90
|
+
def begin_section(klass, name, note)
|
91
|
+
message = "\e[1;36m==>\e[0m \e[1m#{klass}(#{name}) -- #{note}\e[0m"
|
92
|
+
if @github_actions_markup
|
93
|
+
puts "::group::#{message}"
|
94
|
+
else
|
95
|
+
puts message
|
96
|
+
end
|
97
|
+
|
98
|
+
# Record the start time
|
99
|
+
@start_times ||= Hash.new
|
100
|
+
@start_times[[klass, name]] = Time.now
|
101
|
+
|
102
|
+
$stdout.flush
|
103
|
+
end
|
104
|
+
|
105
|
+
def end_section(klass, name)
|
106
|
+
took = Time.now - @start_times[[klass, name]]
|
107
|
+
puts "::endgroup::" if @github_actions_markup
|
108
|
+
puts "\e[1;36m==>\e[0m \e[1m#{klass}(#{name}) -- done in #{took.round(2)}s\e[0m"
|
109
|
+
end
|
110
|
+
|
111
|
+
def rm_rf(list)
|
112
|
+
FileUtils.rm_rf(list)
|
113
|
+
end
|
114
|
+
|
115
|
+
def rm_f(list)
|
116
|
+
FileUtils.rm_f(list)
|
117
|
+
end
|
118
|
+
|
119
|
+
def cp_r(src, dest)
|
120
|
+
FileUtils.cp_r(src, dest)
|
121
|
+
end
|
122
|
+
|
123
|
+
def mv(src, dest)
|
124
|
+
FileUtils.mv(src, dest)
|
125
|
+
end
|
126
|
+
|
127
|
+
def mkdir_p(list)
|
128
|
+
FileUtils.mkdir_p(list)
|
129
|
+
end
|
130
|
+
|
131
|
+
def write(path, data)
|
132
|
+
File.write(path, data)
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def _print_command(args, env)
|
138
|
+
require "shellwords"
|
139
|
+
# Bold cyan
|
140
|
+
print "\e[1;36m ==>\e[0m "
|
141
|
+
print "env " + env.map { |k, v| "#{k}=#{v}" }.join(" ") + " " if env
|
142
|
+
print args.map { |arg| Shellwords.escape(arg.to_s) }.join(" ") + "\n"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Human readable status printer for the build.
|
147
|
+
class StatusPrinter
|
148
|
+
def initialize
|
149
|
+
@mutex = Mutex.new
|
150
|
+
@counter = 0
|
151
|
+
@indicators = "|/-\\"
|
152
|
+
end
|
153
|
+
|
154
|
+
def stdout(message)
|
155
|
+
require "io/console"
|
156
|
+
@mutex.synchronize do
|
157
|
+
$stdout.print "\e[K"
|
158
|
+
first_line = message.lines(chomp: true).first || ""
|
159
|
+
|
160
|
+
# Make sure we don't line-wrap the output
|
161
|
+
size =
|
162
|
+
__skip__ =
|
163
|
+
IO.respond_to?(:console_size) ? IO.console_size : IO.console.winsize
|
164
|
+
terminal_width = size[1].to_i.nonzero? || 80
|
165
|
+
width_limit = terminal_width / 2 - 3
|
166
|
+
|
167
|
+
if first_line.length > width_limit
|
168
|
+
first_line = (first_line[0..width_limit - 5] || "") + "..."
|
169
|
+
end
|
170
|
+
indicator = @indicators[@counter] || " "
|
171
|
+
to_print = " " + indicator + " " + first_line
|
172
|
+
$stdout.print to_print
|
173
|
+
$stdout.print "\e[1A\n"
|
174
|
+
@counter += 1
|
175
|
+
@counter = 0 if @counter >= @indicators.length
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def stderr(message)
|
180
|
+
@mutex.synchronize { $stdout.print message }
|
181
|
+
end
|
182
|
+
|
183
|
+
def done
|
184
|
+
@mutex.synchronize { $stdout.print "\e[K" }
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative "./product"
|
2
|
+
|
3
|
+
module RubyWasm
|
4
|
+
class BaseRubyProduct < BuildProduct
|
5
|
+
def initialize(build_dir, source)
|
6
|
+
@build_dir = build_dir
|
7
|
+
@source = source
|
8
|
+
@channel = source.name
|
9
|
+
end
|
10
|
+
|
11
|
+
def product_build_dir
|
12
|
+
File.join(@build_dir, RbConfig::CONFIG["host"], "baseruby-#{@channel}")
|
13
|
+
end
|
14
|
+
|
15
|
+
def install_dir
|
16
|
+
File.join(product_build_dir, "opt")
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
"baseruby-#{@channel}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def build(executor)
|
24
|
+
executor.mkdir_p product_build_dir
|
25
|
+
@source.build(executor)
|
26
|
+
return if Dir.exist?(install_dir)
|
27
|
+
executor.system @source.configure_file,
|
28
|
+
"--prefix=#{install_dir}",
|
29
|
+
"--disable-install-doc",
|
30
|
+
chdir: product_build_dir
|
31
|
+
executor.system "make",
|
32
|
+
"-j#{executor.process_count}",
|
33
|
+
"install",
|
34
|
+
chdir: product_build_dir
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|