Add a simple CxxTarget type. This allows access to GN's target object from a rust target. Bug: 528225104 Change-Id: I88fca33a79ef82a40a5602b3ee6b6c4b6a6a6964 Reviewed-on: https://gn-review.googlesource.com/c/gn/+/25561 Reviewed-by: Takuto Ikuta <tikuta@google.com> Commit-Queue: Matt Stark <msta@google.com>
diff --git a/src/gn/ffi/bridge.cc b/src/gn/ffi/bridge.cc index 2bef7a7..723f70d 100644 --- a/src/gn/ffi/bridge.cc +++ b/src/gn/ffi/bridge.cc
@@ -3,6 +3,7 @@ #include "gn/err.h" #include "gn/ffi/err.h" #include "gn/ffi/scope.h" +#include "gn/ffi/target.h" #include "gn/ffi/test_with_scope.h" #include "gn/ffi/value.h" #include "gn/label.h" @@ -10,6 +11,7 @@ #include "gn/scope.h" #include "gn/settings.h" #include "gn/source_dir.h" +#include "gn/target.h" #include "gn/test_with_scope.h" #include "gn/value.h" #include <array> @@ -811,6 +813,7 @@ using OutputFile = ::OutputFile; using SourceDir = ::SourceDir; using Label = ::Label; +using Target = ::Target; using Settings = ::Settings; using Scope = ::Scope; using TestWithScope = ::TestWithScope; @@ -966,6 +969,21 @@ new (return$) ::rust::Str(::rust::cxx_to_rust((self.*name$)())); } +void cxxbridge1$196$Target$label(::Target const &self, ::Label const **return$) noexcept { + ::Label const &(::Target::*label$)() const = &::Target::label; + new (return$) ::Label const *(&(self.*label$)()); +} + +::Settings const *cxxbridge1$196$Target$settings_cxx(::Target const &self) noexcept { + ::Settings const *(::Target::*settings_cxx$)() const = &::Target::settings; + return (self.*settings_cxx$)(); +} + +void cxxbridge1$196$register_dependency(::Target &target, ::rust::Str package, ::rust::Str name, ::rust::Str toolchain_package, ::rust::Str toolchain_name) noexcept { + void (*register_dependency$)(::Target &, ::rust::Str, ::rust::Str, ::rust::Str, ::rust::Str) = ::register_dependency; + register_dependency$(target, package, name, toolchain_package, toolchain_name); +} + void cxxbridge1$196$Settings$toolchain_label(::Settings const &self, ::Label const **return$) noexcept { ::Label const &(::Settings::*toolchain_label$)() const = &::Settings::toolchain_label; new (return$) ::Label const *(&(self.*toolchain_label$)());
diff --git a/src/gn/ffi/bridge.h b/src/gn/ffi/bridge.h index dbd322d..f8b8a1d 100644 --- a/src/gn/ffi/bridge.h +++ b/src/gn/ffi/bridge.h
@@ -4,6 +4,7 @@ #include "gn/err.h" #include "gn/ffi/err.h" #include "gn/ffi/scope.h" +#include "gn/ffi/target.h" #include "gn/ffi/test_with_scope.h" #include "gn/ffi/value.h" #include "gn/label.h" @@ -11,6 +12,7 @@ #include "gn/scope.h" #include "gn/settings.h" #include "gn/source_dir.h" +#include "gn/target.h" #include "gn/test_with_scope.h" #include "gn/value.h" #include <array> @@ -749,6 +751,7 @@ using OutputFile = ::OutputFile; using SourceDir = ::SourceDir; using Label = ::Label; +using Target = ::Target; using Settings = ::Settings; using Scope = ::Scope; using TestWithScope = ::TestWithScope;
diff --git a/src/gn/starlark/crates/ffi/src/bridge.rs b/src/gn/starlark/crates/ffi/src/bridge.rs index 1c8bf00..23ed719 100644 --- a/src/gn/starlark/crates/ffi/src/bridge.rs +++ b/src/gn/starlark/crates/ffi/src/bridge.rs
@@ -129,6 +129,7 @@ include!("gn/err.h"); include!("gn/ffi/err.h"); include!("gn/ffi/scope.h"); + include!("gn/ffi/target.h"); include!("gn/ffi/test_with_scope.h"); include!("gn/ffi/value.h"); include!("gn/label.h"); @@ -136,6 +137,7 @@ include!("gn/scope.h"); include!("gn/settings.h"); include!("gn/source_dir.h"); + include!("gn/target.h"); include!("gn/test_with_scope.h"); include!("gn/value.h"); @@ -187,6 +189,19 @@ #[cxx_return_type = "const std::string&"] pub fn name(self: &Label) -> &str; + #[rust_name = "CxxTarget"] + type Target; + pub(in crate::target) fn label(self: &CxxTarget) -> &Label; + #[rust_name = "settings_cxx"] + pub(in crate::target) fn settings(self: &CxxTarget) -> *const Settings; + pub(in crate::target) fn register_dependency( + target: Pin<&mut CxxTarget>, + package: &str, + name: &str, + toolchain_package: &str, + toolchain_name: &str, + ); + type Settings; pub(in crate::settings) fn toolchain_label(self: &Settings) -> &Label;
diff --git a/src/gn/starlark/crates/ffi/src/eval_context.rs b/src/gn/starlark/crates/ffi/src/eval_context.rs index 19d8b3b..3e88e00 100644 --- a/src/gn/starlark/crates/ffi/src/eval_context.rs +++ b/src/gn/starlark/crates/ffi/src/eval_context.rs
@@ -81,9 +81,7 @@ .ok_or_else(|| Error::RequiresBzlFile.into()) } - fn require_rule_impl( - &self, - ) -> starlark::Result<&mut types::CtxState<crate::target_ref::TargetRef>> { + fn require_rule_impl(&self) -> starlark::Result<&mut types::CtxState<crate::TargetRef>> { todo!() } }
diff --git a/src/gn/starlark/crates/ffi/src/lib.rs b/src/gn/starlark/crates/ffi/src/lib.rs index 2d39a16..6a2ffa8 100644 --- a/src/gn/starlark/crates/ffi/src/lib.rs +++ b/src/gn/starlark/crates/ffi/src/lib.rs
@@ -28,16 +28,19 @@ mod session; mod settings; mod slice; +mod target; mod target_ref; mod test_with_scope; mod value; pub use bridge::{ - Err, KeyValue, Label, OutputFile, OwnedFrozenValue, Scope, Settings, SourceDir, Value, - ValueType, + CxxTarget, Err, KeyValue, Label, OutputFile, OwnedFrozenValue, Scope, Settings, SourceDir, + Value, ValueType, }; pub use mutability::Immutable; pub use opaque::{NonOpaque, OpaqueSized}; pub use session::Session; pub use slice::{OwnedSlice, Slice}; +pub use target::Target; +pub use target_ref::TargetRef; pub use test_with_scope::TestWithScope;
diff --git a/src/gn/starlark/crates/ffi/src/target.rs b/src/gn/starlark/crates/ffi/src/target.rs new file mode 100644 index 0000000..c0b2a00 --- /dev/null +++ b/src/gn/starlark/crates/ffi/src/target.rs
@@ -0,0 +1,67 @@ +// 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. + +use std::ptr::NonNull; + +#[derive(Copy, Clone)] +pub struct Target { + // We maintain a 0-1 relationship between starlark Targets and rust targets. + // starlark targets store a reference to C++ targets, and C++ targets store an optional + // reference to starlark targets. + cxx: NonNull<crate::bridge::CxxTarget>, + // Note: This is not a lightweight reference type. + // Fields such as rules, attr, and providers will be added in the future. +} + +impl std::ops::Deref for Target { + type Target = crate::bridge::CxxTarget; + + fn deref(&self) -> &Self::Target { + // Safety: The C++ Target pointer is guaranteed to be valid and live for the + // duration of the build evaluation. + unsafe { self.cxx.as_ref() } + } +} + +impl allocative::Allocative for Target { + fn visit<'a, 'b: 'a>(&self, visitor: &'a mut allocative::Visitor<'b>) { + let visitor = visitor.enter_self_sized::<Self>(); + visitor.exit(); + } +} + +// Safety: Target pointers in GN are heap-allocated and thread-safe to transfer +// across evaluation boundaries. +unsafe impl Send for Target {} +// Safety: Target pointers in GN are thread-safe to reference across evaluation +// boundaries. +unsafe impl Sync for Target {} + +impl crate::bridge::CxxTarget { + /// Returns the settings for the target. + pub fn settings(&self) -> &crate::Settings { + // Safety: Settings pointer is always valid and non-null on constructed Targets. + unsafe { self.settings_cxx().as_ref() }.unwrap() + } + + /// Returns the toolchain label for the target. + pub fn toolchain(&self) -> types::LabelRef<'_> { + self.settings().toolchain_label().as_ref() + } + + /// Registers a dependency on this target. + pub fn register_dependency( + self: std::pin::Pin<&mut Self>, + label: types::LabelRef<'_>, + toolchain: types::LabelRef<'_>, + ) { + crate::bridge::register_dependency( + self, + label.package().as_str(), + label.name(), + toolchain.package().as_str(), + toolchain.name(), + ); + } +}
diff --git a/src/gn/starlark/crates/ffi/src/target_ref.rs b/src/gn/starlark/crates/ffi/src/target_ref.rs index 238a59f..9bc9c7e 100644 --- a/src/gn/starlark/crates/ffi/src/target_ref.rs +++ b/src/gn/starlark/crates/ffi/src/target_ref.rs
@@ -3,16 +3,40 @@ // found in the LICENSE file. use allocative::Allocative; -use starlark::values::{AllocValue, Heap, ProvidesStaticType, StarlarkValue, Value}; +use starlark::values::{ + AllocValue, Heap, ProvidesStaticType, StarlarkValue, Value, ValueLike as _, +}; use starlark_derive::{starlark_value, NoSerialize}; -use types::LabelRef; +use types::{LabelRef, TargetRef as _}; -#[derive(Clone, Allocative, ProvidesStaticType, Debug, NoSerialize, PartialEq, Eq, Hash)] -pub struct TargetRef; +use crate::target::Target; + +#[derive(Clone, Copy, Allocative, ProvidesStaticType, NoSerialize)] +pub struct TargetRef(pub(crate) &'static Target); + +impl PartialEq for TargetRef { + fn eq(&self, other: &Self) -> bool { + std::ptr::eq(self.0, other.0) + } +} +impl Eq for TargetRef {} + +impl std::hash::Hash for TargetRef { + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + std::ptr::hash(self.0, state); + } +} + +impl std::fmt::Debug for TargetRef { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Delegate to Display + write!(f, "{self}") + } +} impl std::fmt::Display for TargetRef { - fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.label()) } } @@ -20,15 +44,19 @@ #[starlark_value(type = "Target")] impl<'v> StarlarkValue<'v> for TargetRef { - fn equals(&self, _other: Value<'v>) -> starlark::Result<bool> { - todo!() + fn equals(&self, other: Value<'v>) -> starlark::Result<bool> { + Ok(other + .downcast_ref::<Self>() + .is_some_and(|other| other == self)) } fn write_hash( &self, - _hasher: &mut starlark::collections::StarlarkHasher, + hasher: &mut starlark::collections::StarlarkHasher, ) -> starlark::Result<()> { - todo!() + use std::hash::Hash as _; + self.hash(hasher); + Ok(()) } } @@ -42,11 +70,11 @@ type Rule = rule::FrozenRule<crate::eval_context::EvalContext>; fn label(&self) -> LabelRef<'_> { - todo!() + self.0.label().as_ref() } fn toolchain(&self) -> LabelRef<'_> { - todo!() + self.0.toolchain() } fn rule(&self) -> Option<&'static Self::Rule> {