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