Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project: Add wasm32-unknown-unknown support (WASM) #93

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ A streaming compression/decompression library for rust with bindings to libbz2.
bzip2 = "0.4"
```

## WASM
bzip2-rs can be compiled to WASM. Make sure you added `wasm32-unknown-unknown` target
```bash
rustup target add wasm32-unknown-unknown
```
To build and run WASM example make sure that you working directory in terminal is `bzip2-sys`
### Build WASM target
```bash
cargo build --target wasm32-unknown-unknown --no-default-features --example it_work
```

### Run WASM target using wasmtime
```bash
wasmtime ..\target\wasm32-unknown-unknown\debug\examples\it_work.wasm --invoke test_decompress
```

# License

Expand Down
2 changes: 2 additions & 0 deletions bzip2-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ cc = "1.0"
[features]
# Enable this feature if you want to have a statically linked bzip2
static = []
std = [] # Use std types instead of libc in bindgen

41 changes: 38 additions & 3 deletions bzip2-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ extern crate cc;
extern crate pkg_config;

use std::path::PathBuf;
use std::{env, fs};
use std::{env, fmt, fs};

fn main() {
let mut cfg = cc::Build::new();
Expand All @@ -23,6 +23,29 @@ fn main() {
}
}

// List out the WASM targets that need wasm-shim.
// Note that Emscripten already provides its own C standard library so
// wasm32-unknown-emscripten should not be included here.
// See: https://github.com/gyscos/zstd-rs/pull/209
let need_wasm_shim = env::var("TARGET").map_or(false, |target| {
target == "wasm32-unknown-unknown" || target == "wasm32-wasi"
});

if need_wasm_shim {
cargo_print(&"rerun-if-changed=wasm-shim/stdlib.h");
cargo_print(&"rerun-if-changed=wasm-shim/string.h");

cfg.include("wasm-shim/");
cfg.define("XXH_STATIC_ASSERT", Some("0"));
cfg.opt_level(3);
}
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();

if target_arch == "wasm32" || target_os == "hermit" {
cargo_print(&"rustc-cfg=feature=\"std\"");
}

let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());

cfg.include("bzip2-1.0.8")
Expand All @@ -42,6 +65,18 @@ fn main() {
let include = dst.join("include");
fs::create_dir_all(&include).unwrap();
fs::copy(src.join("bzlib.h"), dst.join("include/bzlib.h")).unwrap();
println!("cargo:root={}", dst.display());
println!("cargo:include={}", dst.join("include").display());
cargo_print(&format_args!("cargo:root={}", dst.display()));
cargo_print(&format_args!(
"cargo:include={}",
dst.join("include").display()
));
}

/// Print a line for cargo.
///
/// If non-cargo is set, do not print anything.
fn cargo_print(content: &dyn fmt::Display) {
if cfg!(not(feature = "non-cargo")) {
println!("cargo:{}", content);
}
}
15 changes: 15 additions & 0 deletions bzip2-sys/bzlib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifdef PKG_CONFIG

/* Just use installed headers */
#include <bzlib.h>

#else // #ifdef PKG_CONFIG

#include "bzip2-1.0.8/bzlib.h"

#endif // #ifdef PKG_CONFIG


/* This file is used to generate bindings for both headers.
* Check update_bindings.sh to see how to use it.
* Or use the `bindgen` feature, which will create the bindings automatically. */
35 changes: 35 additions & 0 deletions bzip2-sys/examples/it_work.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#[cfg(feature = "std")]
use std::os::raw::{c_char, c_int, c_uint};

#[cfg(not(feature = "std"))]
use libc::{c_char, c_int, c_uint};

#[no_mangle]
pub extern "C" fn test_decompress() -> bool {
let uncompressed_bytes = include_bytes!("../bzip2-1.0.8/sample1.ref");
let compressed_bytes = include_bytes!("../bzip2-1.0.8/sample1.bz2");
let mut raw: Box<bzip2_sys::bz_stream> = unsafe { Box::new(std::mem::zeroed()) };
let mut buf: [u8; 100352] = [0; 98 * 1024];
unsafe {
assert_eq!(bzip2_sys::BZ2_bzDecompressInit(&mut *raw, 0, 0 as c_int), 0);
raw.next_in = compressed_bytes.as_ptr() as *mut c_char;
raw.avail_in = compressed_bytes.len().min(c_uint::MAX as usize) as c_uint;

raw.next_out = buf.as_mut_ptr() as *mut c_char;
raw.avail_out = buf.len() as c_uint;
assert_eq!(
bzip2_sys::BZ2_bzDecompress(&mut *raw),
bzip2_sys::BZ_STREAM_END
);
bzip2_sys::BZ2_bzDecompressEnd(&mut *raw);
};
let total_out = ((raw.total_out_lo32 as u64) | ((raw.total_out_hi32 as u64) << 32)) as usize;
assert_eq!(total_out, uncompressed_bytes.len());

let slice: &[u8] = buf[0..total_out].as_ref();
assert_eq!(uncompressed_bytes, slice);

return true;
}

fn main() {}
7 changes: 7 additions & 0 deletions bzip2-sys/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

extern crate libc;

#[cfg(target_arch = "wasm32")]
mod wasm_shim;

#[cfg(feature = "std")]
use std::os::raw::{c_char, c_int, c_uint, c_void};

#[cfg(not(feature = "std"))]
use libc::{c_char, c_int, c_uint, c_void};

pub const BZ_RUN: c_int = 0;
Expand Down
22 changes: 22 additions & 0 deletions bzip2-sys/wasm-shim/stdlib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <stddef.h>

#ifndef _STDLIB_H
#define _STDLIB_H 1

void *rust_zstd_wasm_shim_malloc(size_t size);
void *rust_zstd_wasm_shim_calloc(size_t nmemb, size_t size);
void rust_zstd_wasm_shim_free(void *ptr);

inline void *malloc(size_t size) {
return rust_zstd_wasm_shim_malloc(size);
}

inline void *calloc(size_t nmemb, size_t size) {
return rust_zstd_wasm_shim_calloc(nmemb, size);
}

inline void free(void *ptr) {
rust_zstd_wasm_shim_free(ptr);
}

#endif // _STDLIB_H
22 changes: 22 additions & 0 deletions bzip2-sys/wasm-shim/string.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <stdlib.h>

#ifndef _STRING_H
#define _STRING_H 1

void *rust_zstd_wasm_shim_memcpy(void *restrict dest, const void *restrict src, size_t n);
void *rust_zstd_wasm_shim_memmove(void *dest, const void *src, size_t n);
void *rust_zstd_wasm_shim_memset(void *dest, int c, size_t n);

inline void *memcpy(void *restrict dest, const void *restrict src, size_t n) {
return rust_zstd_wasm_shim_memcpy(dest, src, n);
}

inline void *memmove(void *dest, const void *src, size_t n) {
return rust_zstd_wasm_shim_memmove(dest, src, n);
}

inline void *memset(void *dest, int c, size_t n) {
return rust_zstd_wasm_shim_memset(dest, c, n);
}

#endif // _STRING_H
55 changes: 55 additions & 0 deletions bzip2-sys/wasm_shim.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use std::alloc::{alloc, dealloc, Layout};
use std::os::raw::{c_int, c_void};

#[no_mangle]
pub extern "C" fn rust_zstd_wasm_shim_malloc(size: usize) -> *mut c_void {
unsafe {
let layout = Layout::from_size_align_unchecked(size, 1);
alloc(layout).cast()
}
}

#[no_mangle]
pub extern "C" fn rust_zstd_wasm_shim_calloc(nmemb: usize, size: usize) -> *mut c_void {
unsafe {
let layout = Layout::from_size_align_unchecked(size * nmemb, 1);
alloc(layout).cast()
}
}

#[no_mangle]
pub unsafe extern "C" fn rust_zstd_wasm_shim_free(ptr: *mut c_void) {
// layout is not actually used
let layout = Layout::from_size_align_unchecked(1, 1);
dealloc(ptr.cast(), layout);
}

#[no_mangle]
pub unsafe extern "C" fn rust_zstd_wasm_shim_memcpy(
dest: *mut c_void,
src: *const c_void,
n: usize,
) -> *mut c_void {
std::ptr::copy_nonoverlapping(src as *const u8, dest as *mut u8, n);
dest
}

#[no_mangle]
pub unsafe extern "C" fn rust_zstd_wasm_shim_memmove(
dest: *mut c_void,
src: *const c_void,
n: usize,
) -> *mut c_void {
std::ptr::copy(src as *const u8, dest as *mut u8, n);
dest
}

#[no_mangle]
pub unsafe extern "C" fn rust_zstd_wasm_shim_memset(
dest: *mut c_void,
c: c_int,
n: usize,
) -> *mut c_void {
std::ptr::write_bytes(dest as *mut u8, c as u8, n);
dest
}