From 6744bb8d750b9ab11d2ec9448334732b98feb58a Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Sat, 30 Mar 2019 19:27:00 -0400 Subject: Call ninja directly from build.rs (#2020) --- cli/build.rs | 2 +- core/build.rs | 2 +- gn.rs | 110 ---------------------------------------- tools/format.py | 2 +- tools/gn.rs | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++ tools/hyper_hello.rs | 20 ++++---- 6 files changed, 150 insertions(+), 124 deletions(-) delete mode 100644 gn.rs create mode 100644 tools/gn.rs diff --git a/cli/build.rs b/cli/build.rs index 4d50d8a5f..8e05b2119 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -1,7 +1,7 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. // Run "cargo build -vv" if you want to see gn output. mod gn { - include!("../gn.rs"); + include!("../tools/gn.rs"); } fn main() { diff --git a/core/build.rs b/core/build.rs index 0cb775e5c..8b827d9e7 100644 --- a/core/build.rs +++ b/core/build.rs @@ -1,7 +1,7 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. // Run "cargo build -vv" if you want to see gn output. mod gn { - include!("../gn.rs"); + include!("../tools/gn.rs"); } fn main() { diff --git a/gn.rs b/gn.rs deleted file mode 100644 index 5d27b8bb0..000000000 --- a/gn.rs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -// This is used in cli/build.rs and core/build.rs to interface with the GN build -// system (which defines the deno build). - -use std::env; -use std::path::{self, Path, PathBuf}; -use std::process::Command; - -pub struct Build { - gn_mode: String, - pub gn_out_dir: String, - pub gn_out_path: PathBuf, - pub check_only: bool, -} - -impl Build { - pub fn setup() -> Build { - let gn_mode = if cfg!(target_os = "windows") { - // On Windows, we need to link with a release build of libdeno, because - // rust always uses the release CRT. - // TODO(piscisaureus): make linking with debug libdeno possible. - String::from("release") - } else { - // Cargo sets PROFILE to either "debug" or "release", which conveniently - // matches the build modes we support. - env::var("PROFILE").unwrap() - }; - - // cd into workspace root. - assert!(env::set_current_dir("..").is_ok()); - - let cwd = env::current_dir().unwrap(); - // If not using host default target the output folder will change - // target/release will become target/$TARGET/release - // Gn should also be using this output directory as well - // most things will work with gn using the default - // output directory but some tests depend on artifacts - // being in a specific directory relative to the main build output - let gn_out_path = cwd.join(format!("target/{}", gn_mode.clone())); - let gn_out_dir = normalize_path(&gn_out_path); - - // Tell Cargo when to re-run this file. We do this first, so these directives - // can take effect even if something goes wrong later in the build process. - println!("cargo:rerun-if-env-changed=DENO_BUILD_PATH"); - // TODO: this is obviously not appropriate here. - println!("cargo:rerun-if-env-changed=APPVEYOR_REPO_COMMIT"); - - // This helps Rust source files locate the snapshot, source map etc. - println!("cargo:rustc-env=GN_OUT_DIR={}", gn_out_dir); - - // Detect if we're being invoked by the rust language server (RLS). - // Unfortunately we can't detect whether we're being run by `cargo check`. - let check_only = env::var_os("CARGO") - .map(PathBuf::from) - .as_ref() - .and_then(|p| p.file_stem()) - .and_then(|f| f.to_str()) - .map(|s| s.starts_with("rls")) - .unwrap_or(false); - - if check_only { - // Enable the 'check_only' feature, which enables some workarounds in the - // rust source code to compile successfully without a bundle and snapshot - println!("cargo:rustc-cfg=feature=\"check-only\""); - } - - Build { - gn_out_dir, - gn_out_path, - check_only, - gn_mode, - } - } - - pub fn run(&self, gn_target: &str) { - if !self.gn_out_path.join("build.ninja").exists() { - let status = Command::new("python") - .env("DENO_BUILD_PATH", &self.gn_out_dir) - .env("DENO_BUILD_MODE", &self.gn_mode) - .arg("./tools/setup.py") - .status() - .expect("setup.py failed"); - assert!(status.success()); - } - - // TODO(ry) call ninja directly here, not python. - let status = Command::new("python") - .env("DENO_BUILD_PATH", &self.gn_out_dir) - .env("DENO_BUILD_MODE", &self.gn_mode) - .arg("./tools/build.py") - .arg(gn_target) - .arg("-v") - .status() - .expect("build.py failed"); - assert!(status.success()); - } -} - -// Utility function to make a path absolute, normalizing it to use forward -// slashes only. The returned value is an owned String, otherwise panics. -fn normalize_path>(path: T) -> String { - path - .as_ref() - .to_str() - .unwrap() - .to_owned() - .chars() - .map(|c| if path::is_separator(c) { '/' } else { c }) - .collect() -} diff --git a/tools/format.py b/tools/format.py index b0d3bc5e4..8dec2117c 100755 --- a/tools/format.py +++ b/tools/format.py @@ -46,4 +46,4 @@ qrun([ "third_party/rustfmt/" + platform() + "/rustfmt", "--config-path", rustfmt_config, -] + find_exts(["cli", "core"], [".rs"])) +] + find_exts(["cli", "core", "tools"], [".rs"])) diff --git a/tools/gn.rs b/tools/gn.rs new file mode 100644 index 000000000..d43399fe9 --- /dev/null +++ b/tools/gn.rs @@ -0,0 +1,138 @@ +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. +// This is used in cli/build.rs and core/build.rs to interface with the GN build +// system (which defines the deno build). + +use std::env; +use std::path::{self, Path, PathBuf}; +use std::process::Command; + +pub struct Build { + gn_mode: String, + root: PathBuf, + pub gn_out_dir: String, + pub gn_out_path: PathBuf, + pub check_only: bool, +} + +impl Build { + pub fn setup() -> Build { + let gn_mode = if cfg!(target_os = "windows") { + // On Windows, we need to link with a release build of libdeno, because + // rust always uses the release CRT. + // TODO(piscisaureus): make linking with debug libdeno possible. + String::from("release") + } else { + // Cargo sets PROFILE to either "debug" or "release", which conveniently + // matches the build modes we support. + env::var("PROFILE").unwrap() + }; + + // cd into workspace root. + assert!(env::set_current_dir("..").is_ok()); + + let root = env::current_dir().unwrap(); + // If not using host default target the output folder will change + // target/release will become target/$TARGET/release + // Gn should also be using this output directory as well + // most things will work with gn using the default + // output directory but some tests depend on artifacts + // being in a specific directory relative to the main build output + let gn_out_path = root.join(format!("target/{}", gn_mode.clone())); + let gn_out_dir = normalize_path(&gn_out_path); + + // Tell Cargo when to re-run this file. We do this first, so these directives + // can take effect even if something goes wrong later in the build process. + println!("cargo:rerun-if-env-changed=DENO_BUILD_PATH"); + // TODO: this is obviously not appropriate here. + println!("cargo:rerun-if-env-changed=APPVEYOR_REPO_COMMIT"); + + // This helps Rust source files locate the snapshot, source map etc. + println!("cargo:rustc-env=GN_OUT_DIR={}", gn_out_dir); + + // Detect if we're being invoked by the rust language server (RLS). + // Unfortunately we can't detect whether we're being run by `cargo check`. + let check_only = env::var_os("CARGO") + .map(PathBuf::from) + .as_ref() + .and_then(|p| p.file_stem()) + .and_then(|f| f.to_str()) + .map(|s| s.starts_with("rls")) + .unwrap_or(false); + + if check_only { + // Enable the 'check_only' feature, which enables some workarounds in the + // rust source code to compile successfully without a bundle and snapshot + println!("cargo:rustc-cfg=feature=\"check-only\""); + } + + Build { + gn_out_dir, + gn_out_path, + check_only, + gn_mode, + root, + } + } + + pub fn run(&self, gn_target: &str) { + if !self.gn_out_path.join("build.ninja").exists() { + let status = Command::new("python") + .env("DENO_BUILD_PATH", &self.gn_out_dir) + .env("DENO_BUILD_MODE", &self.gn_mode) + .env("DEPOT_TOOLS_WIN_TOOLCHAIN", "0") + .arg("./tools/setup.py") + .status() + .expect("setup.py failed"); + assert!(status.success()); + } + + let mut ninja = Command::new("third_party/depot_tools/ninja"); + let ninja = if !cfg!(target_os = "windows") { + &mut ninja + } else { + // Windows needs special configuration. This is similar to the function of + // python_env() in //tools/util.py. + let python_path: Vec = vec![ + "third_party/python_packages", + "third_party/python_packages/win32", + "third_party/python_packages/win32/lib", + "third_party/python_packages/Pythonwin", + ].into_iter() + .map(|p| self.root.join(p).into_os_string().into_string().unwrap()) + .collect(); + let orig_path = String::from(";") + + &env::var_os("PATH").unwrap().into_string().unwrap(); + let path = self + .root + .join("third_party/python_packages/pywin32_system32") + .into_os_string() + .into_string() + .unwrap(); + ninja + .env("PYTHONPATH", python_path.join(";")) + .env("PATH", path + &orig_path) + .env("DEPOT_TOOLS_WIN_TOOLCHAIN", "0") + }; + + let status = ninja + .arg(gn_target) + .arg("-C") + .arg(&self.gn_out_dir) + .status() + .expect("ninja failed"); + assert!(status.success()); + } +} + +// Utility function to make a path absolute, normalizing it to use forward +// slashes only. The returned value is an owned String, otherwise panics. +fn normalize_path>(path: T) -> String { + path + .as_ref() + .to_str() + .unwrap() + .to_owned() + .chars() + .map(|c| if path::is_separator(c) { '/' } else { c }) + .collect() +} diff --git a/tools/hyper_hello.rs b/tools/hyper_hello.rs index d46ba3e14..7a24ea735 100644 --- a/tools/hyper_hello.rs +++ b/tools/hyper_hello.rs @@ -4,10 +4,10 @@ #![deny(warnings)] extern crate hyper; -use std::env; -use hyper::{Body, Response, Server}; -use hyper::service::service_fn_ok; use hyper::rt::{self, Future}; +use hyper::service::service_fn_ok; +use hyper::{Body, Response, Server}; +use std::env; static PHRASE: &'static [u8] = b"Hello World!"; @@ -22,17 +22,15 @@ fn main() { // new_service is run for each connection, creating a 'service' // to handle requests for that specific connection. let new_service = || { - // This is the `Service` that will handle the connection. - // `service_fn_ok` is a helper to convert a function that - // returns a Response into a `Service`. - service_fn_ok(|_| { - Response::new(Body::from(PHRASE)) - }) + // This is the `Service` that will handle the connection. + // `service_fn_ok` is a helper to convert a function that + // returns a Response into a `Service`. + service_fn_ok(|_| Response::new(Body::from(PHRASE))) }; let server = Server::bind(&addr) - .serve(new_service) - .map_err(|e| eprintln!("server error: {}", e)); + .serve(new_service) + .map_err(|e| eprintln!("server error: {}", e)); println!("Listening on http://{}", addr); -- cgit v1.2.3