rust_library and Rust-specific variables

Introduces a `rust_library` target that will generate `.rlib` files, and
some associated Rust variables.

Change-Id: I93b9dfeac17a7b21bf48bb792e7ca83c475707d8
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/4882
Commit-Queue: Julie Hockett <juliehockett@google.com>
Reviewed-by: Brett Wilson <brettw@google.com>
diff --git a/build/gen.py b/build/gen.py
index 943f2e8..00752ee 100755
--- a/build/gen.py
+++ b/build/gen.py
@@ -516,6 +516,8 @@
         'tools/gn/qt_creator_writer.cc',
         'tools/gn/runtime_deps.cc',
         'tools/gn/rust_substitution_type.cc',
+        'tools/gn/rust_values.cc',
+        'tools/gn/rust_variables.cc',
         'tools/gn/scheduler.cc',
         'tools/gn/scope.cc',
         'tools/gn/scope_per_file_provider.cc',
diff --git a/tools/gn/binary_target_generator.cc b/tools/gn/binary_target_generator.cc
index 1f568b4..5b01b62 100644
--- a/tools/gn/binary_target_generator.cc
+++ b/tools/gn/binary_target_generator.cc
@@ -87,6 +87,7 @@
       case SourceFile::SOURCE_O:
       case SourceFile::SOURCE_DEF:
       case SourceFile::SOURCE_GO:
+      case SourceFile::SOURCE_RS:
       case SourceFile::SOURCE_RC:
         // These are allowed.
         break;
