ruby_wasm 2.5.0-x64-mingw-ucrt

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.clang-format +8 -0
  3. data/CONTRIBUTING.md +126 -0
  4. data/Gemfile +17 -0
  5. data/LICENSE +21 -0
  6. data/NOTICE +1293 -0
  7. data/README.md +153 -0
  8. data/Rakefile +163 -0
  9. data/Steepfile +24 -0
  10. data/benchmarks/vm_deep_call.rb +55 -0
  11. data/builders/wasm32-unknown-emscripten/Dockerfile +43 -0
  12. data/builders/wasm32-unknown-emscripten/entrypoint.sh +7 -0
  13. data/builders/wasm32-unknown-wasi/Dockerfile +47 -0
  14. data/builders/wasm32-unknown-wasi/entrypoint.sh +7 -0
  15. data/docs/api.md +2 -0
  16. data/docs/cheat_sheet.md +195 -0
  17. data/docs/faq.md +25 -0
  18. data/exe/rbwasm +7 -0
  19. data/ext/.gitignore +2 -0
  20. data/ext/README.md +11 -0
  21. data/ext/extinit.c.erb +32 -0
  22. data/lib/ruby_wasm/3.1/ruby_wasm.so +0 -0
  23. data/lib/ruby_wasm/3.2/ruby_wasm.so +0 -0
  24. data/lib/ruby_wasm/build/build_params.rb +3 -0
  25. data/lib/ruby_wasm/build/downloader.rb +18 -0
  26. data/lib/ruby_wasm/build/executor.rb +187 -0
  27. data/lib/ruby_wasm/build/product/baseruby.rb +37 -0
  28. data/lib/ruby_wasm/build/product/crossruby.rb +330 -0
  29. data/lib/ruby_wasm/build/product/libyaml.rb +68 -0
  30. data/lib/ruby_wasm/build/product/openssl.rb +88 -0
  31. data/lib/ruby_wasm/build/product/product.rb +39 -0
  32. data/lib/ruby_wasm/build/product/ruby_source.rb +103 -0
  33. data/lib/ruby_wasm/build/product/wasi_vfs.rb +45 -0
  34. data/lib/ruby_wasm/build/product/zlib.rb +68 -0
  35. data/lib/ruby_wasm/build/product.rb +8 -0
  36. data/lib/ruby_wasm/build/toolchain/wit_bindgen.rb +31 -0
  37. data/lib/ruby_wasm/build/toolchain.rb +193 -0
  38. data/lib/ruby_wasm/build.rb +88 -0
  39. data/lib/ruby_wasm/cli.rb +217 -0
  40. data/lib/ruby_wasm/packager/core.rb +156 -0
  41. data/lib/ruby_wasm/packager/file_system.rb +158 -0
  42. data/lib/ruby_wasm/packager.rb +159 -0
  43. data/lib/ruby_wasm/rake_task.rb +59 -0
  44. data/lib/ruby_wasm/util.rb +15 -0
  45. data/lib/ruby_wasm/version.rb +3 -0
  46. data/lib/ruby_wasm.rb +33 -0
  47. data/package-lock.json +9500 -0
  48. data/package.json +12 -0
  49. data/rakelib/check.rake +37 -0
  50. data/rakelib/ci.rake +152 -0
  51. data/rakelib/doc.rake +29 -0
  52. data/rakelib/format.rake +35 -0
  53. data/rakelib/gem.rake +22 -0
  54. data/rakelib/packaging.rake +151 -0
  55. data/rakelib/version.rake +40 -0
  56. data/sig/open_uri.rbs +4 -0
  57. data/sig/ruby_wasm/build.rbs +318 -0
  58. data/sig/ruby_wasm/cli.rbs +27 -0
  59. data/sig/ruby_wasm/ext.rbs +13 -0
  60. data/sig/ruby_wasm/packager.rbs +91 -0
  61. data/sig/ruby_wasm/util.rbs +5 -0
  62. data/tools/clang-format-diff.sh +18 -0
  63. data/tools/exe/rbminify +12 -0
  64. data/tools/lib/syntax_tree/minify_ruby.rb +63 -0
  65. metadata +113 -0
