diff --git a/.gn b/.gn index b90b382106..8bcc1f92ea 100644 --- a/.gn +++ b/.gn @@ -19,6 +19,8 @@ secondary_source = "//v8/" default_args = { clang_use_chrome_plugins = false is_component_build = false + treat_warnings_as_errors = false + linux_use_bundled_binutils = false use_dummy_lastchange = true use_sysroot = false diff --git a/build.rs b/build.rs index 48221b6e54..ab6601143f 100644 --- a/build.rs +++ b/build.rs @@ -91,8 +91,10 @@ fn main() { false }; - // Build from source - if env::var_os("V8_FROM_SOURCE").is_some() { + + // Build from source -- FORCED for dynamic library build + // if env_bool("V8_FROM_SOURCE") { + if true { if is_asan && std::env::var_os("OPT_LEVEL").unwrap_or_default() == "0" { panic!("v8 crate cannot be compiled with OPT_LEVEL=0 and ASAN.\nTry `[profile.dev.package.v8] opt-level = 1`.\nAborting before miscompilations cause issues."); } @@ -157,18 +159,64 @@ fn build_v8(is_asan: bool) { gn_args.push("use_custom_libcxx=false".to_string()); } - // Fix GN's host_cpu detection when using x86_64 bins on Apple Silicon - if cfg!(target_os = "macos") && cfg!(target_arch = "aarch64") { - gn_args.push("host_cpu=\"arm64\"".to_string()) + gn_args.push(r#"extra_cflags = [ "-D_LIBCPP_DISABLE_ASSERTS" ]"#.to_string()); + + gn_args.push(r#"default_symbol_visibility = "hidden""#.to_string()); + let repo_root = env::current_dir().unwrap(); + let abseil_options_path = repo_root + .join("third_party") + .join("abseil-cpp") + .join("absl") + .join("base") + .join("options.h"); + + modify_abseil_options(&abseil_options_path).expect("Failed to modify options.h"); + + if cfg!(target_os = "windows" ) { + patch_inspector_protocol(); + } + + if cfg!(target_os = "macos") { + // Fix GN's host_cpu detection when using x86_64 bins on Apple Silicon + let host_arch = std::env::var("HOST_ARCH").unwrap_or_else(|_| { + // Detect the host architecture + match std::env::consts::ARCH { + "x86_64" => "x64".to_string(), + "aarch64" => "arm64".to_string(), + other => other.to_string(), + } + }); + + if host_arch == "x64" { + patch_v8_files(); + } + + let target_cpu = match target_arch.as_str() { + "x86_64" => "x64", + "aarch64" => "arm64", + _ => panic!("Unsupported architecture"), + }; + + gn_args.push(format!("target_cpu=\"{}\"", target_cpu)); + gn_args.push(format!("host_cpu=\"{}\"", host_arch)); + + if target_arch == "x86_64" { + gn_args.push(r#"extra_cflags += [ "-arch", "x86_64" ]"#.to_string()); + gn_args.push(r#"extra_ldflags = [ "-arch", "x86_64" ]"#.to_string()); + } else if target_arch == "aarch64" { + gn_args.push(r#"extra_cflags += [ "-arch", "arm64" ]"#.to_string()); + gn_args.push(r#"extra_ldflags = [ "-arch", "arm64" ]"#.to_string()); + } } if env::var_os("DISABLE_CLANG").is_some() { gn_args.push("is_clang=false".into()); // -gline-tables-only is Clang-only gn_args.push("line_tables_only=false".into()); - } else if let Some(clang_base_path) = find_compatible_system_clang() { + } else if let Some(clang_base_path) = find_compatible_system_clang(&target_os) { println!("clang_base_path (system): {}", clang_base_path.display()); - gn_args.push(format!("clang_base_path={:?}", clang_base_path)); + let clang_base_path_str = format!("\"{}\"", clang_base_path.display()); + gn_args.push(format!("clang_base_path={}", clang_base_path_str)); gn_args.push("treat_warnings_as_errors=false".to_string()); } else { println!("using Chromium's clang"); @@ -547,7 +595,7 @@ where let mut inflate_state = InflateState::default(); let mut input_buffer = [0; 16 * 1024]; let mut output_buffer = [0; 16 * 1024]; - let mut input_offset = 0; + let mut input_offset = 0; // Skip the gzip header gzip_header::read_gz_header(input).unwrap(); @@ -617,6 +665,26 @@ fn copy_archive(url: &str, filename: &Path) { fn print_link_flags() { println!("cargo:rustc-link-lib=static=rusty_v8"); + + /* + // Platform-specific linker arguments + if cfg!(target_os = "macos") { + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + println!("cargo:rustc-link-search=native=./target/release/gn_out/{}", target_arch); + println!("cargo:rustc-link-lib=dylib=v8_libplatform"); + println!("cargo:rustc-link-lib=dylib=v8_libbase"); + println!("cargo:rustc-link-lib=dylib=v8"); + println!("cargo:rustc-link-lib=dylib=third_party_icu_icui18n"); + println!("cargo:rustc-link-lib=dylib=icuuc"); + println!("cargo:rustc-link-lib=dylib=third_party_abseil-cpp_absl"); + println!("cargo:rustc-link-lib=dylib=c++_chrome"); + } else if cfg!(target_os = "linux") { + //println!("cargo:rustc-link-lib=dylib=c++"); + } else if cfg!(target_os = "windows") { + // Windows uses a different mechanism; rpath is not used + // You might need to copy the DLLs next to the executable + } + */ let should_dyn_link_libcxx = env::var("CARGO_FEATURE_USE_CUSTOM_LIBCXX") .is_err() || env::var("GN_ARGS").map_or(false, |gn_args| { @@ -666,6 +734,7 @@ fn print_link_flags() { } } + // Chromium depot_tools contains helpers // which delegate to the "relevant" `buildtools` // directory when invoked, so they don't count. @@ -688,7 +757,7 @@ fn need_gn_ninja_download() -> bool { // * unversioned (Linux) packages of clang (if recent enough) // but unfortunately it doesn't work with version-suffixed packages commonly // found in Linux packet managers -fn is_compatible_clang_version(clang_path: &Path) -> bool { +fn is_compatible_clang_version(clang_path: &str) -> bool { if let Ok(o) = Command::new(clang_path).arg("--version").output() { let _output = String::from_utf8(o.stdout).unwrap(); // TODO check version output to make sure it's supported. @@ -696,19 +765,67 @@ fn is_compatible_clang_version(clang_path: &Path) -> bool { const _MIN_LLVM_CLANG_VER: f32 = 8.0; return true; } - false + true +} + +fn deactivate_lld() { + // Add use_lld=false to GN_ARGS environment variable + if let Ok(mut gn_args) = env::var("GN_ARGS") { + if !gn_args.contains("use_lld=false") { + if !gn_args.is_empty() { + gn_args.push(' '); + } + gn_args.push_str("use_lld=false"); + env::set_var("GN_ARGS", gn_args); + } + } else { + env::set_var("GN_ARGS", "use_lld=false"); + } } -fn find_compatible_system_clang() -> Option { +fn find_compatible_system_clang(target_os: &str) -> Option { if let Ok(p) = env::var("CLANG_BASE_PATH") { let base_path = Path::new(&p); let clang_path = base_path.join("bin").join("clang"); - if is_compatible_clang_version(&clang_path) { + if is_compatible_clang_version(&clang_path.display().to_string()) { return Some(base_path.to_path_buf()); + } else { + None + } + } else if target_os == "macos" { + let clang_path = Path::new("/usr").join("bin").join("clang"); + if is_compatible_clang_version(&clang_path.display().to_string()) { + deactivate_lld(); + return Some(Path::new("/usr").to_path_buf()); + } else { + None } + } else if target_os == "windows" { + let _llvm_path = Path::new("C:\\") + .join("Program Files (x86)") + .join("Microsoft Visual Studio") + .join("2022") + .join("BuildTools") + .join("VC") + .join("Tools") + .join("Llvm"); + + let llvm_path = Path::new("C:\\").join("LLVM"); + let clang_path = llvm_path.clone() + .join("bin") + .join("clang-cl.exe"); + + let clang_path_str = format!("\"{}\"", clang_path.display()); + + if is_compatible_clang_version(&clang_path_str) { + deactivate_lld(); + return Some(llvm_path); + } else { + None + } + } else { + None } - - None } // Download chromium's clang into OUT_DIR because Cargo will not allow us to @@ -777,12 +894,13 @@ fn maybe_symlink_root_dir(dirs: &mut Dirs) { use std::os::windows::fs::symlink_dir; let get_prefix = |p: &Path| { - p.components() + let prefix = p.components() .find_map(|c| match c { std::path::Component::Prefix(p) => Some(p), _ => None, }) - .map(|p| p.as_os_str().to_owned()) + .map(|p| p.as_os_str().to_string_lossy().to_lowercase()); + prefix }; let Dirs { out, root } = dirs; @@ -820,7 +938,9 @@ pub fn is_debug() -> bool { } fn gn() -> String { - env::var("GN").unwrap_or_else(|_| "gn".to_owned()) + let gn = env::var("GN").unwrap_or_else(|_| "gn".to_owned()); + println!("Using gn: {}", gn.clone()); + gn } /* @@ -828,13 +948,17 @@ fn gn() -> String { * variable or defaulting to `python3`. */ fn python() -> String { - env::var("PYTHON").unwrap_or_else(|_| "python3".to_owned()) + let python = env::var("PYTHON").unwrap_or_else(|_| "python3".to_owned()); + println!("Using python: {}", python); + //env::var("PYTHON").unwrap_or_else(|_| "python".to_owned()) + python } type NinjaEnv = Vec<(String, String)>; fn ninja(gn_out_dir: &Path, maybe_env: Option) -> Command { - let cmd_string = env::var("NINJA").unwrap_or_else(|_| "ninja".to_owned()); + let cmd_string = env::var("NINJA").unwrap_or_else(|_| "C:\\Strawberry\\c\\bin\\ninja.exe".to_owned()); + println!("Using ninja: {}", cmd_string); let mut cmd = Command::new(cmd_string); cmd.arg("-C"); cmd.arg(gn_out_dir); @@ -854,7 +978,8 @@ pub type GnArgs = Vec; pub fn maybe_gen(manifest_dir: &str, gn_args: GnArgs) -> PathBuf { let dirs = get_dirs(Some(manifest_dir)); - let gn_out_dir = dirs.out.join("gn_out"); + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let gn_out_dir = dirs.out.join("gn_out").join(target_arch); if !gn_out_dir.exists() || !gn_out_dir.join("build.ninja").exists() { let args = if let Ok(extra_args) = env::var("EXTRA_GN_ARGS") { @@ -887,8 +1012,14 @@ pub fn maybe_gen(manifest_dir: &str, gn_args: GnArgs) -> PathBuf { } pub fn build(target: &str, maybe_env: Option) { - let gn_out_dir = get_dirs(None).out.join("gn_out"); + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let gn_out_dir = get_dirs(None).out.join("gn_out").join(target_arch); + if !gn_out_dir.exists() { + fs::create_dir_all(&gn_out_dir).expect("Failed to create gn_out_dir"); + } + println!("cargo:rerun-if-env-changed=CARGO_CFG_TARGET_ARCH"); + println!("cargo:rerun-if-env-changed=PROFILE"); rerun_if_changed(&gn_out_dir, maybe_env.clone(), target); // This helps Rust source files locate the snapshot, source map etc. @@ -975,6 +1106,87 @@ pub fn parse_ninja_graph(s: &str) -> HashSet { out } +fn modify_abseil_options(options_path: &PathBuf) -> io::Result<()> { + // Read the contents of options.h + let current_content = fs::read_to_string(&options_path)?; + + // Create the expected content + let new_content = current_content + .lines() + .map(|line| { + if line.contains("#define ABSL_OPTION_USE_INLINE_NAMESPACE") { + "#define ABSL_OPTION_USE_INLINE_NAMESPACE 1".to_string() + } else if line.contains("#define ABSL_OPTION_INLINE_NAMESPACE_NAME") { + "#define ABSL_OPTION_INLINE_NAMESPACE_NAME v8".to_string() + } else { + line.to_string() + } + }) + .collect::>() + .join("\n"); + + // Only write if content actually changed + if current_content != new_content { + let mut file = fs::File::create(&options_path)?; + file.write_all(new_content.as_bytes())?; + } + + Ok(()) +} + + +fn patch_v8_files() { + // List all files that need patching. + let files_to_patch = [ + "v8/src/compiler/turboshaft/wasm-revec-reducer.h", + "v8/src/compiler/turboshaft/wasm-revec-phase.cc", + ]; + + for file in &files_to_patch { + if Path::new(file).exists() { + println!("Patching {}", file); + let status = Command::new("sed") + .args(&[ + "-i.bak", + "s/\\.TryCast