Skip to content

Commit

Permalink
Get hydroflow to compile to WASM (hydro-project#329)
Browse files Browse the repository at this point in the history
Tests do not work yet; I have a followup PR.

1. Turn off diagnostics for non-proc-macro crates. Diagnostics don't
   work when building for WASM. The proc-macro crates that are compiled
   at compile time still enable diagonstics because they target the
   (presumably non-WASM) host architecture where diagonstics work.

2. Use version 2 for the Cargo feature resolver. The version 1 resolver
   does not treat proc-macro edges differently from regular dependency
   edges. That is, suppose we depend on package P transitively via both
   a proc-macro edge and a regular edge, and the proc-macro edge enables
   feature X but the regular edge does not.

   With the version 1 resolver, Cargo will compile P only once with X
   enabled (assuming same host and target arch). With the v2 resolver,
   Cargo will compile P (at least) twice; once with X enabled for the
   proc-macro crate, once with P disabled.

   In our project, P = {hydroflow_datalog_core, hydroflow_lang}, X =
   diagnostics. The version 1 resolver works for non-WASM builds
   (because diagnostics compiles fine), but for WASM builds the v1
   resolver attempts to build hydroflow_datalog_core for WASM with
   diagnostics enabled (because of feature resolution).

   Note that enabling the v2 feature resolver should not change compile
   times: on non-WASM, diagnostics is always enabled so we only compile
   P once. On WASM builds, we would have compiled twice anyway (once for
   the host architecture for the proc-macro package, another for WASM).

3. Turn on only a subset of Tokio features when compiling for WASM. In
   particular, the WASM environment does not natively support threads
   and fails to compile with threading features enabled.

4. Manually enable the "js" feature for hydroflow/getrandom. See the
   comment in hydroflow/Cargo.toml.
  • Loading branch information
tylerhou committed Mar 1, 2023
1 parent 449e073 commit 465bcab
Show file tree
Hide file tree
Showing 15 changed files with 56 additions and 10 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ members = [
"variadics",
]

resolver = "2"

[profile.release]
strip = true # Strip symbols from the binary
opt-level = "z" # Optimize for size
Expand Down
23 changes: 19 additions & 4 deletions hydroflow/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,29 @@ serde = { version = "1", features = [ "derive" ] }
serde_json = "1"
slotmap = "1.0"
static_assertions = "1.1.0"
tokio = { version = "1.16", features = [ "full" ] }
tokio-stream = { version = "0.1.10", features = [ "io-util" ] }
tokio-util = { version = "0.7.4", features = [ "net", "codec" ] }
variadics = { path = "../variadics" }
rustc-hash = "1.1.0"
tempfile = { version = "3.3.0", optional = true }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "1.16", features = [ "full" ] }
tokio-util = { version = "0.7.4", features = [ "net", "codec" ] }

[target.'cfg(target_arch = "wasm32")'.dependencies]
tokio = { version = "1.16", features = [ "rt" , "sync", "macros", "io-util", "time" ] }
tokio-util = { version = "0.7.4", features = [ "codec" ] }
# We depend on getrandom transitively through rand. To compile getrandom to
# WASM, we need to enable its "js" feature. However, rand does not expose a
# passthrough to enable "js" on getrandom. As a workaround, we enable the
# getrandom js feature here; when the feature resolver computes the set of
# features for getrandom (unification), it will include "js".
getrandom = { version = "0.2.6", features = [ "js" ] }

[dev-dependencies]
chrono = { version = "0.4.20", features = [ "serde" ], default-features = false }
chrono = { version = "0.4.20", features = [ "serde", "clock" ], default-features = false }
clap = { version = "4.1.8", features = [ "derive" ] }
colored = "2.0"
criterion = { version = "0.4", features = [ "async_tokio", "html_reports" ] }
futures = { version = "0.3" }
itertools = "0.10.3"
rand = "0.8.4"
Expand All @@ -84,3 +95,7 @@ trybuild = "1.0.71"
hdrhistogram = "7"
zipf = "7.0.0"
core_affinity = "0.5.10"

[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
# Rayon (rust data-parallelism library) does not compile on WASM.
criterion = { version = "0.4", features = [ "async_tokio", "html_reports" ] }
2 changes: 2 additions & 0 deletions hydroflow/src/scheduled/net/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![cfg(not(target_arch = "wasm32"))]

//! This module contiains networking code.
//!
//! ## How Tokio interacts with Hydroflow (Mingwei 2021-12-07)
Expand Down
2 changes: 2 additions & 0 deletions hydroflow/src/scheduled/net/network_vertex.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![cfg(not(target_arch = "wasm32"))]

use std::collections::HashMap;

use futures::{SinkExt, StreamExt};
Expand Down
5 changes: 5 additions & 0 deletions hydroflow/src/util/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
//! Helper utilities for the Hydroflow surface syntax.
mod udp;
#[cfg(not(target_arch = "wasm32"))]
pub use udp::*;

mod tcp;
#[cfg(not(target_arch = "wasm32"))]
pub use tcp::*;

#[cfg(unix)]
Expand Down Expand Up @@ -106,11 +109,13 @@ pub fn ipv4_resolve(addr: &str) -> Result<SocketAddr, std::io::Error> {
}
}

