Skip to content

Commit 5e50d3e

Browse files
Merge pull request #616 from ruby/katei/wasi-sdk-25
Bump wasi-sdk to 24
2 parents 672c474 + 273d909 commit 5e50d3e

File tree

15 files changed

+289
-149
lines changed

15 files changed

+289
-149
lines changed

.github/workflows/build-gems.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
supported-ruby-platforms: |
2121
exclude: [arm-linux, x64-mingw32, aarch64-mingw-ucrt]
2222
stable-ruby-versions: |
23-
exclude: [head]
23+
exclude: [head, "4.0"]
2424
2525
cross-gem:
2626
name: Compile native gem for ${{ matrix.ruby-platform }}

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ $ npm install --save @ruby/wasm-wasi@2.7.2-2025-10-03-a
138138
When a new version of Ruby is released, the following steps need to be taken to add support for it in ruby.wasm:
139139

140140
1. Update `lib/ruby_wasm/cli.rb`:
141-
- Add a new entry in the `build_source_aliases` method for the new version
141+
- Add a new entry in the `build_config_aliases` method for the new version
142142
- Specify the tarball URL and required default extensions
143143

144144
2. Update `Rakefile`:

Rakefile

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ NPM_PACKAGES = [
2929
name: "ruby-head-wasm-wasi",
3030
ruby_version: "head",
3131
gemfile: "packages/npm-packages/ruby-head-wasm-wasi/Gemfile",
32-
target: "wasm32-unknown-wasip1",
32+
target: "wasm32-unknown-wasip1"
3333
},
3434
{
3535
name: "ruby-head-wasm-wasip2",
3636
ruby_version: "head",
3737
gemfile: "packages/npm-packages/ruby-head-wasm-wasip2/Gemfile",
3838
target: "wasm32-unknown-wasip2",
39-
enable_component_model: true,
39+
enable_component_model: true
4040
},
4141
{
4242
name: "ruby-3.4-wasm-wasi",
@@ -66,16 +66,6 @@ STANDALONE_PACKAGES = [
6666

6767
LIB_ROOT = File.dirname(__FILE__)
6868

69-
TOOLCHAINS = {}
70-
BUILDS
71-
.map { |_, target, _| target }
72-
.uniq
73-
.each do |target|
74-
build_dir = File.join(LIB_ROOT, "build")
75-
toolchain = RubyWasm::Toolchain.get(target, build_dir)
76-
TOOLCHAINS[toolchain.name] = toolchain
77-
end
78-
7969
class BuildTask < Struct.new(:name, :target, :build_command)
8070
def ruby_cache_key
8171
return @key if @key

lib/ruby_wasm/build.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def initialize(
4343
@target = target
4444
@build_dir = build_dir
4545
@rubies_dir = rubies_dir
46-
@toolchain = (toolchain || RubyWasm::Toolchain.get(target, @build_dir))
46+
@toolchain = toolchain || raise("toolchain is required")
4747

4848
@libyaml = RubyWasm::LibYAMLProduct.new(@build_dir, @target, @toolchain)
4949
@zlib = RubyWasm::ZlibProduct.new(@build_dir, @target, @toolchain)

lib/ruby_wasm/build/executor.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,16 @@ def _print_command(args, env)
147147
end
148148
end
149149

150+
class SilentExecutor
151+
def system(*args, chdir: nil, env: nil)
152+
# @type var kwargs: Hash[Symbol, untyped]
153+
kwargs = {}
154+
kwargs[:chdir] = chdir if chdir
155+
kwargs[:exception] = true
156+
__skip__ = env ? Kernel.system(env, *args, **kwargs) : Kernel.system(*args, **kwargs)
157+
end
158+
end
159+
150160
# Human readable status printer for the build.
151161
class StatusPrinter
152162
def initialize

lib/ruby_wasm/build/product/crossruby.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ def build_exts(executor)
204204
def build(executor, remake: false, reconfigure: false)
205205
executor.mkdir_p dest_dir
206206
executor.mkdir_p build_dir
207-
@toolchain.install
207+
@toolchain.install(executor)
208208
[@source, @baseruby, @libyaml, @zlib, @openssl, @wasi_vfs].each do |prod|
209209
next unless prod
210210
executor.begin_section prod.class, prod.name, "Building"

lib/ruby_wasm/build/toolchain.rb

Lines changed: 144 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,15 @@ def check_envvar(name)
1616
raise "missing environment variable: #{name}" if ENV[name].nil?
1717
end
1818

19-
def self.get(target, build_dir = nil)
19+
def self.get(target, options, build_dir = nil)
2020
case target
2121
when /^wasm32-unknown-wasi/
22-
return RubyWasm::WASISDK.new(build_dir: build_dir)
22+
return(
23+
RubyWasm::WASISDK.new(
24+
build_dir: build_dir,
25+
version: options[:wasi_sdk_version]
26+
)
27+
)
2328
when "wasm32-unknown-emscripten"
2429
return RubyWasm::Emscripten.new
2530
else
@@ -56,32 +61,24 @@ class WASISDK < Toolchain
5661
def initialize(
5762
wasi_sdk_path = ENV["WASI_SDK_PATH"],
5863
build_dir: nil,
59-
version_major: 22,
60-
version_minor: 0,
64+
version: "23.0",
6165
binaryen_version: 108
6266
)
63-
@wasm_opt_path = Toolchain.find_path("wasm-opt")
6467
@need_fetch_wasi_sdk = wasi_sdk_path.nil?
65-
@need_fetch_binaryen = @wasm_opt_path.nil?
66-
6768
if @need_fetch_wasi_sdk
6869
if build_dir.nil?
6970
raise "build_dir is required when WASI_SDK_PATH is not set"
7071
end
71-
wasi_sdk_path = File.join(build_dir, "toolchain", "wasi-sdk")
72-
@version_major = version_major
73-
@version_minor = version_minor
74-
end
75-
76-
if @need_fetch_binaryen
77-
if build_dir.nil?
78-
raise "build_dir is required when wasm-opt not installed in PATH"
72+
wasi_sdk_path = File.join(build_dir, "toolchain", "wasi-sdk-#{version}")
73+
if version.nil?
74+
raise "version is required when WASI_SDK_PATH is not set"
7975
end
80-
@binaryen_path = File.join(build_dir, "toolchain", "binaryen")
81-
@binaryen_version = binaryen_version
82-
@wasm_opt_path = File.join(@binaryen_path, "bin", "wasm-opt")
76+
@version = version
8377
end
8478

79+
@binaryen =
80+
Binaryen.new(build_dir: build_dir, binaryen_version: binaryen_version)
81+
8582
@tools = {
8683
cc: "#{wasi_sdk_path}/bin/clang",
8784
cxx: "#{wasi_sdk_path}/bin/clang++",
@@ -101,27 +98,127 @@ def find_tool(name)
10198
end
10299

103100
def wasm_opt
104-
@wasm_opt_path
101+
@binaryen.wasm_opt
105102
end
106103

107104
def wasi_sdk_path
108105
@wasi_sdk_path
109106
end
110107

111-
def download_url(version_major, version_minor)
112-
version = "#{version_major}.#{version_minor}"
108+
def download_url
109+
major, _ = @version.split(".").map(&:to_i)
110+
# @type var assets: Array[[Regexp, Array[String]]]
113111
assets = [
114-
[/x86_64-linux/, "wasi-sdk-#{version}-linux.tar.gz"],
115-
[/(arm64e?|x86_64)-darwin/, "wasi-sdk-#{version}-macos.tar.gz"]
112+
[
113+
/x86_64-linux/,
114+
[
115+
"wasi-sdk-#{@version}-x86_64-linux.tar.gz",
116+
# For wasi-sdk version < 23.0
117+
"wasi-sdk-#{@version}-linux.tar.gz"
118+
]
119+
],
120+
[
121+
/arm64e?-darwin/,
122+
[
123+
"wasi-sdk-#{@version}-arm64-macos.tar.gz",
124+
# For wasi-sdk version < 23.0
125+
"wasi-sdk-#{@version}-macos.tar.gz"
126+
]
127+
],
128+
[
129+
/x86_64-darwin/,
130+
[
131+
"wasi-sdk-#{@version}-x86_64-macos.tar.gz",
132+
# For wasi-sdk version < 23.0
133+
"wasi-sdk-#{@version}-macos.tar.gz"
134+
]
135+
]
116136
]
117-
asset = assets.find { |os, _| os =~ RUBY_PLATFORM }&.at(1)
137+
asset = assets.find { |os, candidates| os =~ RUBY_PLATFORM }
118138
if asset.nil?
119139
raise "unsupported platform for fetching WASI SDK: #{RUBY_PLATFORM}"
120140
end
121-
"https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-#{version_major}/#{asset}"
141+
_, candidates = asset
142+
candidates_urls =
143+
candidates.map do |candidate|
144+
"https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-#{major}/#{candidate}"
145+
end
146+
require "net/http"
147+
# Find an asset that exists by checking HEAD response to see if the asset exists
148+
candidates_urls.each do |url_str|
149+
# @type var url: URI::HTTPS
150+
url = URI.parse(url_str)
151+
ok =
152+
__skip__ = Net::HTTP.start(
153+
url.host,
154+
url.port,
155+
use_ssl: url.scheme == "https"
156+
) do |http|
157+
response = http.head(url.request_uri)
158+
next response.code == "302"
159+
end
160+
return url_str if ok
161+
end
162+
raise "WASI SDK asset not found: #{candidates_urls.join(", ")}"
163+
end
164+
165+
def install_wasi_sdk(executor)
166+
return unless @need_fetch_wasi_sdk
167+
wasi_sdk_tarball =
168+
File.join(File.dirname(@wasi_sdk_path), "wasi-sdk-#{@version}.tar.gz")
169+
unless File.exist? wasi_sdk_tarball
170+
FileUtils.mkdir_p File.dirname(wasi_sdk_tarball)
171+
executor.system "curl",
172+
"-fsSL",
173+
"-o",
174+
wasi_sdk_tarball,
175+
self.download_url
176+
end
177+
unless File.exist? @wasi_sdk_path
178+
FileUtils.mkdir_p @wasi_sdk_path
179+
executor.system "tar",
180+
"-C",
181+
@wasi_sdk_path,
182+
"--strip-component",
183+
"1",
184+
"-xzf",
185+
wasi_sdk_tarball
186+
end
187+
end
188+
189+
def install(executor)
190+
install_wasi_sdk(executor)
191+
@binaryen.install(executor)
192+
end
193+
end
194+
195+
class Binaryen
196+
def initialize(build_dir: nil, binaryen_version: 108)
197+
@wasm_opt_path = Toolchain.find_path("wasm-opt")
198+
@need_fetch_binaryen = @wasm_opt_path.nil?
199+
if @need_fetch_binaryen
200+
if build_dir.nil?
201+
raise "build_dir is required when wasm-opt not installed in PATH"
202+
end
203+
@binaryen_path = File.join(build_dir, "toolchain", "binaryen")
204+
@binaryen_version = binaryen_version
205+
@wasm_opt_path = File.join(@binaryen_path, "bin", "wasm-opt")
206+
end
207+
end
208+
209+
def wasm_opt
210+
@wasm_opt_path
122211
end
123212

124-
def binaryen_download_url(version)
213+
def binaryen_path
214+
@binaryen_path
215+
end
216+
217+
def binaryen_version
218+
@binaryen_version
219+
end
220+
221+
def download_url(version)
125222
assets = [
126223
[
127224
/x86_64-linux/,
@@ -143,47 +240,44 @@ def binaryen_download_url(version)
143240
"https://github.com/WebAssembly/binaryen/releases/download/version_#{@binaryen_version}/#{asset}"
144241
end
145242

146-
def install_wasi_sdk
147-
return unless @need_fetch_wasi_sdk
148-
wasi_sdk_tarball =
149-
File.join(File.dirname(@wasi_sdk_path), "wasi-sdk.tar.gz")
150-
unless File.exist? wasi_sdk_tarball
151-
FileUtils.mkdir_p File.dirname(wasi_sdk_tarball)
152-
system "curl -L -o #{wasi_sdk_tarball} #{self.download_url(@version_major, @version_minor)}"
153-
end
154-
unless File.exist? @wasi_sdk_path
155-
FileUtils.mkdir_p @wasi_sdk_path
156-
system "tar -C #{@wasi_sdk_path} --strip-component 1 -xzf #{wasi_sdk_tarball}"
157-
end
158-
end
159-
160-
def install_binaryen
243+
def install(executor)
161244
return unless @need_fetch_binaryen
162245
binaryen_tarball = File.expand_path("../binaryen.tar.gz", @binaryen_path)
163246
unless File.exist? binaryen_tarball
164247
FileUtils.mkdir_p File.dirname(binaryen_tarball)
165-
system "curl -L -o #{binaryen_tarball} #{self.binaryen_download_url(@binaryen_version)}"
248+
executor.system "curl",
249+
"-L",
250+
"-o",
251+
binaryen_tarball,
252+
self.download_url(@binaryen_version)
166253
end
167254

168255
unless File.exist? @binaryen_path
169256
FileUtils.mkdir_p @binaryen_path
170-
system "tar -C #{@binaryen_path} --strip-component 1 -xzf #{binaryen_tarball}"
257+
executor.system "tar",
258+
"-C",
259+
@binaryen_path,
260+
"--strip-component",
261+
"1",
262+
"-xzf",
263+
binaryen_tarball
171264
end
172265
end
173-
174-
def install
175-
install_wasi_sdk
176-
install_binaryen
177-
end
178266
end
179267

180268
class Emscripten < Toolchain
181269
def initialize
182-
@tools = { cc: "emcc", cxx: "em++", ld: "emcc", ar: "emar", ranlib: "emranlib" }
270+
@tools = {
271+
cc: "emcc",
272+
cxx: "em++",
273+
ld: "emcc",
274+
ar: "emar",
275+
ranlib: "emranlib"
276+
}
183277
@name = "emscripten"
184278
end
185279

186-
def install
280+
def install(executor)
187281
end
188282

189283
def find_tool(name)

0 commit comments

Comments
 (0)