Class: RubyWasm::Packager

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_wasm/packager.rb

Overview

A class responsible for packaging whole Ruby project

Defined Under Namespace

Modules: ComponentAdapter Classes: Core, FileSystem

Constant Summary collapse

EXCLUDED_GEMS =

The list of excluded gems from the Bundler definition.

%w[ruby_wasm bundler]
ALL_DEFAULT_EXTS =
"cgi/escape,continuation,coverage,date,digest/bubblebabble,digest,digest/md5,digest/rmd160,digest/sha1,digest/sha2,etc,fcntl,json,json/generator,json/parser,objspace,pathname,psych,rbconfig/sizeof,ripper,stringio,strscan,monitor,zlib,openssl"

Instance Method Summary collapse

Constructor Details

#initialize(root, config = nil, definition = nil, features: RubyWasm::FeatureSet.derive_from_env) ⇒ Packager

Initializes a new instance of the RubyWasm::Packager class.

Parameters:

  • root (String)

    The root directory of the Ruby project. The root directory (will) contain the following files:

    * build_manifest.json
    * rubies
    * build
    
  • config (Hash) (defaults to: nil)

    The build config used for building Ruby.

  • definition (Bundler::Definition) (defaults to: nil)

    The Bundler definition.

  • features (RubyWasm::FeatureSet) (defaults to: RubyWasm::FeatureSet.derive_from_env)

    The features used for packaging.



13
14
15
16
17
18
# File 'lib/ruby_wasm/packager.rb', line 13

def initialize(root, config = nil, definition = nil, features: RubyWasm::FeatureSet.derive_from_env)
  @root = root
  @definition = definition
  @config = config
  @features = features
end

Instance Method Details

#build_optionsObject

Retrieves the build options used for building Ruby itself.



99
100
101
102
103
104
105
106
107
# File 'lib/ruby_wasm/packager.rb', line 99

def build_options
  default = {
    target: RubyWasm::Target.new("wasm32-unknown-wasip1"),
    default_exts: ALL_DEFAULT_EXTS
  }
  override = @config || {}
  # Merge the default options with the config options
  default.merge(override)
end

#featuresObject



91
92
93
# File 'lib/ruby_wasm/packager.rb', line 91

def features
  @features
end

#full_build_optionsObject

Retrieves the resolved build options



110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/ruby_wasm/packager.rb', line 110

def full_build_options
  options = build_options
  build_dir = File.join(@root, "build")
  rubies_dir = File.join(@root, "rubies")
  toolchain = RubyWasm::Toolchain.get(options[:target], build_dir)
  options.merge(
    toolchain: toolchain,
    build_dir: build_dir,
    rubies_dir: rubies_dir,
    src: options[:src]
  )
end

#package(executor, dest_dir, options) ⇒ Array<Integer>

Packages the Ruby code into a Wasm binary. (including extensions)

Parameters:

  • executor (RubyWasm::BuildExecutor)

    The executor for building the Wasm binary.

  • dest_dir (String)

    The destination used to construct the filesystem.

  • options (Hash)

    The packaging options.

Returns:

  • (Array<Integer>)

    The bytes of the packaged Wasm binary.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/ruby_wasm/packager.rb', line 26

def package(executor, dest_dir, options)
  ruby_core = self.ruby_core_build()
  tarball = ruby_core.build(executor, options)

  fs = RubyWasm::Packager::FileSystem.new(dest_dir, self)
  fs.package_ruby_root(tarball, executor)

  wasm_bytes = File.binread(File.join(fs.ruby_root, "bin", "ruby"))

  ruby_core.build_gem_exts(executor, fs.bundle_dir)

  fs.package_gems
  fs.remove_non_runtime_files(executor)
  if options[:stdlib]
    options[:without_stdlib_components].each do |component|
      fs.remove_stdlib_component(executor, component)
    end
  else
    fs.remove_stdlib(executor)
  end

  if full_build_options[:target] == "wasm32-unknown-wasip1" && !features.support_component_model?
    # wasi-vfs supports only WASI target
    wasi_vfs = RubyWasmExt::WasiVfs.new
    wasi_vfs.map_dir("/bundle", fs.bundle_dir)
    wasi_vfs.map_dir("/usr", File.dirname(fs.ruby_root))

    wasm_bytes = wasi_vfs.pack(wasm_bytes)
  end
  wasm_bytes = ruby_core.link_gem_exts(executor, fs.ruby_root, fs.bundle_dir, wasm_bytes)

  if features.support_component_model?
    wasi_virt = RubyWasmExt::WasiVirt.new
    wasi_virt.allow_all
    [
      { guest: "/bundle", host: fs.bundle_dir },
      { guest: "/usr", host: File.dirname(fs.ruby_root) }
    ].each do |map|
      map => { guest:, host: }
      RubyWasm.logger.debug "Adding files into VFS: #{host} => #{guest}"
      wasi_virt.map_dir(guest, host)
    end
    wasm_bytes = wasi_virt.compose(wasm_bytes)
  end

  wasm_bytes = RubyWasmExt.preinitialize(wasm_bytes) if options[:optimize]
  wasm_bytes
end

#ruby_core_buildObject



75
76
77
# File 'lib/ruby_wasm/packager.rb', line 75

def ruby_core_build
  @ruby_core_build ||= RubyWasm::Packager::Core.new(self)
end

#specsObject

Retrieves the specs from the Bundler definition, excluding the excluded gems.



83
84
85
86
87
88
89
# File 'lib/ruby_wasm/packager.rb', line 83

def specs
  return [] unless @definition
  __skip__ = @specs ||= @definition.resolve.materialize(@definition.requested_dependencies)
    .reject { |spec| EXCLUDED_GEMS.include?(spec.name) }
    .reject { |spec| spec.is_a?(Bundler::LazySpecification) }
  @specs
end