ruby_wasm 2.5.0.pre.1
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 +124 -0
- data/Cargo.lock +2452 -0
- data/Cargo.toml +7 -0
- data/Gemfile +17 -0
- data/LICENSE +21 -0
- data/NOTICE +1293 -0
- data/README.md +161 -0
- data/Rakefile +164 -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/ext/ruby_wasm/Cargo.toml +17 -0
- data/ext/ruby_wasm/extconf.rb +6 -0
- data/ext/ruby_wasm/src/lib.rs +69 -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 +326 -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 +83 -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 +195 -0
- data/lib/ruby_wasm/packager/core.rb +156 -0
- data/lib/ruby_wasm/packager/file_system.rb +157 -0
- data/lib/ruby_wasm/packager.rb +159 -0
- data/lib/ruby_wasm/rake_task.rb +58 -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/ruby_wasm.gemspec +32 -0
- data/sig/open_uri.rbs +4 -0
- data/sig/ruby_wasm/build.rbs +322 -0
- data/sig/ruby_wasm/cli.rbs +24 -0
- data/sig/ruby_wasm/ext.rbs +11 -0
- data/sig/ruby_wasm/packager.rbs +91 -0
- data/sig/ruby_wasm/util.rbs +5 -0
- data/tasks/check.rake +37 -0
- data/tasks/ci.rake +152 -0
- data/tasks/doc.rake +24 -0
- data/tasks/format.rake +34 -0
- data/tasks/gem.rake +19 -0
- data/tasks/packaging.rake +148 -0
- data/tasks/version.rake +38 -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 +115 -0
@@ -0,0 +1,156 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
class RubyWasm::Packager::Core
|
4
|
+
def initialize(packager)
|
5
|
+
@packager = packager
|
6
|
+
end
|
7
|
+
|
8
|
+
def build(executor, options)
|
9
|
+
strategy = build_strategy
|
10
|
+
strategy.build(executor, options)
|
11
|
+
end
|
12
|
+
|
13
|
+
extend Forwardable
|
14
|
+
|
15
|
+
def_delegators :build_strategy, :cache_key, :artifact
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def build_strategy
|
20
|
+
@build_strategy ||=
|
21
|
+
begin
|
22
|
+
has_exts = @packager.specs.any? { |spec| spec.extensions.any? }
|
23
|
+
if @packager.support_dynamic_linking?
|
24
|
+
DynamicLinking.new(@packager)
|
25
|
+
else
|
26
|
+
StaticLinking.new(@packager)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class BuildStrategy
|
32
|
+
def initialize(packager)
|
33
|
+
@packager = packager
|
34
|
+
end
|
35
|
+
|
36
|
+
def build(executor, options)
|
37
|
+
raise NotImplementedError
|
38
|
+
end
|
39
|
+
|
40
|
+
# Array of paths to extconf.rb files.
|
41
|
+
def specs_with_extensions
|
42
|
+
@packager.specs.filter_map do |spec|
|
43
|
+
exts =
|
44
|
+
spec.extensions.select do |ext|
|
45
|
+
# Filter out extensions of default gems (e.g. json, openssl)
|
46
|
+
# for the exactly same gem version.
|
47
|
+
File.exist?(File.join(spec.full_gem_path, ext))
|
48
|
+
end
|
49
|
+
next nil if exts.empty?
|
50
|
+
[spec, exts]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def cache_key(digest)
|
55
|
+
raise NotImplementedError
|
56
|
+
end
|
57
|
+
|
58
|
+
def artifact
|
59
|
+
raise NotImplementedError
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class DynamicLinking < BuildStrategy
|
64
|
+
end
|
65
|
+
|
66
|
+
class StaticLinking < BuildStrategy
|
67
|
+
def build(executor, options)
|
68
|
+
build = derive_build
|
69
|
+
force_rebuild =
|
70
|
+
options[:remake] || options[:clean] || options[:reconfigure]
|
71
|
+
if File.exist?(build.crossruby.artifact) && !force_rebuild
|
72
|
+
return build.crossruby.artifact
|
73
|
+
end
|
74
|
+
build.crossruby.clean(executor) if options[:clean]
|
75
|
+
|
76
|
+
do_build =
|
77
|
+
proc do
|
78
|
+
build.crossruby.build(
|
79
|
+
executor,
|
80
|
+
remake: options[:remake],
|
81
|
+
reconfigure: options[:reconfigure]
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
__skip__ =
|
86
|
+
if defined?(Bundler)
|
87
|
+
Bundler.with_unbundled_env(&do_build)
|
88
|
+
else
|
89
|
+
do_build.call
|
90
|
+
end
|
91
|
+
build.crossruby.artifact
|
92
|
+
end
|
93
|
+
|
94
|
+
def cache_key(digest)
|
95
|
+
derive_build.cache_key(digest)
|
96
|
+
end
|
97
|
+
|
98
|
+
def artifact
|
99
|
+
derive_build.crossruby.artifact
|
100
|
+
end
|
101
|
+
|
102
|
+
def derive_build
|
103
|
+
return @build if @build
|
104
|
+
__skip__ =
|
105
|
+
build ||= RubyWasm::Build.new(name, **@packager.full_build_options)
|
106
|
+
build.crossruby.user_exts = user_exts(build)
|
107
|
+
# Emscripten uses --global-base=1024 by default, but it conflicts with
|
108
|
+
# --stack-first and -z stack-size since global-base 1024 is smaller than
|
109
|
+
# the large stack size.
|
110
|
+
# Also -g produces some warnings on Emscripten and it confuses the configure
|
111
|
+
# script of Ruby.
|
112
|
+
if @packager.full_build_options[:target] != "wasm32-unknown-emscripten"
|
113
|
+
build.crossruby.debugflags = %w[-g]
|
114
|
+
build.crossruby.wasmoptflags = %w[-O3 -g]
|
115
|
+
build.crossruby.ldflags = %w[
|
116
|
+
-Xlinker
|
117
|
+
--stack-first
|
118
|
+
-Xlinker
|
119
|
+
-z
|
120
|
+
-Xlinker
|
121
|
+
stack-size=16777216
|
122
|
+
]
|
123
|
+
end
|
124
|
+
@build = build
|
125
|
+
build
|
126
|
+
end
|
127
|
+
|
128
|
+
def user_exts(build)
|
129
|
+
@user_exts ||=
|
130
|
+
specs_with_extensions.flat_map do |spec, exts|
|
131
|
+
exts.map do |ext|
|
132
|
+
ext_feature = File.dirname(ext) # e.g. "ext/cgi/escape"
|
133
|
+
ext_srcdir = File.join(spec.full_gem_path, ext_feature)
|
134
|
+
ext_relative_path = File.join(spec.full_name, ext_feature)
|
135
|
+
RubyWasm::CrossRubyExtProduct.new(
|
136
|
+
ext_srcdir,
|
137
|
+
build.toolchain,
|
138
|
+
ext_relative_path: ext_relative_path
|
139
|
+
)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def name
|
145
|
+
require "digest"
|
146
|
+
options = @packager.full_build_options
|
147
|
+
src_channel = options[:src][:name]
|
148
|
+
target_triplet = options[:target]
|
149
|
+
base = "ruby-#{src_channel}-#{target_triplet}#{options[:suffix]}"
|
150
|
+
exts = specs_with_extensions.sort
|
151
|
+
hash = ::Digest::MD5.new
|
152
|
+
specs_with_extensions.each { |spec, _| hash << spec.full_name }
|
153
|
+
exts.empty? ? base : "#{base}-#{hash.hexdigest}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# Package Ruby code into a mountable directory.
|
2
|
+
class RubyWasm::Packager::FileSystem
|
3
|
+
def initialize(dest_dir, packager)
|
4
|
+
@dest_dir = dest_dir
|
5
|
+
@packager = packager
|
6
|
+
@ruby_root = File.join(@dest_dir, "usr", "local")
|
7
|
+
end
|
8
|
+
|
9
|
+
def package_ruby_root(tarball, executor)
|
10
|
+
usr_dir = File.dirname(@ruby_root)
|
11
|
+
executor.mkdir_p usr_dir
|
12
|
+
executor.system(
|
13
|
+
"tar",
|
14
|
+
"-C",
|
15
|
+
usr_dir,
|
16
|
+
"-xzf",
|
17
|
+
tarball,
|
18
|
+
"--strip-components=2"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def remove_stdlib(executor)
|
23
|
+
# Include only rbconfig.rb
|
24
|
+
rbconfig =
|
25
|
+
File.join(
|
26
|
+
@ruby_root,
|
27
|
+
"lib",
|
28
|
+
"ruby",
|
29
|
+
ruby_version,
|
30
|
+
"wasm32-wasi",
|
31
|
+
"rbconfig.rb"
|
32
|
+
)
|
33
|
+
# Remove all files except rbconfig.rb
|
34
|
+
RubyWasm.logger.info "Removing stdlib (except rbconfig.rb: #{rbconfig})"
|
35
|
+
rbconfig_contents = File.read(rbconfig)
|
36
|
+
executor.rm_rf @ruby_root
|
37
|
+
executor.mkdir_p File.dirname(rbconfig)
|
38
|
+
File.write(rbconfig, rbconfig_contents)
|
39
|
+
end
|
40
|
+
|
41
|
+
def package_gems
|
42
|
+
@packager.specs.each do |spec|
|
43
|
+
RubyWasm.logger.info "Packaging gem: #{spec.full_name}"
|
44
|
+
end
|
45
|
+
self.each_gem_content_path do |relative, source|
|
46
|
+
RubyWasm.logger.debug "Packaging gem file: #{relative}"
|
47
|
+
dest = File.join(@dest_dir, relative)
|
48
|
+
FileUtils.mkdir_p File.dirname(dest)
|
49
|
+
FileUtils.cp_r source, dest
|
50
|
+
end
|
51
|
+
|
52
|
+
setup_rb_path = File.join(bundle_relative_path, "setup.rb")
|
53
|
+
RubyWasm.logger.info "Packaging setup.rb: #{setup_rb_path}"
|
54
|
+
full_setup_rb_path = File.join(@dest_dir, setup_rb_path)
|
55
|
+
FileUtils.mkdir_p File.dirname(full_setup_rb_path)
|
56
|
+
File.write(full_setup_rb_path, setup_rb_content)
|
57
|
+
end
|
58
|
+
|
59
|
+
def setup_rb_content
|
60
|
+
content = ""
|
61
|
+
self.each_gem_require_path do |relative, _|
|
62
|
+
content << %Q[$:.unshift File.expand_path("#{File.join("/", relative)}")\n]
|
63
|
+
end
|
64
|
+
content
|
65
|
+
end
|
66
|
+
|
67
|
+
def remove_non_runtime_files(executor)
|
68
|
+
%w[
|
69
|
+
**/*.so
|
70
|
+
usr/local/lib/libruby-static.a
|
71
|
+
usr/local/bin/ruby
|
72
|
+
usr/local/include
|
73
|
+
].each do |pattern|
|
74
|
+
Dir
|
75
|
+
.glob(File.join(@dest_dir, pattern))
|
76
|
+
.each do |entry|
|
77
|
+
RubyWasm.logger.debug do
|
78
|
+
relative_entry = Pathname.new(entry).relative_path_from(@dest_dir)
|
79
|
+
"Removing non-runtime file: #{relative_entry}"
|
80
|
+
end
|
81
|
+
executor.rm_rf entry
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def bundle_dir
|
87
|
+
File.join(@dest_dir, bundle_relative_path)
|
88
|
+
end
|
89
|
+
|
90
|
+
def ruby_root
|
91
|
+
@ruby_root
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
# Iterates over each gem's require path and extension path.
|
97
|
+
# Yields the installation relative path and the source path.
|
98
|
+
def each_gem_require_path(&block)
|
99
|
+
each_gem_extension_path(&block)
|
100
|
+
@packager.specs.each do |spec|
|
101
|
+
spec.raw_require_paths.each do |require_path|
|
102
|
+
source = File.expand_path(require_path, spec.full_gem_path)
|
103
|
+
next unless File.exist?(source)
|
104
|
+
relative =
|
105
|
+
File.join(bundle_relative_path, "gems", spec.full_name, require_path)
|
106
|
+
yield relative, source
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def each_gem_content_path(&block)
|
112
|
+
each_gem_extension_path(&block)
|
113
|
+
|
114
|
+
@packager.specs.each do |spec|
|
115
|
+
next unless File.exist?(spec.full_gem_path)
|
116
|
+
|
117
|
+
Dir
|
118
|
+
.children(spec.full_gem_path)
|
119
|
+
.each do |require_path|
|
120
|
+
source = File.expand_path(require_path, spec.full_gem_path)
|
121
|
+
next unless File.exist?(source)
|
122
|
+
relative =
|
123
|
+
File.join(
|
124
|
+
bundle_relative_path,
|
125
|
+
"gems",
|
126
|
+
spec.full_name,
|
127
|
+
require_path
|
128
|
+
)
|
129
|
+
yield relative, source
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def each_gem_extension_path
|
135
|
+
@packager.specs.each do |spec|
|
136
|
+
if !spec.extensions.empty? && File.exist?(spec.extension_dir)
|
137
|
+
relative = File.join(bundle_relative_path, "extensions", spec.full_name)
|
138
|
+
yield relative, spec.extension_dir
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def bundle_relative_path
|
144
|
+
"bundle"
|
145
|
+
end
|
146
|
+
|
147
|
+
def ruby_version
|
148
|
+
rubyarchdir = self.rubyarchdir
|
149
|
+
File.basename(File.dirname(rubyarchdir))
|
150
|
+
end
|
151
|
+
|
152
|
+
def rubyarchdir
|
153
|
+
maybe =
|
154
|
+
Dir.glob(File.join(@ruby_root, "lib", "ruby", "*", "wasm32-wasi")).first
|
155
|
+
maybe || raise("Cannot find rubyarchdir")
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# A class responsible for packaging whole Ruby project
|
2
|
+
class RubyWasm::Packager
|
3
|
+
# Initializes a new instance of the RubyWasm::Packager class.
|
4
|
+
#
|
5
|
+
# @param config [Hash] The build config used for building Ruby.
|
6
|
+
# @param definition [Bundler::Definition] The Bundler definition.
|
7
|
+
def initialize(config = nil, definition = nil)
|
8
|
+
@definition = definition
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
# Packages the Ruby code into a Wasm binary. (including extensions)
|
13
|
+
#
|
14
|
+
# @param executor [RubyWasm::BuildExecutor] The executor for building the Wasm binary.
|
15
|
+
# @param dest_dir [String] The destination used to construct the filesystem.
|
16
|
+
# @param options [Hash] The packaging options.
|
17
|
+
# @return [Array<Integer>] The bytes of the packaged Wasm binary.
|
18
|
+
def package(executor, dest_dir, options)
|
19
|
+
ruby_core = self.ruby_core_build()
|
20
|
+
tarball = ruby_core.build(executor, options)
|
21
|
+
|
22
|
+
fs = RubyWasm::Packager::FileSystem.new(dest_dir, self)
|
23
|
+
fs.package_ruby_root(tarball, executor)
|
24
|
+
|
25
|
+
ruby_wasm_bin = File.expand_path("bin/ruby", fs.ruby_root)
|
26
|
+
wasm_bytes = File.binread(ruby_wasm_bin).bytes
|
27
|
+
|
28
|
+
fs.package_gems
|
29
|
+
fs.remove_non_runtime_files(executor)
|
30
|
+
fs.remove_stdlib(executor) unless options[:stdlib]
|
31
|
+
|
32
|
+
if full_build_options[:target] == "wasm32-unknown-wasi"
|
33
|
+
# wasi-vfs supports only WASI target
|
34
|
+
wasi_vfs = RubyWasmExt::WasiVfs.new
|
35
|
+
wasi_vfs.map_dir("/bundle", fs.bundle_dir)
|
36
|
+
wasi_vfs.map_dir("/usr", File.dirname(fs.ruby_root))
|
37
|
+
|
38
|
+
wasm_bytes = wasi_vfs.pack(wasm_bytes)
|
39
|
+
end
|
40
|
+
|
41
|
+
wasm_bytes = RubyWasmExt.preinitialize(wasm_bytes) if options[:optimize]
|
42
|
+
wasm_bytes
|
43
|
+
end
|
44
|
+
|
45
|
+
def ruby_core_build
|
46
|
+
@ruby_core_build ||= RubyWasm::Packager::Core.new(self)
|
47
|
+
end
|
48
|
+
|
49
|
+
# The list of excluded gems from the Bundler definition.
|
50
|
+
EXCLUDED_GEMS = %w[ruby_wasm bundler]
|
51
|
+
|
52
|
+
# Retrieves the specs from the Bundler definition, excluding the excluded gems.
|
53
|
+
def specs
|
54
|
+
return [] unless @definition
|
55
|
+
@definition.specs.reject { |spec| EXCLUDED_GEMS.include?(spec.name) }
|
56
|
+
end
|
57
|
+
|
58
|
+
# Checks if dynamic linking is supported.
|
59
|
+
def support_dynamic_linking?
|
60
|
+
@ruby_channel == "head"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Retrieves the root directory of the Ruby project.
|
64
|
+
# The root directory contains the following stuff:
|
65
|
+
# * patches/*.patch
|
66
|
+
# * build_manifest.json
|
67
|
+
# * rubies
|
68
|
+
# * build
|
69
|
+
def root
|
70
|
+
__skip__ =
|
71
|
+
@root ||=
|
72
|
+
begin
|
73
|
+
if explicit = ENV["RUBY_WASM_ROOT"]
|
74
|
+
File.expand_path(explicit)
|
75
|
+
elsif defined?(Bundler)
|
76
|
+
Bundler.root
|
77
|
+
else
|
78
|
+
Dir.pwd
|
79
|
+
end
|
80
|
+
rescue Bundler::GemfileNotFound
|
81
|
+
Dir.pwd
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Retrieves the alias definitions for the Ruby sources.
|
86
|
+
def self.build_source_aliases(root)
|
87
|
+
patches = Dir[File.join(root, "patches", "*.patch")]
|
88
|
+
sources = {
|
89
|
+
"head" => {
|
90
|
+
type: "github",
|
91
|
+
repo: "ruby/ruby",
|
92
|
+
rev: "997124fc0b7697bb9383e8feb8e1d88017c4bcb8",
|
93
|
+
patches: patches.map { |p| File.expand_path(p) }
|
94
|
+
},
|
95
|
+
"3.3" => {
|
96
|
+
type: "tarball",
|
97
|
+
url: "https://cache.ruby-lang.org/pub/ruby/3.3/ruby-3.3.0.tar.gz"
|
98
|
+
},
|
99
|
+
"3.2" => {
|
100
|
+
type: "tarball",
|
101
|
+
url: "https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.2.tar.gz"
|
102
|
+
}
|
103
|
+
}
|
104
|
+
sources.each { |name, source| source[:name] = name }
|
105
|
+
|
106
|
+
build_manifest = File.join(root, "build_manifest.json")
|
107
|
+
if File.exist?(build_manifest)
|
108
|
+
begin
|
109
|
+
manifest = JSON.parse(File.read(build_manifest))
|
110
|
+
manifest["ruby_revisions"].each do |name, rev|
|
111
|
+
sources[name][:rev] = rev
|
112
|
+
end
|
113
|
+
rescue StandardError => e
|
114
|
+
RubyWasm.logger.warn "Failed to load build_manifest.json: #{e}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
sources
|
118
|
+
end
|
119
|
+
|
120
|
+
ALL_DEFAULT_EXTS =
|
121
|
+
"bigdecimal,cgi/escape,continuation,coverage,date,dbm,digest/bubblebabble,digest,digest/md5,digest/rmd160,digest/sha1,digest/sha2,etc,fcntl,fiber,gdbm,json,json/generator,json/parser,nkf,objspace,pathname,psych,racc/cparse,rbconfig/sizeof,ripper,stringio,strscan,monitor,zlib,openssl"
|
122
|
+
|
123
|
+
# Retrieves the build options used for building Ruby itself.
|
124
|
+
def build_options
|
125
|
+
default = {
|
126
|
+
target: "wasm32-unknown-wasi",
|
127
|
+
src: "3.3",
|
128
|
+
default_exts: ALL_DEFAULT_EXTS
|
129
|
+
}
|
130
|
+
override = @config || {}
|
131
|
+
# Merge the default options with the config options
|
132
|
+
default.merge(override)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Retrieves the resolved build options
|
136
|
+
def full_build_options
|
137
|
+
options = build_options
|
138
|
+
build_dir = File.join(root, "build")
|
139
|
+
rubies_dir = File.join(root, "rubies")
|
140
|
+
toolchain = RubyWasm::Toolchain.get(options[:target], build_dir)
|
141
|
+
src =
|
142
|
+
if options[:src].is_a?(Hash)
|
143
|
+
options[:src]
|
144
|
+
else
|
145
|
+
src_name = options[:src]
|
146
|
+
aliases = self.class.build_source_aliases(root)
|
147
|
+
aliases[src_name] ||
|
148
|
+
raise(
|
149
|
+
"Unknown Ruby source: #{src_name} (available: #{aliases.keys.join(", ")})"
|
150
|
+
)
|
151
|
+
end
|
152
|
+
options.merge(
|
153
|
+
toolchain: toolchain,
|
154
|
+
build_dir: build_dir,
|
155
|
+
rubies_dir: rubies_dir,
|
156
|
+
src: src
|
157
|
+
)
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "rake/tasklib"
|
2
|
+
require_relative "./build"
|
3
|
+
|
4
|
+
class RubyWasm::BuildTask < ::Rake::TaskLib
|
5
|
+
# Name of the task.
|
6
|
+
attr_accessor :name
|
7
|
+
|
8
|
+
def initialize(
|
9
|
+
name,
|
10
|
+
target:,
|
11
|
+
src:,
|
12
|
+
toolchain: nil,
|
13
|
+
build_dir: nil,
|
14
|
+
rubies_dir: nil,
|
15
|
+
**options,
|
16
|
+
&block
|
17
|
+
)
|
18
|
+
@build =
|
19
|
+
RubyWasm::Build.new(
|
20
|
+
name,
|
21
|
+
target: target,
|
22
|
+
src: src,
|
23
|
+
toolchain: toolchain,
|
24
|
+
build_dir: build_dir || File.join(Dir.pwd, "build"),
|
25
|
+
rubies_dir: rubies_dir || File.join(Dir.pwd, "rubies"),
|
26
|
+
**options,
|
27
|
+
&block
|
28
|
+
)
|
29
|
+
yield @build if block_given?
|
30
|
+
@crossruby = @build.crossruby
|
31
|
+
# Rake.verbose can be Object.new by default, so compare with true explicitly.
|
32
|
+
executor = RubyWasm::BuildExecutor.new(verbose: Rake.verbose == true)
|
33
|
+
|
34
|
+
desc "Cross-build Ruby for #{@target}"
|
35
|
+
task name do
|
36
|
+
next if File.exist? @crossruby.artifact
|
37
|
+
@crossruby.build(executor)
|
38
|
+
end
|
39
|
+
namespace name do
|
40
|
+
task :remake do
|
41
|
+
@crossruby.build(executor, remake: true)
|
42
|
+
end
|
43
|
+
task :reconfigure do
|
44
|
+
@crossruby.build(executor, reconfigure: true)
|
45
|
+
end
|
46
|
+
task :clean do
|
47
|
+
@crossruby.clean(executor)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def hexdigest
|
53
|
+
require "digest"
|
54
|
+
digest = Digest::SHA256.new
|
55
|
+
@build.cache_key(digest)
|
56
|
+
digest.hexdigest
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RubyWasm
|
2
|
+
module SizeFormatter
|
3
|
+
def format(size)
|
4
|
+
units = %w[B KB MB GB TB]
|
5
|
+
unit = 0
|
6
|
+
while size > 1024 and unit < units.size - 1
|
7
|
+
size /= 1024.0
|
8
|
+
unit += 1
|
9
|
+
end
|
10
|
+
"%s #{units[unit]}" % size.round(2)
|
11
|
+
end
|
12
|
+
|
13
|
+
module_function :format
|
14
|
+
end
|
15
|
+
end
|
data/lib/ruby_wasm.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
3
|
+
require_relative "ruby_wasm/version"
|
4
|
+
require_relative "ruby_wasm/util"
|
5
|
+
require_relative "ruby_wasm/build"
|
6
|
+
require_relative "ruby_wasm/packager"
|
7
|
+
require_relative "ruby_wasm/packager/file_system"
|
8
|
+
require_relative "ruby_wasm/packager/core"
|
9
|
+
|
10
|
+
module RubyWasm
|
11
|
+
class << self
|
12
|
+
attr_accessor :log_level
|
13
|
+
|
14
|
+
def logger
|
15
|
+
@logger ||=
|
16
|
+
begin
|
17
|
+
logger =
|
18
|
+
Logger.new(
|
19
|
+
$stderr,
|
20
|
+
level: @log_level || Logger::INFO,
|
21
|
+
progname: "rbwasm"
|
22
|
+
)
|
23
|
+
logger.formatter =
|
24
|
+
proc { |severity, datetime, progname, msg| "#{severity}: #{msg}\n" }
|
25
|
+
logger
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def logger=(logger)
|
30
|
+
@logger = logger
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|