• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "gn/rust_values_generator.h"
6 
7 #include "gn/config_values_generator.h"
8 #include "gn/err.h"
9 #include "gn/filesystem_utils.h"
10 #include "gn/functions.h"
11 #include "gn/parse_tree.h"
12 #include "gn/rust_variables.h"
13 #include "gn/scope.h"
14 #include "gn/target.h"
15 #include "gn/value_extractors.h"
16 
17 static const char* kRustSupportedCrateTypesError =
18     "\"crate_type\" must be one of \"bin\", \"cdylib\", \"dylib\", or "
19     "\"proc-macro\", \"rlib\", \"staticlib\".";
20 
RustValuesGenerator(Target * target,Scope * scope,const FunctionCallNode * function_call,Err * err)21 RustValuesGenerator::RustValuesGenerator(Target* target,
22                                          Scope* scope,
23                                          const FunctionCallNode* function_call,
24                                          Err* err)
25     : target_(target),
26       scope_(scope),
27       function_call_(function_call),
28       err_(err) {}
29 
30 RustValuesGenerator::~RustValuesGenerator() = default;
31 
Run()32 void RustValuesGenerator::Run() {
33   // source_set targets don't need any special Rust handling.
34   if (target_->output_type() == Target::SOURCE_SET)
35     return;
36 
37   // Check that this type of target is Rust-supported.
38   if (target_->output_type() != Target::EXECUTABLE &&
39       target_->output_type() != Target::SHARED_LIBRARY &&
40       target_->output_type() != Target::RUST_LIBRARY &&
41       target_->output_type() != Target::RUST_PROC_MACRO &&
42       target_->output_type() != Target::STATIC_LIBRARY &&
43       target_->output_type() != Target::LOADABLE_MODULE) {
44     // Only valid rust output types.
45     *err_ = Err(function_call_,
46                 "Target type \"" +
47                     std::string(Target::GetStringForOutputType(
48                         target_->output_type())) +
49                     "\" is not supported for Rust compilation.",
50                 "Supported target types are \"executable\", \"loadable_module\""
51                 "\"shared_library\", \"static_library\", or \"source_set\".");
52     return;
53   }
54 
55   if (!FillCrateName())
56     return;
57 
58   if (!FillCrateType())
59     return;
60 
61   if (!FillCrateRoot())
62     return;
63 
64   if (!FillAliasedDeps())
65     return;
66 }
67 
FillCrateName()68 bool RustValuesGenerator::FillCrateName() {
69   const Value* value = scope_->GetValue(variables::kRustCrateName, true);
70   if (!value) {
71     // The target name will be used.
72     target_->rust_values().crate_name() = target_->label().name();
73     return true;
74   }
75   if (!value->VerifyTypeIs(Value::STRING, err_))
76     return false;
77 
78   target_->rust_values().crate_name() = std::move(value->string_value());
79   return true;
80 }
81 
FillCrateType()82 bool RustValuesGenerator::FillCrateType() {
83   const Value* value = scope_->GetValue(variables::kRustCrateType, true);
84   if (!value) {
85     // Require shared_library and loadable_module targets to tell us what
86     // they want.
87     if (target_->output_type() == Target::SHARED_LIBRARY ||
88         target_->output_type() == Target::LOADABLE_MODULE) {
89       *err_ = Err(function_call_,
90                   "Must set \"crate_type\" on a Rust \"shared_library\".",
91                   kRustSupportedCrateTypesError);
92       return false;
93     }
94 
95     return true;
96   }
97 
98   if (!value->VerifyTypeIs(Value::STRING, err_))
99     return false;
100 
101   if (value->string_value() == "bin") {
102     target_->rust_values().set_crate_type(RustValues::CRATE_BIN);
103     return true;
104   }
105   if (value->string_value() == "cdylib") {
106     target_->rust_values().set_crate_type(RustValues::CRATE_CDYLIB);
107     return true;
108   }
109   if (value->string_value() == "dylib") {
110     target_->rust_values().set_crate_type(RustValues::CRATE_DYLIB);
111     return true;
112   }
113   if (value->string_value() == "proc-macro") {
114     target_->rust_values().set_crate_type(RustValues::CRATE_PROC_MACRO);
115     return true;
116   }
117   if (value->string_value() == "rlib") {
118     target_->rust_values().set_crate_type(RustValues::CRATE_RLIB);
119     return true;
120   }
121   if (value->string_value() == "staticlib") {
122     target_->rust_values().set_crate_type(RustValues::CRATE_STATICLIB);
123     return true;
124   }
125 
126   *err_ = Err(value->origin(),
127               "Inadmissible crate type \"" + value->string_value() + "\".",
128               kRustSupportedCrateTypesError);
129   return false;
130 }
131 
FillCrateRoot()132 bool RustValuesGenerator::FillCrateRoot() {
133   const Value* value = scope_->GetValue(variables::kRustCrateRoot, true);
134   if (!value) {
135     // If there's only one source, use that.
136     if (target_->sources().size() == 1) {
137       target_->rust_values().set_crate_root(target_->sources()[0]);
138       return true;
139     }
140     // Otherwise, see if "lib.rs" or "main.rs" (as relevant) are in sources.
141     std::string to_find =
142         target_->output_type() == Target::EXECUTABLE ? "main.rs" : "lib.rs";
143     for (auto& source : target_->sources()) {
144       if (source.GetName() == to_find) {
145         target_->rust_values().set_crate_root(source);
146         return true;
147       }
148     }
149     *err_ = Err(function_call_, "Missing \"crate_root\" and missing \"" +
150                                     to_find + "\" in sources.");
151     return false;
152   }
153 
154   if (!value->VerifyTypeIs(Value::STRING, err_))
155     return false;
156 
157   SourceFile dest;
158   if (!ExtractRelativeFile(scope_->settings()->build_settings(), *value,
159                            scope_->GetSourceDir(), &dest, err_))
160     return false;
161 
162   target_->rust_values().set_crate_root(dest);
163   return true;
164 }
165 
FillAliasedDeps()166 bool RustValuesGenerator::FillAliasedDeps() {
167   const Value* value = scope_->GetValue(variables::kRustAliasedDeps, true);
168   if (!value)
169     return true;
170 
171   if (!value->VerifyTypeIs(Value::SCOPE, err_))
172     return false;
173 
174   Scope::KeyValueMap aliased_deps;
175   value->scope_value()->GetCurrentScopeValues(&aliased_deps);
176   for (const auto& pair : aliased_deps) {
177     Label dep_label =
178         Label::Resolve(scope_->GetSourceDir(),
179                        scope_->settings()->build_settings()->root_path_utf8(),
180                        ToolchainLabelForScope(scope_), pair.second, err_);
181 
182     if (err_->has_error())
183       return false;
184 
185     // Insert into the aliased_deps map.
186     target_->rust_values().aliased_deps().emplace(std::move(dep_label),
187                                                   pair.first);
188   }
189 
190   return true;
191 }
192