#[cfg(not(target_arch = "wasm32"))]
pub async fn bind_udp_bytes(addr: SocketAddr) -> (UdpSink, UdpStream, SocketAddr) {
let socket = tokio::net::UdpSocket::bind(addr).await.unwrap();
udp_bytes(socket)
}

#[cfg(not(target_arch = "wasm32"))]
pub async fn bind_udp_lines(addr: SocketAddr) -> (UdpLinesSink, UdpLinesStream, SocketAddr) {
let socket = tokio::net::UdpSocket::bind(addr).await.unwrap();
udp_lines(socket)
Expand Down
2 changes: 2 additions & 0 deletions hydroflow/src/util/tcp.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![cfg(not(target_arch = "wasm32"))]

use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
use tokio::net::TcpStream;
use tokio_util::codec::{
Expand Down
2 changes: 2 additions & 0 deletions hydroflow/src/util/udp.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![cfg(not(target_arch = "wasm32"))]

use std::net::SocketAddr;

use bytes::Bytes;
Expand Down
2 changes: 2 additions & 0 deletions hydroflow/tests/surface_async.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![cfg(not(target_arch = "wasm32"))]

//! Surface syntax tests of asynchrony and networking.
use std::collections::{BTreeSet, HashSet};
Expand Down
5 changes: 4 additions & 1 deletion hydroflow_datalog/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ quote = "1.0.0"
syn = { version = "1.0.0", features = [ "parsing", "extra-traits" ] }
proc-macro2 = "1.0.27"
proc-macro-crate = "1.1.0"
hydroflow_datalog_core = { path = "../hydroflow_datalog_core" }
# Note: If we ever compile this proc macro crate to WASM (e.g., if we are
# building on a WASM host), we may need to turn diagnostics off for WASM if
# proc_macro2 does not support WASM at that time.
hydroflow_datalog_core = { path = "../hydroflow_datalog_core", features = [ "diagnostics" ] }
4 changes: 2 additions & 2 deletions hydroflow_datalog_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition = "2021"
path = "src/lib.rs"

[features]
default = [ "diagnostics" ]
default = []
diagnostics = [ "hydroflow_lang/diagnostics" ]

[dependencies]
Expand All @@ -17,7 +17,7 @@ syn = { version = "1.0.0", features = [ "parsing", "extra-traits" ] }
proc-macro2 = "1.0.27"
proc-macro-crate = "1.1.0"
rust-sitter = "0.2.1"
hydroflow_lang = { path = "../hydroflow_lang", default-features = false }
hydroflow_lang = { path = "../hydroflow_lang" }

[build-dependencies]
rust-sitter-tool = "0.2.1"
Expand Down
5 changes: 5 additions & 0 deletions hydroflow_internalmacro.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
hydroflow_internalmacro.d: hydroflow_internalmacro/src/lib.rs

hydroflow_internalmacro/src/lib.rs:

# env-dep:CARGO_MANIFEST_DIR=/Users/tylerhou/code/hydroflow/hydroflow_internalmacro
2 changes: 1 addition & 1 deletion hydroflow_internalmacro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ proc-macro = true
proc-macro2 = "1.0.0"
proc-macro-crate = "1.1.0"
quote = "1.0.0"
syn = { version = "1.0.0", features = [ "parsing", "extra-traits" ] }
syn = { version = "1.0.0", features = [ "parsing", "extra-traits", "full" ] }
2 changes: 1 addition & 1 deletion hydroflow_lang/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"

[features]
default = [ "diagnostics" ]
default = []
diagnostics = []

[dependencies]
Expand Down
5 changes: 4 additions & 1 deletion hydroflow_macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ edition = "2021"
proc-macro = true

[dependencies]
hydroflow_lang = { path = "../hydroflow_lang" }
# Note: If we ever compile this proc macro crate to WASM (e.g., if we are
# building on a WASM host), we may need to turn diagnostics off for WASM if
# proc_macro2 still does not support WASM.
hydroflow_lang = { path = "../hydroflow_lang", features = [ "diagnostics" ] }
proc-macro2 = "1.0.0"
proc-macro-crate = "1.1.0"
quote = "1.0.0"
Expand Down

0 comments on commit 465bcab

Please sign in to comment.