diff --git a/tools/gn/rust_values.cc b/tools/gn/rust_values.cc
new file mode 100644
index 0000000..08f3e5e
--- /dev/null
+++ b/tools/gn/rust_values.cc
@@ -0,0 +1,9 @@
+// Copyright 2019 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.
+
+#include "tools/gn/rust_values.h"
+
+RustValues::RustValues() : crate_type_(RustValues::CRATE_AUTO) {}
+
+RustValues::~RustValues() = default;
\ No newline at end of file
diff --git a/tools/gn/rust_values.h b/tools/gn/rust_values.h
new file mode 100644
index 0000000..a4762fb
--- /dev/null
+++ b/tools/gn/rust_values.h
@@ -0,0 +1,63 @@
+// Copyright 2019 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.
+
+#ifndef TOOLS_GN_RUST_TARGET_VALUES_H_
+#define TOOLS_GN_RUST_TARGET_VALUES_H_
+
+#include <map>
+
+#include "base/containers/flat_map.h"
+#include "tools/gn/label.h"
+#include "tools/gn/source_file.h"
+
+// Holds the values (outputs, args, script name, etc.) for either an action or
+// an action_foreach target.
+class RustValues {
+ public:
+  RustValues();
+  ~RustValues();
+
+  // Shared library crate types are specified here, all other crate types are
+  // automatically deduced from the target type (e.g. executables use crate_type
+  // = "bin", static_libraries use crate_type = "staticlib").
+  enum CrateType {
+    CRATE_AUTO = 0,
+    CRATE_DYLIB,
+    CRATE_CDYLIB,
+    CRATE_PROC_MACRO,
+  };
+
+  // Name of this crate.
+  std::string& crate_name() { return crate_name_; }
+  const std::string& crate_name() const { return crate_name_; }
+
+  // Main source file for this crate.
+  const SourceFile& crate_root() const { return crate_root_; }
+  void set_crate_root(SourceFile& s) { crate_root_ = s; }
+
+  // Crate type for compilation.
+  CrateType crate_type() { return crate_type_; }
+  const CrateType crate_type() const { return crate_type_; }
+  void set_crate_type(CrateType s) { crate_type_ = s; }
+
+  std::string& edition() { return edition_; }
+  const std::string& edition() const { return edition_; }
+
+  // Any renamed dependencies for the `extern` flags.
+  const std::map<Label, std::string>& aliased_deps() const {
+    return aliased_deps_;
+  }
+  std::map<Label, std::string>& aliased_deps() { return aliased_deps_; }
+
+ private:
+  std::string crate_name_;
+  SourceFile crate_root_;
+  CrateType crate_type_ = CRATE_AUTO;
+  std::string edition_;
+  std::map<Label, std::string> aliased_deps_;
+
+  DISALLOW_COPY_AND_ASSIGN(RustValues);
+};
+
+#endif  // TOOLS_GN_RUST_TARGET_VALUES_H_
diff --git a/tools/gn/rust_variables.cc b/tools/gn/rust_variables.cc
new file mode 100644
index 0000000..67018c7
--- /dev/null
+++ b/tools/gn/rust_variables.cc
@@ -0,0 +1,129 @@
+// Copyright 2019 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.
+
+#include "tools/gn/rust_variables.h"
+
+namespace variables {
+
+// Rust target variables ------------------------------------------------------
+
+const char kRustAliasedDeps[] = "aliased_deps";
+const char kRustAliasedDeps_HelpShort[] =
+    "aliased_deps: [scope] Set of crate-dependency pairs.";
+const char kRustAliasedDeps_Help[] =
+    R"(aliased_deps: [scope] Set of crate-dependency pairs.
+
+  Valid for `rust_library` targets and `executable`, `static_library`, and
+  `shared_library` targets that contain Rust sources.
+
+  A scope, each key indicating the renamed crate and the corresponding value
+  specifying the label of the dependency producing the relevant binary.
+
+  All dependencies listed in this field *must* be listed as deps of the target.
+
+    executable("foo") {
+      sources = [ "main.rs" ]
+      deps = [ "//bar" ]
+    }
+
+  This target would compile the `foo` crate with the following `extern` flag:
+  `rustc ...command... --extern bar=<build_out_dir>/obj/bar`
+
+    executable("foo") {
+      sources = [ "main.rs" ]
+      deps = [ ":bar" ]
+      aliased_deps = {
+        bar_renamed = ":bar"
+      }
+    }
+
+  With the addition of `aliased_deps`, above target would instead compile with:
+  `rustc ...command... --extern bar_renamed=<build_out_dir>/obj/bar`
+)";
+
+const char kRustCrateName[] = "crate_name";
+const char kRustCrateName_HelpShort[] =
+    "crate_name: [string] The name for the compiled crate.";
+const char kRustCrateName_Help[] =
+    R"(crate_name: [string] The name for the compiled crate.
+
+  Valid for `rust_library` targets and `executable`, `static_library`,
+  `shared_library`, and `source_set` targets that contain Rust sources.
+
+  If crate_name is not set, then this rule will use the target name.
+)";
+
+const char kRustCrateType[] = "crate_type";
+const char kRustCrateType_HelpShort[] =
+    "crate_type: [string] The type of linkage to use on a shared_library.";
+const char kRustCrateType_Help[] =
+    R"(crate_type: [string] The type of linkage to use on a shared_library.
+
+  Valid for `rust_library` targets and `executable`, `static_library`,
+  `shared_library`, and `source_set` targets that contain Rust sources.
+
+  Options for this field are "cdylib", "staticlib", "proc-macro", and "dylib".
+  This field sets the `crate-type` attribute for the `rustc` tool on static
+  libraries, as well as the appropiate output extension in the
+  `rust_output_extension` attribute. Since outputs must be explicit, the `lib`
+  crate type (where the Rust compiler produces what it thinks is the
+  appropriate library type) is not supported.
+
+  It should be noted that the "dylib" crate type in Rust is unstable in the set
+  of symbols it exposes, and most usages today are potentially wrong and will
+  be broken in the future.
+
+  Static libraries, rust libraries, and executables have this field set
+  automatically.
+)";
+
+const char kRustCrateRoot[] = "crate_root";
+const char kRustCrateRoot_HelpShort[] =
+    "crate_root: [string] The root source file for a binary or library.";
+const char kRustCrateRoot_Help[] =
+    R"(crate_root: [string] The root source file for a binary or library.
+
+  Valid for `rust_library` targets and `executable`, `static_library`,
+  `shared_library`, and `source_set` targets that contain Rust sources.
+
+  This file is usually the `main.rs` or `lib.rs` for binaries and libraries,
+  respectively.
+
+  If crate_root is not set, then this rule will look for a lib.rs file (or
+  main.rs for executable) or a single file in sources, if sources contains
+  only one file.
+)";
+
+const char kRustEdition[] = "edition";
+const char kRustEdition_HelpShort[] =
+    "edition: [string] The rustc edition to use in compiliation.";
+const char kRustEdition_Help[] =
+    R"(edition: [string] The rustc edition to use in compiliation.
+
+  Valid for `rust_library` targets and `executable`, `static_library`,
+  `shared_library`, and `source_set` targets that contain Rust sources.
+
+  This indicates the compiler edition to use in compilition. Should be a value
+  like "2015" or "2018", indiicating the appropriate value to pass to the
+  `--edition=<>` flag in rustc.
+)";
+
+void InsertRustVariables(VariableInfoMap* info_map) {
+  info_map->insert(std::make_pair(
+      kRustAliasedDeps,
+      VariableInfo(kRustAliasedDeps_HelpShort, kRustAliasedDeps_Help)));
+  info_map->insert(std::make_pair(
+      kRustCrateName,
+      VariableInfo(kRustCrateName_HelpShort, kRustCrateName_Help)));
+  info_map->insert(std::make_pair(
+      kRustCrateType,
+      VariableInfo(kRustCrateType_HelpShort, kRustCrateType_Help)));
+  info_map->insert(std::make_pair(
+      kRustCrateRoot,
+      VariableInfo(kRustCrateRoot_HelpShort, kRustCrateRoot_Help)));
+  info_map->insert(std::make_pair(
+      kRustEdition, VariableInfo(kRustEdition_HelpShort, kRustEdition_Help)));
+}
+
+}  // namespace variables
diff --git a/tools/gn/rust_variables.h b/tools/gn/rust_variables.h
new file mode 100644
index 0000000..c9ae4a0
--- /dev/null
+++ b/tools/gn/rust_variables.h
@@ -0,0 +1,38 @@
+// Copyright 2019 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.
+
+#ifndef TOOLS_GN_RUST_VARIABLES_H_
+#define TOOLS_GN_RUST_VARIABLES_H_
+
+#include "tools/gn/variables.h"
+
+namespace variables {
+
+// Rust target vars ------------------------------------------------------
+
+extern const char kRustAliasedDeps[];
+extern const char kRustAliasedDeps_HelpShort[];
+extern const char kRustAliasedDeps_Help[];
+
+extern const char kRustCrateName[];
+extern const char kRustCrateName_HelpShort[];
+extern const char kRustCrateName_Help[];
+
+extern const char kRustCrateType[];
+extern const char kRustCrateType_HelpShort[];
+extern const char kRustCrateType_Help[];
+
+extern const char kRustCrateRoot[];
+extern const char kRustCrateRoot_HelpShort[];
+extern const char kRustCrateRoot_Help[];
+
+extern const char kRustEdition[];
+extern const char kRustEdition_HelpShort[];
+extern const char kRustEdition_Help[];
+
+void InsertRustVariables(VariableInfoMap* info_map);
+
+}  // namespace variables
+
+#endif  // TOOLS_GN_RUST_VARIABLES_H_
\ No newline at end of file
diff --git a/tools/gn/target.cc b/tools/gn/target.cc
index 1afd22b..d48ffd9 100644
--- a/tools/gn/target.cc
+++ b/tools/gn/target.cc
@@ -407,11 +407,12 @@
 bool Target::IsBinary() const {
   return output_type_ == EXECUTABLE || output_type_ == SHARED_LIBRARY ||
          output_type_ == LOADABLE_MODULE || output_type_ == STATIC_LIBRARY ||
-         output_type_ == SOURCE_SET;
+         output_type_ == SOURCE_SET || output_type_ == RUST_LIBRARY;
 }
 
 bool Target::IsLinkable() const {
-  return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY;
+  return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY ||
+         output_type_ == RUST_LIBRARY;
 }
 
 bool Target::IsFinal() const {
@@ -419,7 +420,8 @@
          output_type_ == LOADABLE_MODULE || output_type_ == ACTION ||
          output_type_ == ACTION_FOREACH || output_type_ == COPY_FILES ||
          output_type_ == CREATE_BUNDLE ||
-         (output_type_ == STATIC_LIBRARY && complete_static_lib_);
+         (output_type_ == STATIC_LIBRARY && complete_static_lib_) ||
+         output_type_ == RUST_LIBRARY;
 }
 
 DepsIteratorRange Target::GetDeps(DepsIterationType type) const {
@@ -464,18 +466,18 @@
 
   // Tool not specified for this target type.
   if (err) {
-    *err = Err(
-        defined_from(), "This target uses an undefined tool.",
-        base::StringPrintf(
-            "The target %s\n"
-            "of type \"%s\"\n"
-            "uses toolchain %s\n"
-            "which doesn't have the tool \"%s\" defined.\n\n"
-            "Alas, I can not continue.",
-            label().GetUserVisibleName(false).c_str(),
-            GetStringForOutputType(output_type_),
-            label().GetToolchainLabel().GetUserVisibleName(false).c_str(),
-            Tool::GetToolTypeForTargetFinalOutput(this)));
+    *err =
+        Err(defined_from(), "This target uses an undefined tool.",
+            base::StringPrintf(
+                "The target %s\n"
+                "of type \"%s\"\n"
+                "uses toolchain %s\n"
+                "which doesn't have the tool \"%s\" defined.\n\n"
+                "Alas, I can not continue.",
+                label().GetUserVisibleName(false).c_str(),
+                GetStringForOutputType(output_type_),
+                label().GetToolchainLabel().GetUserVisibleName(false).c_str(),
+                Tool::GetToolTypeForTargetFinalOutput(this)));
   }
   return false;
 }
