Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
356ae9c
Change build scripts to build V8 to a dynamic library and link rusty_…
lucksus Sep 16, 2024
683815c
Force V8_FROM_SOURCE (cherrypicked from 79d4c81fb174968735b7759c1eb64…
lucksus Sep 16, 2024
9e5b8e3
v8_monolithic = true
lucksus Sep 19, 2024
793011f
Change build settings trying to get cppgc and other unresolved symbol…
lucksus Sep 19, 2024
1a380fc
use_custom_libcxx = true
lucksus Sep 20, 2024
24dce9f
Remove cppgc linking and set LIBCPP_ABI_VERSION to 1
lucksus Sep 20, 2024
7eb8ec1
Fix setting of LIBCPP_ABI_VERSION
lucksus Sep 23, 2024
c36471f
Instead of downgrading LIBCPP_ABI, use system clang on macos
lucksus Sep 23, 2024
10f02b6
Fix compilation of build.rs after last commit
lucksus Sep 23, 2024
d1717ef
Detect and use system clang on Windows too
lucksus Sep 30, 2024
81aa290
Detect and use system clang on Windows too
jhweir Sep 30, 2024
06e646b
Merge branch 'v0.92-dll' of github.com:coasys/rusty_v8 into v0.92-dll
lucksus Oct 1, 2024
b99a608
Try fix handling of clang_path in build.rs to avoid problem with spac…
lucksus Oct 1, 2024
ca086ff
Refactor build.rs to improve dynamic library linking
fayeed Oct 14, 2024
a9be97c
Refactor build.rs to improve dynamic library linking
fayeed Oct 17, 2024
55ad446
Refactor build.rs to improve dynamic library linking
fayeed Oct 17, 2024
b6b0839
Refactor build.rs to improve dynamic library linking and fix handling…
fayeed Oct 18, 2024
9fed747
Fix macOS build (' => ") and write build artifacts to gn_out/TARGET_ARCH
lucksus Oct 28, 2024
3d3fe74
Don't always turn debug symbols off, so debug builds of consuming cra…
lucksus Oct 28, 2024
33ade85
Change linker search path to include architecture directory
lucksus Oct 28, 2024
28280bf
don't treat warnings as errors
lucksus Oct 28, 2024
066d271
Revert "Refactor build.rs to improve dynamic library linking and fix …
lucksus Oct 29, 2024
20befe0
On Linux, go back to static lib but with special abseil::v8 namespace
lucksus Oct 31, 2024
00e051d
Modify abseil namespace and build static for linux and windows
lucksus Nov 4, 2024
e929104
Fix Windows clang path
lucksus Nov 4, 2024
1dfa63b
Don't have symbol_visibility = "hidden" on macOS where we still build…
lucksus Nov 6, 2024
ae67c90
Switch macOS back to static build with abseil namespace too
lucksus Nov 6, 2024
ff3f64e
Rebuild if target arch has changed
lucksus Nov 7, 2024
60b32be
Explicitly pass arch through to clang on macOS
lucksus Nov 7, 2024
e3849ca
Rebuild if PROFILE (debug/release) changed
lucksus Nov 7, 2024
203fe5d
Fix reassignment of extra_cflags
lucksus Nov 7, 2024
30a2496
Don't rerun build if PROFILE changes (seems to trigger rebuild every …
lucksus Nov 11, 2024
1f2f017
Don't touch abseil code files if they were changed before to prevent …
lucksus Nov 21, 2024
bd08cbd
Remove visibility=hidden flags again, namespacing abseil is the actua…
lucksus Nov 22, 2024
22f07e6
Rerun if PROFILE (debug/release) has changed
lucksus Nov 22, 2024
8525cee
Fix extra_cflags syntax
lucksus Nov 22, 2024
cc7271b
Set symbol_level to 2 for debug, 1 for release builds
lucksus Nov 22, 2024
50b4f61
cflag: -D_LIBCPP_DISABLE_ASSERTS
lucksus Nov 22, 2024
7efd271
is_component_build=false in .gn to always build a static lib
lucksus Nov 22, 2024
4a13d40
Keep symbol level to 1 to prevent B/BL out of range errors
lucksus Nov 22, 2024
2aa8167
Patch v8 sources to avoid non standard use of C++ template, preventin…
lucksus Feb 24, 2025
b8c21aa
Fix maybe_symlink_root_dir to treat C:\ and c:\ as same drive
lucksus Mar 3, 2025
d78e718
Add patch to build.rs, fixing inspector_protocol.gni to turn /C:/ int…
lucksus Mar 3, 2025
06b344d
Fix match line in last commit
lucksus Mar 3, 2025
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
2 changes: 2 additions & 0 deletions .gn
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
254 changes: 233 additions & 21 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
}
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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| {
Expand Down Expand Up @@ -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.
Expand All @@ -688,27 +757,75 @@ 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.
const _MIN_APPLE_CLANG_VER: f32 = 11.0;
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<PathBuf> {
fn find_compatible_system_clang(target_os: &str) -> Option<PathBuf> {
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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -820,21 +938,27 @@ 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
}

/*
* Get the system's python binary - specified via the PYTHON environment
* 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<NinjaEnv>) -> 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);
Expand All @@ -854,7 +978,8 @@ pub type GnArgs = Vec<String>;

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") {
Expand Down Expand Up @@ -887,8 +1012,14 @@ pub fn maybe_gen(manifest_dir: &str, gn_args: GnArgs) -> PathBuf {
}

pub fn build(target: &str, maybe_env: Option<NinjaEnv>) {
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.
Expand Down Expand Up @@ -975,6 +1106,87 @@ pub fn parse_ninja_graph(s: &str) -> HashSet<String> {
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::<Vec<String>>()
.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</.template TryCast</g",
file,
])
.status()
.expect("Failed to run sed for patching V8 source");
if !status.success() {
panic!("sed patch failed for {}", file);
}
} else {
println!("File {} not found; skipping patch", file);
}
}
}

fn patch_inspector_protocol() {
let v8_root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("v8");
let gni_path = v8_root.join("third_party/inspector_protocol/inspector_protocol.gni");

// Read the original content
let mut content = fs::read_to_string(&gni_path)
.expect("Failed to read inspector_protocol.gni");

// Patch the outputs_pre line
let old_line = "outputs = get_path_info(rebase_path(invoker.outputs, \".\", invoker.out_dir),\n \"abspath\")";
let new_lines = r#"outputs_pre = get_path_info(rebase_path(invoker.outputs, ".", invoker.out_dir), "abspath")
outputs = []
foreach(out, outputs_pre) {
outputs += [ string_replace(out, "/C:/", "C:/") ]
}"#;
if content.contains(old_line) {
content = content.replace(old_line, new_lines);
fs::write(&gni_path, content)
.expect("Failed to write patched inspector_protocol.gni");
println!("Patched inspector_protocol.gni to fix /C:/ paths");
} else {
println!("Warning: Could not find outputs_pre line to patch in inspector_protocol.gni");
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down