Meta: Make Rust FFI headers reproducible
Teach import_rust_crate() to track RustFFI.h as a real build output, and teach the relevant Rust build scripts to rerun when their FFI inputs change. Also keep a copy of RustFFI.h in Cargo's own OUT_DIR and restore the configured FFI output from that cached copy after cargo rustc runs. This fixes the case where Ninja knows the header is missing, reruns the custom command, and Cargo exits without rerunning build.rs because the crate itself is already up to date. When Cargo leaves multiple hashed build-script outputs behind, pick the newest root-output before restoring RustFFI.h so we do not copy a stale header after Rust-side API changes. Finally, track the remaining Rust-side inputs that could leave build artifacts stale: LibUnicode and LibJS now rerun build.rs when src/ changes, and the asmintgen rule now depends on Cargo.lock, the BytecodeDef path dependency, and newly added Rust source files.
This commit is contained in:
parent
e47cdc6b63
commit
c167bfd50a
8 changed files with 95 additions and 11 deletions
|
|
@ -295,7 +295,7 @@ endif()
|
|||
target_link_libraries(LibJS PUBLIC JSClangPlugin)
|
||||
|
||||
if (ENABLE_RUST)
|
||||
import_rust_crate(MANIFEST_PATH Rust/Cargo.toml CRATE_NAME libjs_rust)
|
||||
import_rust_crate(MANIFEST_PATH Rust/Cargo.toml CRATE_NAME libjs_rust FFI_HEADER RustFFI.h)
|
||||
target_link_libraries(LibJS PRIVATE libjs_rust)
|
||||
target_compile_definitions(LibJS PRIVATE ENABLE_RUST)
|
||||
|
||||
|
|
@ -352,7 +352,15 @@ if (DEFINED ASMINT_ARCH)
|
|||
COMMENT "Generating asm struct offsets"
|
||||
)
|
||||
|
||||
file(GLOB ASMINTGEN_SOURCES "${ASMINTGEN_DIR}/src/*.rs" "${ASMINTGEN_DIR}/Cargo.toml")
|
||||
file(GLOB ASMINTGEN_RUST_SOURCES CONFIGURE_DEPENDS "${ASMINTGEN_DIR}/src/*.rs")
|
||||
file(GLOB ASMINTGEN_BYTECODE_DEF_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/BytecodeDef/src/*.rs")
|
||||
set(ASMINTGEN_SOURCES
|
||||
"${ASMINTGEN_DIR}/Cargo.toml"
|
||||
"${ASMINTGEN_DIR}/Cargo.lock"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/BytecodeDef/Cargo.toml"
|
||||
${ASMINTGEN_RUST_SOURCES}
|
||||
${ASMINTGEN_BYTECODE_DEF_SOURCES}
|
||||
)
|
||||
# NB: Clear linker-related env vars so cargo uses the default host
|
||||
# linker. The CI may set CC/CXX or CARGO_TARGET_*_LINKER to a
|
||||
# compiler that isn't available in all build configurations (e.g.
|
||||
|
|
|
|||
|
|
@ -671,6 +671,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
println!("cargo:rerun-if-changed={}", def_path.display());
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=cbindgen.toml");
|
||||
println!("cargo:rerun-if-env-changed=FFI_OUTPUT_DIR");
|
||||
println!("cargo:rerun-if-changed=src");
|
||||
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR")?);
|
||||
|
||||
|
|
@ -684,7 +686,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
e => panic!("{e:?}"),
|
||||
},
|
||||
|bindings| {
|
||||
bindings.write_to_file(ffi_out_dir.join("RustFFI.h"));
|
||||
let header_path = out_dir.join("RustFFI.h");
|
||||
bindings.write_to_file(&header_path);
|
||||
|
||||
if ffi_out_dir != out_dir {
|
||||
bindings.write_to_file(ffi_out_dir.join("RustFFI.h"));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@ set(SOURCES
|
|||
ladybird_lib(LibRegex regex EXPLICIT_SYMBOL_EXPORT)
|
||||
target_link_libraries(LibRegex PRIVATE LibUnicode)
|
||||
|
||||
import_rust_crate(MANIFEST_PATH Rust/Cargo.toml CRATE_NAME libregex_rust)
|
||||
import_rust_crate(MANIFEST_PATH Rust/Cargo.toml CRATE_NAME libregex_rust FFI_HEADER RustFFI.h)
|
||||
target_link_libraries(LibRegex PRIVATE libregex_rust)
|
||||
target_compile_definitions(LibRegex PRIVATE ENABLE_RUST)
|
||||
|
|
|
|||
|
|
@ -10,14 +10,16 @@ use std::path::PathBuf;
|
|||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR")?);
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=cbindgen.toml");
|
||||
println!("cargo:rerun-if-env-changed=FFI_OUTPUT_DIR");
|
||||
println!("cargo:rerun-if-changed=src");
|
||||
|
||||
let ffi_out_dir = env::var("FFI_OUTPUT_DIR")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| PathBuf::from(env::var("OUT_DIR").unwrap()));
|
||||
.unwrap_or_else(|_| out_dir.clone());
|
||||
|
||||
cbindgen::generate(manifest_dir).map_or_else(
|
||||
|error| match error {
|
||||
|
|
@ -25,7 +27,12 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
e => panic!("{e:?}"),
|
||||
},
|
||||
|bindings| {
|
||||
bindings.write_to_file(ffi_out_dir.join("RustFFI.h"));
|
||||
let header_path = out_dir.join("RustFFI.h");
|
||||
bindings.write_to_file(&header_path);
|
||||
|
||||
if ffi_out_dir != out_dir {
|
||||
bindings.write_to_file(ffi_out_dir.join("RustFFI.h"));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ ladybird_lib(LibUnicode unicode)
|
|||
find_package(ICU 78.2 EXACT REQUIRED COMPONENTS data i18n uc)
|
||||
target_link_libraries(LibUnicode PRIVATE ICU::i18n ICU::uc ICU::data)
|
||||
|
||||
import_rust_crate(MANIFEST_PATH Rust/Cargo.toml CRATE_NAME libunicode_rust)
|
||||
import_rust_crate(MANIFEST_PATH Rust/Cargo.toml CRATE_NAME libunicode_rust FFI_HEADER RustFFI.h)
|
||||
target_link_libraries(LibUnicode PRIVATE libunicode_rust)
|
||||
|
||||
# FIXME: Add support for building LibGfx in sanitize
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=cbindgen.toml");
|
||||
println!("cargo:rerun-if-env-changed=FFI_OUTPUT_DIR");
|
||||
println!("cargo:rerun-if-changed=src");
|
||||
|
||||
let ffi_out_dir = env::var("FFI_OUTPUT_DIR")
|
||||
.map(PathBuf::from)
|
||||
|
|
@ -25,7 +27,12 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
e => panic!("{e:?}"),
|
||||
},
|
||||
|bindings| {
|
||||
bindings.write_to_file(ffi_out_dir.join("RustFFI.h"));
|
||||
let header_path = out_dir.join("RustFFI.h");
|
||||
bindings.write_to_file(&header_path);
|
||||
|
||||
if ffi_out_dir != out_dir {
|
||||
bindings.write_to_file(ffi_out_dir.join("RustFFI.h"));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,15 @@
|
|||
# https://github.com/corrosion-rs/corrosion/issues/206
|
||||
# https://github.com/corrosion-rs/corrosion/issues/624
|
||||
function(import_rust_crate)
|
||||
cmake_parse_arguments(PARSE_ARGV 0 ARG "" "MANIFEST_PATH;CRATE_NAME;FFI_OUTPUT_DIR" "")
|
||||
cmake_parse_arguments(PARSE_ARGV 0 ARG "" "MANIFEST_PATH;CRATE_NAME;FFI_OUTPUT_DIR;FFI_HEADER" "")
|
||||
|
||||
set(ARG_MANIFEST_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${ARG_MANIFEST_PATH}")
|
||||
if (NOT ARG_FFI_OUTPUT_DIR)
|
||||
set(ARG_FFI_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
if (ARG_FFI_HEADER)
|
||||
set(ffi_output "${ARG_FFI_OUTPUT_DIR}/${ARG_FFI_HEADER}")
|
||||
endif()
|
||||
|
||||
# Find the workspace Cargo.lock to track as a dependency.
|
||||
get_filename_component(workspace_dir "${ARG_MANIFEST_PATH}" DIRECTORY)
|
||||
|
|
@ -77,7 +80,7 @@ function(import_rust_crate)
|
|||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${output_lib}"
|
||||
OUTPUT "${output_lib}" ${ffi_output}
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E env ${cargo_env}
|
||||
"${RUST_CARGO}"
|
||||
|
|
@ -91,6 +94,13 @@ function(import_rust_crate)
|
|||
--
|
||||
-Cdefault-linker-libraries=yes
|
||||
--emit=dep-info
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-DCARGO_BUILD_SCRIPT_DIR=${cargo_output_dir}/build
|
||||
-DCRATE_NAME=${ARG_CRATE_NAME}
|
||||
-DFFI_HEADER=${ARG_FFI_HEADER}
|
||||
-DFFI_OUTPUT_DIR=${ARG_FFI_OUTPUT_DIR}
|
||||
-P "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/sync_rust_ffi_header.cmake"
|
||||
DEPENDS "${ARG_MANIFEST_PATH}"
|
||||
"${workspace_dir}/Cargo.lock" "${workspace_dir}/Cargo.toml"
|
||||
DEPFILE "${depfile}"
|
||||
|
|
@ -99,7 +109,7 @@ function(import_rust_crate)
|
|||
COMMAND_EXPAND_LISTS
|
||||
)
|
||||
|
||||
add_custom_target(${ARG_CRATE_NAME}-build DEPENDS "${output_lib}")
|
||||
add_custom_target(${ARG_CRATE_NAME}-build DEPENDS "${output_lib}" ${ffi_output})
|
||||
|
||||
add_library(${ARG_CRATE_NAME} STATIC IMPORTED GLOBAL)
|
||||
set_target_properties(${ARG_CRATE_NAME} PROPERTIES
|
||||
|
|
|
|||
45
Meta/CMake/sync_rust_ffi_header.cmake
Normal file
45
Meta/CMake/sync_rust_ffi_header.cmake
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#[[
|
||||
* Copyright (c) 2026-present, the Ladybird developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
]]
|
||||
|
||||
if (NOT DEFINED CRATE_NAME OR NOT DEFINED CARGO_BUILD_SCRIPT_DIR OR NOT DEFINED FFI_HEADER OR NOT DEFINED FFI_OUTPUT_DIR)
|
||||
message(FATAL_ERROR "sync_rust_ffi_header.cmake requires CRATE_NAME, CARGO_BUILD_SCRIPT_DIR, FFI_HEADER, and FFI_OUTPUT_DIR")
|
||||
endif()
|
||||
|
||||
if (FFI_HEADER STREQUAL "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
file(GLOB root_output_files "${CARGO_BUILD_SCRIPT_DIR}/${CRATE_NAME}-*/root-output")
|
||||
|
||||
set(latest_source_header "")
|
||||
set(latest_root_output_timestamp "")
|
||||
|
||||
foreach(root_output_file IN LISTS root_output_files)
|
||||
file(READ "${root_output_file}" out_dir)
|
||||
string(STRIP "${out_dir}" out_dir)
|
||||
|
||||
set(source_header "${out_dir}/${FFI_HEADER}")
|
||||
if (NOT EXISTS "${source_header}")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
file(TIMESTAMP "${root_output_file}" root_output_timestamp "%s" UTC)
|
||||
if (latest_source_header STREQUAL "" OR root_output_timestamp GREATER latest_root_output_timestamp)
|
||||
set(latest_source_header "${source_header}")
|
||||
set(latest_root_output_timestamp "${root_output_timestamp}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if (NOT latest_source_header STREQUAL "")
|
||||
file(MAKE_DIRECTORY "${FFI_OUTPUT_DIR}")
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${latest_source_header}" "${FFI_OUTPUT_DIR}/${FFI_HEADER}"
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(FATAL_ERROR "Failed to find ${FFI_HEADER} in Cargo build output for ${CRATE_NAME}")
|
||||
Loading…
Reference in a new issue