@@ -525,7 +527,8 @@
 void Target::PullDependentTargetLibsFrom(const Target* dep, bool is_public) {
   // Direct dependent libraries.
   if (dep->output_type() == STATIC_LIBRARY ||
-      dep->output_type() == SHARED_LIBRARY || dep->output_type() == SOURCE_SET)
+      dep->output_type() == SHARED_LIBRARY ||
+      dep->output_type() == SOURCE_SET || dep->output_type() == RUST_LIBRARY)
     inherited_libraries_.Append(dep, is_public);
 
   if (dep->output_type() == SHARED_LIBRARY) {
@@ -550,7 +553,7 @@
     // library.
     inherited_libraries_.AppendPublicSharedLibraries(dep->inherited_libraries(),
                                                      is_public);
-  } else if (!dep->IsFinal()) {
+  } else if (!dep->IsFinal() || dep->output_type() == RUST_LIBRARY) {
     // The current target isn't linked, so propogate linked deps and
     // libraries up the dependency tree.
     inherited_libraries_.AppendInherited(dep->inherited_libraries(), is_public);
@@ -571,7 +574,8 @@
   }
 
   // Library settings are always inherited across static library boundaries.
-  if (!dep->IsFinal() || dep->output_type() == STATIC_LIBRARY) {
+  if (!dep->IsFinal() || dep->output_type() == STATIC_LIBRARY ||
+      dep->output_type() == RUST_LIBRARY) {
     all_lib_dirs_.append(dep->all_lib_dirs());
     all_libs_.append(dep->all_libs());
   }
@@ -667,6 +671,7 @@
             this, tool, tool->runtime_outputs(), &runtime_outputs_);
       }
       break;
