Fix issues where cargo wouldn't rerun after static libraries were updated.

This adds `cargo:rerun_if_changed` to the static libraries to ensure
they're up to date. Apparently cargo:rustc-link-lib is insufficient.

Bug: 528225104
Change-Id: I258ce5190c8d181e3bd361a36370f51a6a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/23882
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
diff --git a/src/gn/starlark/crates/build_helper.rs b/src/gn/starlark/crates/build_helper.rs
new file mode 100644
index 0000000..7a943eb
--- /dev/null
+++ b/src/gn/starlark/crates/build_helper.rs
@@ -0,0 +1,29 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+fn require_lib(out_dir: &std::path::Path, name: &str) {
+    println!("cargo:rustc-link-lib=static={}", name);
+    let lib = if cfg!(target_os = "windows") {
+        format!("{}.lib", name)
+    } else {
+        format!("lib{}.a", name)
+    };
+    println!("cargo:rerun-if-changed={}", out_dir.join(lib).display());
+}
+
+fn require_libs(names: &[&str]) {
+    // When running with ninja, it should set NINJA_OUT_DIR.
+    // If running directly with cargo, we know nothing about the output directory,
+    // so we fall back to assuming the default one.
+    let out_dir = if let Ok(out_dir) = std::env::var("NINJA_OUT_DIR") {
+        std::path::PathBuf::from(out_dir)
+    } else {
+        let manifest_dir = std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
+        manifest_dir.join("../../../../../out")
+    };
+    println!("cargo:rustc-link-search=native={}", out_dir.display());
+    for name in names {
+        require_lib(&out_dir, name);
+    }
+}
diff --git a/src/gn/starlark/crates/ffi/build.rs b/src/gn/starlark/crates/ffi/build.rs
index 163b2c0..ae666d1 100644
--- a/src/gn/starlark/crates/ffi/build.rs
+++ b/src/gn/starlark/crates/ffi/build.rs
@@ -2,17 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+include!("../build_helper.rs");
+
 fn main() {
-    // When running with ninja, it should set NINJA_OUT_DIR.
-    // If running directly with cargo, we know nothing about the output directory,
-    // so we fall back to assuming the default one.
-    let out_dir = if let Ok(out_dir) = std::env::var("NINJA_OUT_DIR") {
-        std::path::PathBuf::from(out_dir)
-    } else {
-        let manifest_dir = std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
-        manifest_dir.join("../../../../../out")
-    };
-    println!("cargo:rustc-link-search=native={}", out_dir.display());
-    println!("cargo:rustc-link-lib=static=gn_lib");
-    println!("cargo:rustc-link-lib=static=base");
+    require_libs(&["base", "gn_lib"]);
 }
diff --git a/src/gn/starlark/crates/types/build.rs b/src/gn/starlark/crates/types/build.rs
index 73e52be..747cef8 100644
--- a/src/gn/starlark/crates/types/build.rs
+++ b/src/gn/starlark/crates/types/build.rs
@@ -2,16 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+include!("../build_helper.rs");
+
 fn main() {
-    // When running with ninja, it should set NINJA_OUT_DIR.
-    // If running directly with cargo, we know nothing about the output directory,
-    // so we fall back to assuming the default one.
-    let out_dir = if let Ok(out_dir) = std::env::var("NINJA_OUT_DIR") {
-        std::path::PathBuf::from(out_dir)
-    } else {
-        let manifest_dir = std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
-        manifest_dir.join("../../../../../out")
-    };
-    println!("cargo:rustc-link-search=native={}", out_dir.display());
-    println!("cargo:rustc-link-lib=static=string_atom");
+    require_libs(&["string_atom"]);
 }