├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── build └── main.rs └── src ├── bin └── cargo-emscripten.rs ├── lib.rs └── std_inc.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [root] 2 | name = "cargo-emscripten" 3 | version = "0.0.1" 4 | dependencies = [ 5 | "cargo 0.1.0 (git+https://github.com/rust-lang/cargo)", 6 | "git2 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 7 | "regex 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 8 | "regex_macros 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 9 | ] 10 | 11 | [[package]] 12 | name = "cargo" 13 | version = "0.1.0" 14 | source = "git+https://github.com/rust-lang/cargo#23ed197405509ae17654a86b6d59a8fb6d367f9e" 15 | dependencies = [ 16 | "curl 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 17 | "docopt 0.6.23 (registry+https://github.com/rust-lang/crates.io-index)", 18 | "flate2 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 19 | "git2 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 20 | "glob 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 21 | "log 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 22 | "registry 0.1.0 (git+https://github.com/rust-lang/cargo)", 23 | "rustc-serialize 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", 24 | "semver 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "tar 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 26 | "term 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 27 | "time 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 28 | "toml 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 29 | "url 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", 30 | ] 31 | 32 | [[package]] 33 | name = "curl" 34 | version = "0.1.7" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | dependencies = [ 37 | "curl-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 38 | "url 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", 39 | ] 40 | 41 | [[package]] 42 | name = "curl-sys" 43 | version = "0.1.3" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | dependencies = [ 46 | "libz-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 47 | "openssl-sys 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", 48 | "pkg-config 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 49 | ] 50 | 51 | [[package]] 52 | name = "docopt" 53 | version = "0.6.23" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | dependencies = [ 56 | "regex 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 57 | "rustc-serialize 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", 58 | ] 59 | 60 | [[package]] 61 | name = "flate2" 62 | version = "0.1.3" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | dependencies = [ 65 | "miniz-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 66 | ] 67 | 68 | [[package]] 69 | name = "gcc" 70 | version = "0.1.3" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | 73 | [[package]] 74 | name = "git2" 75 | version = "0.1.7" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | dependencies = [ 78 | "libgit2-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 79 | "time 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 80 | "url 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", 81 | ] 82 | 83 | [[package]] 84 | name = "glob" 85 | version = "0.1.4" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | 88 | [[package]] 89 | name = "libgit2-sys" 90 | version = "0.1.5" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | dependencies = [ 93 | "libssh2-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 94 | "openssl-sys 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", 95 | "pkg-config 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 96 | ] 97 | 98 | [[package]] 99 | name = "libressl-pnacl-sys" 100 | version = "2.1.3" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | dependencies = [ 103 | "pnacl-build-helper 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 104 | ] 105 | 106 | [[package]] 107 | name = "libssh2-sys" 108 | version = "0.1.1" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | dependencies = [ 111 | "libz-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 112 | "openssl-sys 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", 113 | "pkg-config 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 114 | ] 115 | 116 | [[package]] 117 | name = "libz-sys" 118 | version = "0.1.0" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | dependencies = [ 121 | "pkg-config 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 122 | ] 123 | 124 | [[package]] 125 | name = "log" 126 | version = "0.1.7" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | dependencies = [ 129 | "regex 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 130 | ] 131 | 132 | [[package]] 133 | name = "miniz-sys" 134 | version = "0.1.1" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | dependencies = [ 137 | "gcc 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 138 | ] 139 | 140 | [[package]] 141 | name = "openssl-sys" 142 | version = "0.2.12" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | dependencies = [ 145 | "libressl-pnacl-sys 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 146 | "pkg-config 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 147 | ] 148 | 149 | [[package]] 150 | name = "pkg-config" 151 | version = "0.1.3" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | 154 | [[package]] 155 | name = "pnacl-build-helper" 156 | version = "1.1.0" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | 159 | [[package]] 160 | name = "regex" 161 | version = "0.1.8" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | 164 | [[package]] 165 | name = "regex_macros" 166 | version = "0.1.2" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | dependencies = [ 169 | "regex 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 170 | ] 171 | 172 | [[package]] 173 | name = "registry" 174 | version = "0.1.0" 175 | source = "git+https://github.com/rust-lang/cargo#23ed197405509ae17654a86b6d59a8fb6d367f9e" 176 | dependencies = [ 177 | "curl 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 178 | "rustc-serialize 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", 179 | ] 180 | 181 | [[package]] 182 | name = "rustc-serialize" 183 | version = "0.2.4" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | 186 | [[package]] 187 | name = "semver" 188 | version = "0.1.9" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | 191 | [[package]] 192 | name = "tar" 193 | version = "0.1.5" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | 196 | [[package]] 197 | name = "term" 198 | version = "0.1.2" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | dependencies = [ 201 | "log 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 202 | ] 203 | 204 | [[package]] 205 | name = "time" 206 | version = "0.1.9" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | dependencies = [ 209 | "gcc 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 210 | ] 211 | 212 | [[package]] 213 | name = "toml" 214 | version = "0.1.8" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | dependencies = [ 217 | "rustc-serialize 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", 218 | ] 219 | 220 | [[package]] 221 | name = "url" 222 | version = "0.2.13" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | dependencies = [ 225 | "rustc-serialize 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", 226 | ] 227 | 228 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "cargo-emscripten" 4 | version = "0.0.1" 5 | authors = ["Pierre Krieger "] 6 | build = "build/main.rs" 7 | 8 | [lib] 9 | name = "cargo_emscripten" 10 | path = "src/lib.rs" 11 | 12 | [dependencies] 13 | regex = "*" 14 | regex_macros = "*" 15 | 16 | [build-dependencies] 17 | git2 = "*" 18 | 19 | [dependencies.cargo] 20 | git = "https://github.com/rust-lang/cargo" 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Do not use this**. Emscripten support has been merged in Rust. 2 | -------------------------------------------------------------------------------- /build/main.rs: -------------------------------------------------------------------------------- 1 | extern crate git2; 2 | 3 | use std::io::fs::PathExtensions; 4 | use std::io::process; 5 | 6 | fn main() { 7 | let out_dir = Path::new(std::os::getenv("OUT_DIR").unwrap()); 8 | let rust_dir = out_dir.join("rust"); 9 | 10 | println!("Cloning Rust"); 11 | clone_rust(&rust_dir); 12 | 13 | println!("Compiling libcore"); 14 | if !out_dir.join("core.ll").exists() { 15 | compile(&rust_dir.join("src").join("libcore").join("lib.rs"), &out_dir); 16 | } 17 | 18 | println!("Compiling liblibc"); 19 | if !out_dir.join("libc.ll").exists() { 20 | compile(&rust_dir.join("src").join("liblibc").join("lib.rs"), &out_dir); 21 | } 22 | 23 | println!("Compiling liballoc"); 24 | if !out_dir.join("alloc.ll").exists() { 25 | compile(&rust_dir.join("src").join("liballoc").join("lib.rs"), &out_dir); 26 | } 27 | 28 | println!("Compiling libcollections"); 29 | if !out_dir.join("collections.ll").exists() { 30 | compile(&rust_dir.join("src").join("libcollections").join("lib.rs"), &out_dir); 31 | } 32 | 33 | println!("Compiling libunicode"); 34 | if !out_dir.join("unicode.ll").exists() { 35 | compile(&rust_dir.join("src").join("libunicode").join("lib.rs"), &out_dir); 36 | } 37 | 38 | println!("Compiling librand"); 39 | if !out_dir.join("rand.ll").exists() { 40 | compile(&rust_dir.join("src").join("librand").join("lib.rs"), &out_dir); 41 | } 42 | 43 | println!("Compiling libstd"); 44 | if !out_dir.join("std.ll").exists() { 45 | compile(&rust_dir.join("src").join("libstd").join("lib.rs"), &out_dir); 46 | } 47 | } 48 | 49 | fn clone_rust(path: &Path) -> git2::Repository { 50 | if path.exists() { 51 | match git2::Repository::open(path) { 52 | Ok(r) => { 53 | if !r.is_empty().unwrap() { 54 | return r; 55 | } 56 | }, 57 | _ => () 58 | }; 59 | 60 | std::io::fs::rmdir_recursive(path).unwrap(); 61 | } 62 | 63 | std::io::fs::mkdir(path, std::io::USER_RWX).unwrap(); 64 | git2::Repository::clone("https://github.com/rust-lang/rust#ad9e75938", path).unwrap() 65 | } 66 | 67 | fn compile(krate: &Path, out_dir: &Path) { 68 | let mut command = process::Command::new("rustc"); 69 | command.arg(krate); 70 | command.arg("--out-dir").arg(out_dir); 71 | command.arg("--emit=llvm-ir"); 72 | 73 | exec(command); 74 | } 75 | 76 | fn exec(mut cmd: process::Command) { 77 | cmd.stdout(process::StdioContainer::InheritFd(1)); 78 | cmd.stderr(process::StdioContainer::InheritFd(2)); 79 | 80 | let cmd_str = cmd.to_string(); 81 | 82 | if !cmd.status().unwrap().success() { 83 | panic!("Error while executing `{}`", cmd_str); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/bin/cargo-emscripten.rs: -------------------------------------------------------------------------------- 1 | #![feature(old_orphan_check)] 2 | 3 | extern crate "rustc-serialize" as rustc_serialize; 4 | extern crate cargo; 5 | extern crate cargo_emscripten; 6 | extern crate docopt; 7 | 8 | use std::sync::Arc; 9 | 10 | use cargo::ops::{self, CompileOptions, ExecEngine}; 11 | use cargo::util::important_paths::{find_root_manifest_for_cwd}; 12 | 13 | use docopt::Docopt; 14 | 15 | #[derive(RustcDecodable)] 16 | struct Options { 17 | flag_package: Option, 18 | flag_jobs: Option, 19 | flag_features: Vec, 20 | flag_no_default_features: bool, 21 | flag_target: Option, 22 | flag_manifest_path: Option, 23 | flag_verbose: bool, 24 | flag_release: bool, 25 | flag_lib: bool, 26 | flag_emcc: Option, 27 | } 28 | 29 | pub const USAGE: &'static str = " 30 | Compile a local package and all of its dependencies 31 | 32 | Usage: 33 | cargo-emscripten [options] 34 | 35 | Options: 36 | -h, --help Print this message 37 | -p SPEC, --package SPEC Package to build 38 | -j N, --jobs N The number of jobs to run in parallel 39 | --lib Build only lib (if present in package) 40 | --release Build artifacts in release mode, with optimizations 41 | --features FEATURES Space-separated list of features to also build 42 | --no-default-features Do not build the `default` feature 43 | --target TRIPLE Build for the target triple 44 | --manifest-path PATH Path to the manifest to compile 45 | -v, --verbose Use verbose output 46 | --emcc EMCC Sets the `emcc` executable to use 47 | 48 | If the --package argument is given, then SPEC is a package id specification 49 | which indicates which package should be built. If it is not given, then the 50 | current package is built. For more information on SPEC and its format, see the 51 | `cargo help pkgid` command. 52 | "; 53 | 54 | fn main() { 55 | let options: Options = Docopt::new(USAGE) 56 | .and_then(|d| d.decode()) 57 | .unwrap_or_else(|e| e.exit()); 58 | 59 | let mut shell = cargo::shell(options.flag_verbose); 60 | 61 | let root = find_root_manifest_for_cwd(options.flag_manifest_path).unwrap(); 62 | 63 | let env = if options.flag_release { 64 | "release" 65 | } else { 66 | "compile" 67 | }; 68 | 69 | let engine = cargo_emscripten::EmscriptenEngine { emcc: options.flag_emcc.map(|s| Path::new(s)) }; 70 | 71 | let result = { 72 | let mut opts = CompileOptions { 73 | env: env, 74 | shell: &mut shell, 75 | jobs: options.flag_jobs, 76 | target: options.flag_target.as_ref().map(|t| t.as_slice()), 77 | dev_deps: false, 78 | features: options.flag_features.as_slice(), 79 | no_default_features: options.flag_no_default_features, 80 | spec: options.flag_package.as_ref().map(|s| s.as_slice()), 81 | lib_only: options.flag_lib, 82 | exec_engine: Some(Arc::new(box engine as Box)), 83 | }; 84 | 85 | ops::compile(&root, &mut opts) 86 | }; 87 | 88 | cargo::process_executed(result.map(|_| None::<()>).map_err(|err| { 89 | cargo::util::CliError::from_boxed(err, 101) 90 | }), &mut shell); 91 | } 92 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(phase)] 2 | 3 | #[phase(plugin)] 4 | extern crate regex_macros; 5 | 6 | extern crate cargo; 7 | extern crate regex; 8 | 9 | use cargo::ops::{ExecEngine, CommandPrototype}; 10 | use cargo::util::{mod, CargoResult, ProcessError, ProcessBuilder}; 11 | 12 | use std::io::fs::{File, PathExtensions}; 13 | use std::io::process::ProcessOutput; 14 | 15 | mod std_inc; 16 | 17 | pub struct EmscriptenEngine { 18 | pub emcc: Option, 19 | } 20 | 21 | impl ExecEngine for EmscriptenEngine { 22 | fn exec(&self, command: CommandPrototype) -> Result<(), ProcessError> { 23 | exec(command, false, self).map(|_| ()) 24 | } 25 | 26 | fn exec_with_output(&self, command: CommandPrototype) 27 | -> Result { 28 | exec(command, true, self).map(|a| a.unwrap()) 29 | } 30 | } 31 | 32 | fn exec(command: CommandPrototype, with_output: bool, engine: &EmscriptenEngine) 33 | -> Result, ProcessError> 34 | { 35 | // if we don't find `--crate-type bin`, returning immediatly 36 | if command.get_args().windows(2) 37 | .find(|&args| { 38 | args[0].as_str() == Some("--crate-type") && 39 | args[1].as_str() == Some("bin") 40 | }).is_none() 41 | { 42 | let p = command.into_process_builder().unwrap(); 43 | return do_exec(p, with_output); 44 | } 45 | 46 | // finding crate name 47 | let crate_name = command.get_args().windows(2) 48 | .filter_map(|args| { 49 | if args[0].as_str() == Some("--crate-name") { 50 | Some(args[1].as_str().unwrap().to_string()) 51 | } else { 52 | None 53 | } 54 | }) 55 | .next().unwrap(); 56 | 57 | // finding out dir 58 | let out_dir = command.get_args().windows(2) 59 | .filter_map(|args| { 60 | if args[0].as_str() == Some("--out-dir") { 61 | Some(args[1].as_str().unwrap().to_string()) 62 | } else { 63 | None 64 | } 65 | }) 66 | .next().unwrap(); 67 | 68 | // executing compiler 69 | { 70 | let mut new_command = CommandPrototype::new(command.get_type().clone()).unwrap(); 71 | for arg in command.get_args().iter().filter(|a| !a.as_str().unwrap().starts_with("--emit")) { 72 | new_command = new_command.arg(arg.as_bytes_no_nul()); 73 | } 74 | for (key, val) in command.get_envs().iter() { 75 | new_command = new_command.env(key.as_slice(), val.as_ref().map(|v| v.as_bytes_no_nul())); 76 | } 77 | new_command = new_command.cwd(command.get_cwd().clone()); 78 | 79 | let new_command = new_command.arg("--emit=llvm-ir,dep-info"); 80 | try!(do_exec(new_command.into_process_builder().unwrap(), with_output)); 81 | } 82 | 83 | // this is the output file 84 | let ll_output_file = Path::new(format!("{}/{}.ll", out_dir, crate_name)); 85 | assert!(ll_output_file.exists()); 86 | 87 | // writing libstd in the target directory 88 | let libstd = std_inc::write_std(&Path::new(out_dir.clone())); 89 | 90 | // building the "emcc" comand 91 | let emcc = { 92 | let emcc = engine.emcc.as_ref().map(|p| p.as_str().unwrap()).unwrap_or("emcc"); 93 | 94 | let mut process = util::process(emcc).unwrap(); 95 | process = process.arg(ll_output_file); 96 | 97 | for lib in libstd.into_iter() { 98 | process = process.arg(lib); 99 | } 100 | 101 | process = process.arg("-lGL").arg("-lSDL").arg("-s").arg("USE_SDL=2"); 102 | process = process.arg("-o").arg(format!("{}/{}.html", out_dir, crate_name)); 103 | process 104 | }; 105 | 106 | // executing emcc 107 | do_exec(emcc, with_output) 108 | } 109 | 110 | fn do_exec(process: ProcessBuilder, with_output: bool) -> Result, ProcessError> { 111 | if with_output { 112 | process.exec_with_output().map(|o| Some(o)) 113 | } else { 114 | process.exec().map(|_| None) 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/std_inc.rs: -------------------------------------------------------------------------------- 1 | use std::io::fs::File; 2 | 3 | static LIBCOLLECTIONS: &'static [u8] = include_bytes!(concat!(env!("OUT_DIR"), "/collections.ll")); 4 | static LIBCORE: &'static [u8] = include_bytes!(concat!(env!("OUT_DIR"), "/core.ll")); 5 | static LIBLIBC: &'static [u8] = include_bytes!(concat!(env!("OUT_DIR"), "/libc.ll")); 6 | static LIBRAND: &'static [u8] = include_bytes!(concat!(env!("OUT_DIR"), "/rand.ll")); 7 | static LIBSTD: &'static [u8] = include_bytes!(concat!(env!("OUT_DIR"), "/std.ll")); 8 | static LIBUNICODE: &'static [u8] = include_bytes!(concat!(env!("OUT_DIR"), "/unicode.ll")); 9 | 10 | pub fn write_std(path: &Path) -> Vec { 11 | File::create(&path.join("collections.ll")).write(LIBCOLLECTIONS).unwrap(); 12 | File::create(&path.join("core.ll")).write(LIBCORE).unwrap(); 13 | File::create(&path.join("libc.ll")).write(LIBLIBC).unwrap(); 14 | File::create(&path.join("rand.ll")).write(LIBRAND).unwrap(); 15 | File::create(&path.join("std.ll")).write(LIBSTD).unwrap(); 16 | File::create(&path.join("unicode.ll")).write(LIBUNICODE).unwrap(); 17 | 18 | vec![ 19 | path.join("collections.ll"), 20 | path.join("core.ll"), 21 | path.join("libc.ll"), 22 | path.join("rand.ll"), 23 | path.join("std.ll"), 24 | path.join("unicode.ll"), 25 | ] 26 | } 27 | --------------------------------------------------------------------------------