+    case RUST_LIBRARY:
     case STATIC_LIBRARY:
       // Static libraries both have dependencies and linking going off of the
       // first output.
diff --git a/tools/gn/target.h b/tools/gn/target.h
index 1256818..60014d7 100644
--- a/tools/gn/target.h
+++ b/tools/gn/target.h
@@ -23,6 +23,7 @@
 #include "tools/gn/metadata.h"
 #include "tools/gn/ordered_set.h"
 #include "tools/gn/output_file.h"
+#include "tools/gn/rust_values.h"
 #include "tools/gn/source_file.h"
 #include "tools/gn/toolchain.h"
 #include "tools/gn/unique_vector.h"
@@ -47,6 +48,7 @@
     BUNDLE_DATA,
     CREATE_BUNDLE,
     GENERATED_FILE,
+    RUST_LIBRARY,
   };
 
   enum DepsIterationType {
@@ -268,6 +270,9 @@
   ActionValues& action_values() { return action_values_; }
   const ActionValues& action_values() const { return action_values_; }
 
+  RustValues& rust_values() { return rust_values_; }
+  const RustValues& rust_values() const { return rust_values_; }
+
   const OrderedSet<SourceDir>& all_lib_dirs() const { return all_lib_dirs_; }
   const OrderedSet<LibFile>& all_libs() const { return all_libs_; }
 
@@ -417,6 +422,9 @@
   // Used for action[_foreach] targets.
   ActionValues action_values_;
 
+  // Used for Rust targets.
+  RustValues rust_values_;
+
   // Toolchain used by this target. Null until target is resolved.
   const Toolchain* toolchain_;
 
diff --git a/tools/gn/variables.cc b/tools/gn/variables.cc
index 234a2ca..43ef8a0 100644
--- a/tools/gn/variables.cc
+++ b/tools/gn/variables.cc
@@ -4,6 +4,8 @@
 
 #include "tools/gn/variables.h"
 
+#include "tools/gn/rust_variables.h"
+
 namespace variables {
 
 // Built-in variables ----------------------------------------------------------
@@ -1917,6 +1919,10 @@
   static library or source set will have no effect on the executable or shared
   library they're linked into).
 
+  For Rust targets that do not specify a crate_root, then the crate_root will
+  look for a lib.rs file (or main.rs for executable) or a single file in
+  sources, if sources contains only one file.
+
 Sources for non-binary targets
 
   action_foreach
@@ -2203,6 +2209,7 @@
     INSERT_VARIABLE(WriteValueContents)
     INSERT_VARIABLE(WriteRuntimeDeps)
     INSERT_VARIABLE(XcodeExtraAttributes)
+    InsertRustVariables(&info_map);
   }
   return info_map;
 }