@@ -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