Add a function rust can use to create targets

Bug: 528225104
Change-Id: Ie2ea8aeb37e12c35784a85867ff88ecc6a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/25520
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
diff --git a/src/gn/ffi/target.cc b/src/gn/ffi/target.cc
index e55f765..2bd3819 100644
--- a/src/gn/ffi/target.cc
+++ b/src/gn/ffi/target.cc
@@ -10,6 +10,16 @@
 #include "gn/label_ptr.h"
 #include "gn/source_dir.h"
 #include "gn/target.h"
+#include "gn/target_generator.h"
+
+Target* create_target(Scope& scope,
+                      rust::Str name,
+                      rust::Str output_type,
+                      Err& err) {
+  return TargetGenerator::GenerateTarget(&scope, nullptr,
+                                         std::string_view(name),
+                                         std::string_view(output_type), &err);
+}
 
 void register_dependency(Target& target,
                          rust::Str package,
diff --git a/src/gn/ffi/target.h b/src/gn/ffi/target.h
index c55ac81..74cfa60 100644
--- a/src/gn/ffi/target.h
+++ b/src/gn/ffi/target.h
@@ -7,8 +7,16 @@
 
 #include "cxx.h"
 
+class Err;
+class Scope;
 class Target;
 
+// Creates and generates a new target in the given scope.
+Target* create_target(Scope& scope,
+                      rust::Str name,
+                      rust::Str output_type,
+                      Err& err);
+
 // Enforces that `target` cannot be resolved until the target for the label has
 // been resolved.
 void register_dependency(Target& target,
diff --git a/src/gn/starlark/crates/types/src/output_type.rs b/src/gn/starlark/crates/types/src/output_type.rs
index abb5f20..efaa6ae 100644
--- a/src/gn/starlark/crates/types/src/output_type.rs
+++ b/src/gn/starlark/crates/types/src/output_type.rs
@@ -25,6 +25,7 @@
     GeneratedFile,
     RustLibrary,
     RustProcMacro,
+    Noop,
 }
 
 impl OutputType {
diff --git a/src/gn/target.cc b/src/gn/target.cc
index a11a014..b0ebb60 100644
--- a/src/gn/target.cc
+++ b/src/gn/target.cc
@@ -562,6 +562,8 @@
       return functions::kRustLibrary;
     case RUST_PROC_MACRO:
       return functions::kRustProcMacro;
+    case NOOP:
+      return "noop";
     default:
       return "";
   }
diff --git a/src/gn/target.h b/src/gn/target.h
index a4ff8fa..e5303ad 100644
--- a/src/gn/target.h
+++ b/src/gn/target.h
@@ -54,6 +54,7 @@
     GENERATED_FILE,
     RUST_LIBRARY,
     RUST_PROC_MACRO,
+    NOOP,
   };
 
   enum DepsIterationType {
diff --git a/src/gn/target_generator.cc b/src/gn/target_generator.cc
index 69cbaea..9ae82f9 100644
--- a/src/gn/target_generator.cc
+++ b/src/gn/target_generator.cc
@@ -82,6 +82,8 @@
   DoRun();
 }
 
+void TargetGenerator::DoRun() {}
+
 // static
 void TargetGenerator::GenerateTarget(Scope* scope,
                                      const FunctionCallNode* function_call,
@@ -95,11 +97,21 @@
     return;
   }
 
+  GenerateTarget(scope, function_call, args[0].string_value(), output_type,
+                 err);
+}
+
+// static
+Target* TargetGenerator::GenerateTarget(Scope* scope,
+                                        const FunctionCallNode* function_call,
+                                        std::string_view name,
+                                        std::string_view output_type,
+                                        Err* err) {
   // The location of the target is the directory name with no slash at the end.
   // FIXME(brettw) validate name.
   const Label& toolchain_label = ToolchainLabelForScope(scope);
-  Label label(scope->GetSourceDir(), args[0].string_value(),
-              toolchain_label.dir(), toolchain_label.name());
+  Label label(scope->GetSourceDir(), name, toolchain_label.dir(),
+              toolchain_label.name());
 
   if (g_scheduler->verbose_logging())
     g_scheduler->Log("Defining target", label.GetUserVisibleName(true));
@@ -163,21 +175,33 @@
     BinaryTargetGenerator generator(target.get(), scope, function_call,
                                     Target::RUST_PROC_MACRO, err);
     generator.Run();
+  } else if (output_type == "noop") {
+    // This is for targets associated with some (but not all) starlark rules.
+    // Starlark rules support inheritance, and so no-op is used whenever a
+    // target does not inherit from a builtin rule.
+
+    // Ensure that common attributes (eg. visibility) are set.
+    TargetGenerator generator(target.get(), scope, function_call, err);
+    generator.Run();
+    target->set_output_type(Target::NOOP);
   } else {
     *err = Err(function_call, "Not a known target type",
-               "I am very confused by the target type \"" + output_type + "\"");
+               "I am very confused by the target type \"" +
+                   std::string(output_type) + "\"");
   }
 
   if (err->has_error())
-    return;
+    return nullptr;
 
   // Save this target for the file.
   Scope::ItemVector* collector = scope->GetItemCollector();
   if (!collector) {
     *err = Err(function_call, "Can't define a target in this context.");
-    return;
+    return nullptr;
   }
+  Target* target_ptr = target.get();
   collector->push_back(std::move(target));
+  return target_ptr;
 }
 
 const BuildSettings* TargetGenerator::GetBuildSettings() const {
diff --git a/src/gn/target_generator.h b/src/gn/target_generator.h
index 442e9a8..8923daf 100644
--- a/src/gn/target_generator.h
+++ b/src/gn/target_generator.h
@@ -6,6 +6,7 @@
 #define TOOLS_GN_TARGET_GENERATOR_H_
 
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "gn/label_ptr.h"
@@ -16,6 +17,7 @@
 class FunctionCallNode;
 class Scope;
 class SubstitutionPattern;
+class Target;
 class Value;
 
 // Fills the variables in a Target object from a Scope (the result of a script
@@ -40,9 +42,15 @@
                              const std::string& output_type,
                              Err* err);
 
+  static Target* GenerateTarget(Scope* scope,
+                                const FunctionCallNode* function_call,
+                                std::string_view name,
+                                std::string_view output_type,
+                                Err* err);
+
  protected:
   // Derived classes implement this to do type-specific generation.
-  virtual void DoRun() = 0;
+  virtual void DoRun();
 
   const BuildSettings* GetBuildSettings() const;