wasm_split_cli_support/
lib.rs1use std::{
2 collections::HashMap,
3 path::{Path, PathBuf},
4};
5
6use eyre::{Result, WrapErr};
7use split_point::SplitModuleIdentifier;
8
9mod dep_graph;
10mod emit;
11mod graph_utils;
12mod js;
13mod magic_constants;
14mod read;
15mod reloc;
16mod split_point;
17mod util;
18
19#[non_exhaustive]
20pub struct Options<'a> {
21 pub input_wasm: &'a [u8],
23 pub output_dir: &'a Path,
27 pub main_out_path: &'a Path,
32 pub link_name: &'a str,
37 pub main_module: &'a str,
41 pub verbose: bool,
45 #[doc(hidden)]
47 pub strict_tests: bool,
48}
49
50impl<'wasm> Options<'wasm> {
51 pub fn new(input_wasm: &'wasm [u8]) -> Self {
52 Self {
53 input_wasm,
54 output_dir: Path::new("wasm_split"),
55 main_out_path: Path::new("wasm_split/main.wasm"),
56 link_name: "./__wasm_split.js",
57 main_module: "./main.js",
58 verbose: false,
59 strict_tests: false,
60 }
61 }
62}
63
64#[non_exhaustive]
65pub struct SplitWasm {
66 pub split_modules: Vec<PathBuf>,
67 pub prefetch_map: HashMap<String, Vec<String>>,
70}
71
72pub fn transform(opts: Options) -> Result<SplitWasm> {
73 let strictness = if opts.strict_tests {
74 read::Strictness::IntegrationTesting
75 } else {
76 read::Strictness::Lenient
77 };
78 let module = crate::read::InputModule::parse(opts.input_wasm, strictness)?;
80 if opts.verbose {
81 module.reloc_info.print_relocs();
82 }
83 let (dep_graph, reloc_stub_fns) = dep_graph::get_dependencies(&module)?;
85 let split_points = split_point::get_split_points(&module)?;
86 let split_program_info = split_point::compute_split_modules(&module, &dep_graph, split_points)?;
87
88 if split_point::trace_enabled(opts.verbose) {
89 for (name, split_deps) in split_program_info.output_modules.iter() {
90 split_deps.print(format!("{:?}", name).as_str(), &module);
91 }
92 }
93 let link_module = opts.link_name;
95 let emit_state = emit::EmitState::new(
96 &opts,
97 &module,
98 &split_program_info,
99 link_module,
100 reloc_stub_fns,
101 )?;
102 let wasm_modules = emit::emit_modules(
103 &split_program_info,
104 &emit_state,
105 |output_module_index, identifier, data| {
106 let output_path = match identifier {
107 SplitModuleIdentifier::Main => opts.main_out_path.to_path_buf(),
108 _ => opts
109 .output_dir
110 .join(identifier.filename(output_module_index) + ".wasm"),
111 };
112 (identifier, output_path, data)
113 },
114 )?;
115 let js_link_module = js::link_module(opts.main_module, &split_program_info, &emit_state)?;
116 std::fs::create_dir_all(opts.output_dir)?;
118 let mut split_modules = vec![];
119 for (identifier, output_path, data) in wasm_modules {
120 std::fs::write(&output_path, &data)
122 .with_context(|| format!("Error emitting {:?}", identifier))?;
123 if !matches!(identifier, SplitModuleIdentifier::Main) {
124 split_modules.push(output_path);
125 }
126 }
127 let prefetch_map = js_link_module.emit(&opts.output_dir.join(Path::new(link_module)))?;
128
129 Ok(SplitWasm {
130 split_modules,
131 prefetch_map,
132 })
133}