data/package.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "ruby.wasm",
3
+ "private": true,
4
+ "workspaces": [
5
+ "packages/npm-packages/*"
6
+ ],
7
+ "devDependencies": {
8
+ "@playwright/test": "^1.40.1",
9
+ "@rollup/plugin-json": "^6.0.1",
10
+ "rollup": "^4.6.1"
11
+ }
12
+ }
@@ -0,0 +1,37 @@
1
+ namespace :check do
2
+ wit_bindgen = RubyWasm::WitBindgen.new(build_dir: "build")
3
+ task :install_wit_bindgen do
4
+ wit_bindgen.install
5
+ end
6
+ task bindgen_c: :install_wit_bindgen do
7
+ wits = [
8
+ %w[packages/gems/js/ext/witapi/bindgen/rb-abi-guest.wit --export],
9
+ %w[packages/gems/js/ext/js/bindgen/rb-js-abi-host.wit --import]
10
+ ]
11
+ wits.each do |wit|
12
+ path, mode = wit
13
+ sh "#{wit_bindgen.bin_path} guest c #{mode} #{path} --out-dir #{File.dirname(path)}"
14
+ end
15
+ end
16
+
17
+ task bindgen_js: :install_wit_bindgen do
18
+ sh *[
19
+ wit_bindgen.bin_path,
20
+ "host",
21
+ "js",
22
+ "--import",
23
+ "packages/gems/js/ext/witapi/bindgen/rb-abi-guest.wit",
24
+ "--export",
25
+ "packages/gems/js/ext/js/bindgen/rb-js-abi-host.wit",
26
+ "--out-dir",
27
+ "packages/npm-packages/ruby-wasm-wasi/src/bindgen"
28
+ ]
29
+ end
30
+
31
+ desc "Check wit-bindgen'ed sources are up-to-date"
32
+ task bindgen: %i[bindgen_c bindgen_js]
33
+
34
+ task :type do
35
+ sh "bundle exec steep check"
36
+ end
37
+ end
data/rakelib/ci.rake ADDED
@@ -0,0 +1,152 @@
1
+ def latest_build_sources
2
+ BUILD_SOURCES
3
+ .filter_map do |name|
4
+ src = RubyWasm::Packager.build_source_aliases(LIB_ROOT)[name]
5
+ case src[:type]
6
+ when "github"
7
+ url = "repos/#{src[:repo]}/commits/#{src[:rev]}"
8
+ revision = JSON.parse(`gh api #{url}`)
9
+ [name, revision["sha"]]
10
+ when "tarball"
11
+ nil
12
+ else
13
+ raise "#{src[:type]} is not supported to pin source revision"
14
+ end
15
+ end
16
+ .to_h
17
+ end
18
+
19
+ def release_note
20
+ output = <<EOS
21
+ | channel | source |
22
+ |:-------:|:------:|
23
+ EOS
24
+
25
+ BUILD_SOURCES.each do |name|
26
+ source = RubyWasm::Packager.build_source_aliases(LIB_ROOT)[name]
27
+ case source[:type]
28
+ when "github"
29
+ output +=
30
+ "| #{name} | [`#{source[:repo]}@#{source[:rev]}`](https://github.com/ruby/ruby/tree/#{source[:rev]}) |\n"
31
+ when "tarball"
32
+ output += "| #{name} | #{source[:url]} |\n"
33
+ else
34
+ raise "unknown source type: #{source[:type]}"
35
+ end
36
+ end
37
+ output
38
+ end
39
+
40
+ def sh_or_warn(*cmd)
41
+ sh *cmd do |ok, status|
42
+ unless ok
43
+ warn "Command failed with status (#{status.exitstatus}): #{cmd.join ""}"
44
+ end
45
+ end
46
+ end
47
+
48
+ def rake_task_matrix
49
+ require "pathname"
50
+ ruby_cache_keys = {}
51
+ BUILD_TASKS.each { |build| ruby_cache_keys[build.name] = build.hexdigest }
52
+ build_entries =
53
+ BUILD_TASKS.map do |build|
54
+ {
55
+ task: "build:#{build.name}",
56
+ artifact:
57
+ Pathname.new(build.artifact).relative_path_from(LIB_ROOT).to_s,
58
+ artifact_name: File.basename(build.artifact, ".tar.gz"),
59
+ builder: build.target,
60
+ rubies_cache_key: ruby_cache_keys[build.name]
61
+ }
62
+ end
63
+ npm_entries =
64
+ NPM_PACKAGES.map do |pkg|
65
+ entry = {
66
+ task: "npm:#{pkg[:name]}",
67
+ prerelease: "npm:configure_prerelease",
68
+ artifact: "packages/npm-packages/#{pkg[:name]}/#{pkg[:name]}-*.tgz",
69
+ artifact_name: "npm-#{pkg[:name]}",
70
+ builder: pkg[:target],
71
+ rubies_cache_key: npm_pkg_rubies_cache_key(pkg)
72
+ }
73
+ # Run tests only if the package has 'test' script
74
+ package_json =
75
+ JSON.parse(
76
+ File.read("packages/npm-packages/#{pkg[:name]}/package.json")
77
+ )
78
+ if package_json["scripts"] && package_json["scripts"]["test"]
79
+ entry[:test] = "npm:#{pkg[:name]}:check"
80
+ end
81
+ entry
82
+ end
83
+ standalone_entries =
84
+ STANDALONE_PACKAGES.map do |pkg|
85
+ {
86
+ task: "standalone:#{pkg[:name]}",
87
+ artifact: "packages/standalone/#{pkg[:name]}/dist",
88
+ artifact_name: "standalone-#{pkg[:name]}",
89
+ builder: "wasm32-unknown-wasi",
90
+ rubies_cache_key: ruby_cache_keys[pkg[:build]]
91
+ }
92
+ end
93
+ { build: build_entries, npm: npm_entries, standalone: standalone_entries }
94
+ end
95
+
96
+ namespace :ci do
97
+ task :rake_task_matrix do
98
+ print JSON.generate(rake_task_matrix.flat_map { |_, entries| entries })
99
+ end
100
+
101
+ task :pin_build_manifest do
102
+ content = JSON.generate({ ruby_revisions: latest_build_sources })
103
+ File.write("build_manifest.json", content)
104
+ end
105
+
106
+ desc "Fetch artifacts of a run of GitHub Actions"
107
+ task :fetch_artifacts, [:run_id] do |t, args|
108
+ RubyWasm::Toolchain.check_executable("gh")
109
+
110
+ artifacts =
111
+ JSON.load(
112
+ `gh api repos/{owner}/{repo}/actions/runs/#{args[:run_id]}/artifacts`
113
+ )
114
+ matrix = rake_task_matrix.flat_map { |_, entries| entries }
115
+ release_artifacts = matrix.map { |entry| entry[:artifact_name] }
116
+ artifacts =
117
+ artifacts["artifacts"].filter { release_artifacts.include?(_1["name"]) }
118
+ mkdir_p "release"
119
+ Dir.chdir("release") do
120
+ artifacts.each do |artifact|
121
+ url = artifact["archive_download_url"]
122
+ sh "gh api #{url} > #{artifact["name"]}.zip"
123
+ mkdir_p artifact["name"]
124
+ sh "unzip #{artifact["name"]}.zip -d #{artifact["name"]}"
125
+ rm "#{artifact["name"]}.zip"
126
+ end
127
+ end
128
+ end
129
+
130
+ desc "Publish artifacts as a GitHub Release"
131
+ task :publish, [:tag] do |t, args|
132
+ RubyWasm::Toolchain.check_executable("gh")
133
+
134
+ nightly = /^\d{4}-\d{2}-\d{2}-.$/.match?(args[:tag])
135
+ matrix = rake_task_matrix
136
+ files =
137
+ matrix
138
+ .flat_map { |_, entries| entries }
139
+ .map { |entry| "release/#{entry[:artifact_name]}/*" }
140
+ File.open("release/note.md", "w") { |f| f.print release_note }
141
+ matrix[:npm].each do |task|
142
+ artifact = task[:artifact_name]
143
+ tarball = Dir.glob("release/#{artifact}/*")
144
+ next if tarball.empty?
145
+ tarball = tarball[0]
146
+ # tolerate failure as a case that has already been released
147
+ npm_tag = nightly ? "next" : "latest"
148
+ sh_or_warn %Q(npm publish --tag #{npm_tag} #{tarball})
149
+ end
150
+ sh %Q(gh release create #{args[:tag]} --title #{args[:tag]} --notes-file release/note.md #{nightly ? "--prerelease" : ""} #{files.join(" ")})
151
+ end
152
+ end
data/rakelib/doc.rake ADDED
@@ -0,0 +1,29 @@
1
+ require "rdoc/task"
2
+ require "ruby_wasm/version"
3
+
4
+ RDoc::Task.new do |doc|
5
+ doc.main = "README.md"
6
+ doc.title = "ruby.wasm Documentation"
7
+ doc.rdoc_files =
8
+ FileList.new %w[
9
+ *.md
10
+ packages/gems/js/ext/**/*.c
11
+ packages/gems/js/lib/**/*.rb
12
+ ]
13
+ end
14
+
15
+ namespace :doc do
16
+ desc "Update docs/api/javascript.md"
17
+ task :api_js do
18
+ sh "npx",
19
+ "documentation",
20
+ "readme",
21
+ "--readme-file",
22
+ "./packages/npm-packages/ruby-wasm-wasi/README.md",
23
+ "--section",
24
+ "API",
25
+ "--markdown-toc",
26
+ "false",
27
+ "./packages/npm-packages/ruby-wasm-wasi/dist/esm/index.js"
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ namespace :format do
2
+ begin
3
+ require "syntax_tree/rake_tasks"
4
+ SyntaxTree::Rake::WriteTask.new(
5
+ :ruby,
6
+ Rake::FileList[
7
+ "Rakefile",
8
+ "lib/**/*.rb",
9
+ "ext/**/*.rb",
10
+ "test/**/*.rb",
11
+ "rakelib/**/*.rake",
12
+ "packages/**/*.rb"
13
+ ]
14
+ )
15
+ rescue LoadError
16
+ end
17
+
18
+ task :js do
19
+ sh "npm run format", chdir: "packages/npm-packages/ruby-wasm-wasi"
20
+ end
21
+
22
+ task :c do
23
+ sh "find packages/gems/ ext/ -iname *.h -o -iname *.c | xargs clang-format -i"
24
+ end
25
+ end
26
+
27
+ task :format do
28
+ if Rake::Task.task_defined?("format:ruby")
29
+ Rake::Task["format:ruby"].invoke
30
+ else
31
+ puts "\e[33mSyntaxTree not installed, skipping format:ruby\e[0m"
32
+ end
33
+ Rake::Task["format:js"].invoke
34
+ Rake::Task["format:c"].invoke
35
+ end
data/rakelib/gem.rake ADDED
@@ -0,0 +1,22 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/test_*.rb"]
8
+ end
9
+
10
+ begin
11
+ require "rb_sys/extensiontask"
12
+
13
+ gemspec = Gem::Specification.load("ruby_wasm.gemspec")
14
+ RbSys::ExtensionTask.new("ruby_wasm", gemspec) do |ext|
15
+ ext.lib_dir = "lib/ruby_wasm"
16
+ end
17
+ rescue LoadError => e
18
+ task :compile do
19
+ $stderr.puts "Skipping compilation of ruby_wasm extension: #{e.message}"
20
+ exit 1
21
+ end
22
+ end
@@ -0,0 +1,151 @@
1
+ wasi_vfs = RubyWasm::WasiVfsProduct.new(File.join(Dir.pwd, "build"))
2
+ wasi_sdk = TOOLCHAINS["wasi-sdk"]
3
+ tools = {
4
+ "WASI_VFS_CLI" => File.expand_path(File.join(__dir__, "..", "exe", "rbwasm")),
5
+ "WASMOPT" => wasi_sdk.wasm_opt
6
+ }
7
+
8
+ def npm_pkg_build_command(pkg)
9
+ # Skip if the package does not require building ruby
10
+ return nil unless pkg[:ruby_version] && pkg[:target]
11
+ [
12
+ "bundle",
13
+ "exec",
14
+ "rbwasm",
15
+ "build",
16
+ "--ruby-version",
17
+ pkg[:ruby_version],
18
+ "--target",
19
+ pkg[:target],
20
+ "--build-profile",
21
+ "full"
22
+ ]
23
+ end
24
+
25
+ def npm_pkg_rubies_cache_key(pkg)
26
+ build_command = npm_pkg_build_command(pkg)
27
+ return nil unless build_command
28
+ require "open3"
29
+ cmd = build_command + ["--print-ruby-cache-key"]
30
+ stdout, status = Open3.capture2(*cmd)
31
+ unless status.success?
32
+ raise "Command failed with status (#{status.exitstatus}): #{cmd.join ""}"
33
+ end
34
+ require "json"
35
+ JSON.parse(stdout)["hexdigest"]
36
+ end
37
+
38
+ namespace :npm do
39
+ NPM_PACKAGES.each do |pkg|
40
+ base_dir = Dir.pwd
41
+ pkg_dir = "#{Dir.pwd}/packages/npm-packages/#{pkg[:name]}"
42
+
43
+ namespace pkg[:name] do
44
+ desc "Build ruby for npm package #{pkg[:name]}"
45
+ task "ruby" do
46
+ build_command = npm_pkg_build_command(pkg)
47
+ # Skip if the package does not require building ruby
48
+ next unless build_command
49
+
50
+ env = {
51
+ # Share ./build and ./rubies in the same workspace
52
+ "RUBY_WASM_ROOT" => base_dir
53
+ }
54
+ if gemfile_path = pkg[:gemfile]
55
+ env["BUNDLE_GEMFILE"] = File.join(base_dir, gemfile_path)
56
+ else
57
+ # Explicitly disable rubygems integration since Bundler finds
58
+ # Gemfile in the repo root directory.
59
+ build_command.push "--disable-gems"
60
+ end
61
+ dist_dir = File.join(pkg_dir, "dist")
62
+ mkdir_p dist_dir
63
+ if pkg[:target] == "wasm32-unknown-wasi"
64
+ sh env,
65
+ *build_command,
66
+ "--no-stdlib",
67
+ "-o",
68
+ File.join(dist_dir, "ruby.wasm")
69
+ sh env,
70
+ *build_command,
71
+ "-o",
72
+ File.join(dist_dir, "ruby.debug+stdlib.wasm")
73
+ sh wasi_sdk.wasm_opt,
74
+ "--strip-debug",
75
+ File.join(dist_dir, "ruby.wasm"),
76
+ "-o",
77
+ File.join(dist_dir, "ruby.wasm")
78
+ sh wasi_sdk.wasm_opt,
79
+ "--strip-debug",
80
+ File.join(dist_dir, "ruby.debug+stdlib.wasm"),
81
+ "-o",
82
+ File.join(dist_dir, "ruby+stdlib.wasm")
83
+ elsif pkg[:target] == "wasm32-unknown-emscripten"
84
+ sh env, *build_command, "-o", "/dev/null"
85
+ end
86
+ end
87
+
88
+ desc "Build npm package #{pkg[:name]}"
89
+ task "build" => ["ruby"] do
90
+ sh tools, "npm run build", chdir: pkg_dir
91
+ end
92
+
93
+ desc "Check npm package #{pkg[:name]}"
94
+ task "check" do
95
+ sh "npm test", chdir: pkg_dir
96
+ end
97
+ end
98
+
99
+ desc "Make tarball for npm package #{pkg[:name]}"
100
+ task pkg[:name] do
101
+ wasi_sdk.install_binaryen
102
+ Rake::Task["npm:#{pkg[:name]}:build"].invoke
103
+ sh "npm pack", chdir: pkg_dir
104
+ end
105
+ end
106
+
107
+ desc "Configure for pre-release"
108
+ task :configure_prerelease, [:prerel] do |t, args|
109
+ require "json"
110
+ prerel = args[:prerel]
111
+ new_pkgs = {}
112
+ NPM_PACKAGES.each do |pkg|
113
+ pkg_dir = "#{Dir.pwd}/packages/npm-packages/#{pkg[:name]}"
114
+ pkg_json = "#{pkg_dir}/package.json"
115
+ package = JSON.parse(File.read(pkg_json))
116
+
117
+ version = package["version"] + "-#{prerel}"
118
+ new_pkgs[package["name"]] = version
119
+ sh *["npm", "pkg", "set", "version=#{version}"], chdir: pkg_dir
120
+ end
121
+
122
+ NPM_PACKAGES.each do |pkg|
123
+ pkg_dir = "#{Dir.pwd}/packages/npm-packages/#{pkg[:name]}"
124
+ pkg_json = "#{pkg_dir}/package.json"
125
+ package = JSON.parse(File.read(pkg_json))
126
+ (package["dependencies"] || []).each do |dep, _|
127
+ next unless new_pkgs[dep]
128
+ sh *["npm", "pkg", "set", "dependencies.#{dep}=#{new_pkgs[dep]}"],
129
+ chdir: pkg_dir
130
+ end
131
+ end
132
+ end
133
+
134
+ desc "Build all npm packages"
135
+ multitask all: NPM_PACKAGES.map { |pkg| pkg[:name] }
136
+ end
137
+
138
+ namespace :standalone do
139
+ STANDALONE_PACKAGES.each do |pkg|
140
+ pkg_dir = "#{Dir.pwd}/packages/standalone/#{pkg[:name]}"
141
+
142
+ desc "Build standalone package #{pkg[:name]}"
143
+ task "#{pkg[:name]}" => ["build:#{pkg[:build]}"] do
144
+ wasi_sdk.install_binaryen
145
+ base_dir = Dir.pwd
146
+ sh tools,
147
+ "./build-package.sh #{base_dir}/rubies/ruby-#{pkg[:build]}",
148
+ chdir: pkg_dir
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,40 @@
1
+ def bump_version_npm_package(package, version)
2
+ require "json"
3
+ pkg_dir = "#{Dir.pwd}/packages/npm-packages/#{package}"
4
+ pkg_json = "#{pkg_dir}/package.json"
5
+ package = JSON.parse(File.read(pkg_json))
6
+ old_version = package["version"]
7
+ pkg_name = package["name"]
8
+ package["version"] = version
9
+ File.write(pkg_json, JSON.pretty_generate(package) + "\n")
10
+
11
+ # Update package-lock.json
12
+ # Update README.md and other docs
13
+ `git grep -l #{pkg_name}@#{old_version}`.split.each do |file|
14
+ content = File.read(file)
15
+ next_nightly = Date.today.strftime("%Y-%m-%d")
16
+ content.gsub!(
17
+ /#{pkg_name}@#{old_version}-\d{4}-\d{2}-\d{2}-a/,
18
+ "#{pkg_name}@#{version}-#{next_nightly}-a"
19
+ )
20
+ content.gsub!(/#{pkg_name}@#{old_version}/, "#{pkg_name}@#{version}")
21
+ File.write(file, content)
22
+ end
23
+ end
24
+
25
+ def bump_version_rb(version_rb, version)
26
+ version_rb_content = File.read(version_rb)
27
+ version_rb_content.gsub!(/VERSION = ".+"/, "VERSION = \"#{version}\"")
28
+ File.write(version_rb, version_rb_content)
29
+ end
30
+
31
+ task :bump_version, %i[version] do |t, args|
32
+ version = args[:version] or raise "version is required"
33
+ bump_version_rb("lib/ruby_wasm/version.rb", version)
34
+ bump_version_rb("packages/gems/js/lib/js/version.rb", version)
35
+ NPM_PACKAGES.each { |pkg| bump_version_npm_package(pkg[:name], version) }
36
+ # Update ./package-lock.json
37
+ sh "npm install"
38
+ # Update Gemfile.lock
39
+ sh "BUNDLE_GEMFILE=packages/npm-packages/ruby-wasm-wasi/Gemfile bundle install"
40
+ end
data/sig/open_uri.rbs ADDED
@@ -0,0 +1,4 @@
1
+ # TODO: Upstream OpenURI sigs to rbs/stdlib
2
+ module OpenURI
3
+ def self.open_uri: [T] (*untyped, **untyped) { (untyped) -> T } -> T
4
+ end