We use binaryen's linker to produce a wasm file (via s2wasm). The wasm writer has capabilities to export source maps.
The produced source map contains references to the original file, that might require additional source map file processing to include / package original files with it.
#include <stdint.h>
#include <string>
+#include <sstream>
#include <stdlib.h>
#include "s2wasm.h"
struct BinaryenRustModule {
BufferWithRandomAccess buffer;
+ std::string sourceMapJSON;
};
struct BinaryenRustModuleOptions {
bool ignoreUnknownSymbols;
bool debugInfo;
std::string startFunction;
+ std::string sourceMapUrl;
BinaryenRustModuleOptions() :
globalBase(0),
importMemory(false),
ignoreUnknownSymbols(false),
debugInfo(false),
- startFunction("")
+ startFunction(""),
+ sourceMapUrl("")
{}
};
options->startFunction = start;
}
+extern "C" void
+BinaryenRustModuleOptionsSetSourceMapUrl(BinaryenRustModuleOptions *options,
+ char *sourceMapUrl) {
+ options->sourceMapUrl = sourceMapUrl;
+}
+
extern "C" void
BinaryenRustModuleOptionsSetStackAllocation(BinaryenRustModuleOptions *options,
uint64_t stack) {
{
WasmBinaryWriter writer(&linker.getOutput().wasm, ret->buffer, options->debug);
writer.setNamesSection(options->debugInfo);
- // FIXME: support source maps?
- // writer.setSourceMap(sourceMapStream.get(), sourceMapUrl);
+
+ std::unique_ptr<std::ostringstream> sourceMapStream = nullptr;
+ {
+ sourceMapStream = make_unique<std::ostringstream>();
+ writer.setSourceMap(sourceMapStream.get(), options->sourceMapUrl);
+ }
// FIXME: support symbol maps?
// writer.setSymbolMap(symbolMap);
writer.write();
+
+ if (sourceMapStream) {
+ ret->sourceMapJSON = sourceMapStream->str();
+ }
}
return ret.release();
}
return M->buffer.size();
}
+extern "C" const char*
+BinaryenRustModuleSourceMapPtr(const BinaryenRustModule *M) {
+ return M->sourceMapJSON.data();
+}
+
+extern "C" size_t
+BinaryenRustModuleSourceMapLen(const BinaryenRustModule *M) {
+ return M->sourceMapJSON.length();
+}
+
extern "C" void
BinaryenRustModuleFree(BinaryenRustModule *M) {
delete M;
slice::from_raw_parts(ptr, len)
}
}
+
+ /// Returns the data of the source map JSON.
+ pub fn source_map(&self) -> &[u8] {
+ unsafe {
+ let ptr = BinaryenRustModuleSourceMapPtr(self.ptr);
+ let len = BinaryenRustModuleSourceMapLen(self.ptr);
+ slice::from_raw_parts(ptr, len)
+ }
+ }
}
impl Drop for Module {
self
}
+ /// Configures a `sourceMappingURL` custom section value for the module.
+ pub fn source_map_url(&mut self, url: &str) -> &mut Self {
+ let url = CString::new(url).unwrap();
+ unsafe {
+ BinaryenRustModuleOptionsSetSourceMapUrl(self.ptr, url.as_ptr());
+ }
+ self
+ }
+
/// Configures how much stack is initially allocated for the module. 1MB is
/// probably good enough for now.
pub fn stack(&mut self, amt: u64) -> &mut Self {
-> *mut BinaryenRustModule;
fn BinaryenRustModulePtr(module: *const BinaryenRustModule) -> *const u8;
fn BinaryenRustModuleLen(module: *const BinaryenRustModule) -> usize;
+ fn BinaryenRustModuleSourceMapPtr(module: *const BinaryenRustModule) -> *const u8;
+ fn BinaryenRustModuleSourceMapLen(module: *const BinaryenRustModule) -> usize;
fn BinaryenRustModuleFree(module: *mut BinaryenRustModule);
fn BinaryenRustModuleOptionsCreate()
debuginfo: bool);
fn BinaryenRustModuleOptionsSetStart(module: *mut BinaryenRustModuleOptions,
start: *const libc::c_char);
+ fn BinaryenRustModuleOptionsSetSourceMapUrl(module: *mut BinaryenRustModuleOptions,
+ sourceMapUrl: *const libc::c_char);
fn BinaryenRustModuleOptionsSetStackAllocation(
module: *mut BinaryenRustModuleOptions,
stack: u64,
if asm2wasm && config.emit_obj {
let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
- binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out);
+ let suffix = ".wasm.map"; // FIXME use target suffix
+ let map = cgcx.output_filenames.path(OutputType::Exe)
+ .with_extension(&suffix[1..]);
+ binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out, &map);
timeline.record("binaryen");
if !config.emit_asm {
fn binaryen_assemble(cgcx: &CodegenContext,
handler: &Handler,
assembly: &Path,
- object: &Path) {
+ object: &Path,
+ map: &Path) {
use rustc_binaryen::{Module, ModuleOptions};
let input = fs::read(&assembly).and_then(|contents| {
let mut options = ModuleOptions::new();
if cgcx.debuginfo != config::NoDebugInfo {
options.debuginfo(true);
+ let map_file_name = map.file_name().unwrap();
+ options.source_map_url(map_file_name.to_str().unwrap());
}
if cgcx.crate_types.contains(&config::CrateTypeExecutable) {
options.start("main");
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
});
let err = assembled.and_then(|binary| {
- fs::write(&object, binary.data())
+ fs::write(&object, binary.data()).and_then(|()| {
+ if cgcx.debuginfo != config::NoDebugInfo {
+ fs::write(map, binary.source_map())
+ } else {
+ Ok(())
+ }
+ })
});
if let Err(e) = err {
handler.err(&format!("failed to run binaryen assembler: {}", e));