#include "gn/rust_values_generator.h"
#include "gn/config_values_generator.h"
#include "gn/err.h"
#include "gn/filesystem_utils.h"
#include "gn/functions.h"
#include "gn/parse_tree.h"
#include "gn/rust_variables.h"
#include "gn/scope.h"
#include "gn/target.h"
#include "gn/value_extractors.h"
static const char* kRustSupportedCrateTypesError =
"\"crate_type\" must be one of \"bin\", \"cdylib\", \"dylib\", or "
"\"proc-macro\", \"rlib\", \"staticlib\".";
RustValuesGenerator::RustValuesGenerator(Target* target,
Scope* scope,
const FunctionCallNode* function_call,
Err* err)
: target_(target),
scope_(scope),
function_call_(function_call),
err_(err) {}
RustValuesGenerator::~RustValuesGenerator() = default;
void RustValuesGenerator::Run() {
if (target_->output_type() == Target::SOURCE_SET)
return;
if (target_->output_type() != Target::EXECUTABLE &&
target_->output_type() != Target::SHARED_LIBRARY &&
target_->output_type() != Target::RUST_LIBRARY &&
target_->output_type() != Target::RUST_PROC_MACRO &&
target_->output_type() != Target::STATIC_LIBRARY &&
target_->output_type() != Target::LOADABLE_MODULE) {
*err_ = Err(function_call_,
"Target type \"" +
std::string(Target::GetStringForOutputType(
target_->output_type())) +
"\" is not supported for Rust compilation.",
"Supported target types are \"executable\", \"loadable_module\""
"\"shared_library\", \"static_library\", or \"source_set\".");
return;
}
if (!FillCrateName())
return;
if (!FillCrateType())
return;
if (!FillCrateRoot())
return;
if (!FillAliasedDeps())
return;
}
bool RustValuesGenerator::FillCrateName() {
const Value* value = scope_->GetValue(variables::kRustCrateName, true);
if (!value) {
target_->rust_values().crate_name() = target_->label().name();
return true;
}
if (!value->VerifyTypeIs(Value::STRING, err_))
return false;
target_->rust_values().crate_name() = std::move(value->string_value());
return true;
}
bool RustValuesGenerator::FillCrateType() {
const Value* value = scope_->GetValue(variables::kRustCrateType, true);
if (!value) {
if (target_->output_type() == Target::SHARED_LIBRARY ||
target_->output_type() == Target::LOADABLE_MODULE) {
*err_ = Err(function_call_,
"Must set \"crate_type\" on a Rust \"shared_library\".",
kRustSupportedCrateTypesError);
return false;
}
return true;
}
if (!value->VerifyTypeIs(Value::STRING, err_))
return false;
if (value->string_value() == "bin") {
target_->rust_values().set_crate_type(RustValues::CRATE_BIN);
return true;
}
if (value->string_value() == "cdylib") {
target_->rust_values().set_crate_type(RustValues::CRATE_CDYLIB);
return true;
}
if (value->string_value() == "dylib") {
target_->rust_values().set_crate_type(RustValues::CRATE_DYLIB);
return true;
}
if (value->string_value() == "proc-macro") {
target_->rust_values().set_crate_type(RustValues::CRATE_PROC_MACRO);
return true;
}
if (value->string_value() == "rlib") {
target_->rust_values().set_crate_type(RustValues::CRATE_RLIB);
return true;
}
if (value->string_value() == "staticlib") {
target_->rust_values().set_crate_type(RustValues::CRATE_STATICLIB);
return true;
}
*err_ = Err(value->origin(),
"Inadmissible crate type \"" + value->string_value() + "\".",
kRustSupportedCrateTypesError);
return false;
}
bool RustValuesGenerator::FillCrateRoot() {
const Value* value = scope_->GetValue(variables::kRustCrateRoot, true);
if (!value) {
if (target_->sources().size() == 1) {
target_->rust_values().set_crate_root(target_->sources()[0]);
return true;
}
std::string to_find =
target_->output_type() == Target::EXECUTABLE ? "main.rs" : "lib.rs";
for (auto& source : target_->sources()) {
if (source.GetName() == to_find) {
target_->rust_values().set_crate_root(source);
return true;
}
}
*err_ = Err(function_call_, "Missing \"crate_root\" and missing \"" +
to_find + "\" in sources.");
return false;
}
if (!value->VerifyTypeIs(Value::STRING, err_))
return false;
SourceFile dest;
if (!ExtractRelativeFile(scope_->settings()->build_settings(), *value,
scope_->GetSourceDir(), &dest, err_))
return false;
target_->rust_values().set_crate_root(dest);
return true;
}
bool RustValuesGenerator::FillAliasedDeps() {
const Value* value = scope_->GetValue(variables::kRustAliasedDeps, true);
if (!value)
return true;
if (!value->VerifyTypeIs(Value::SCOPE, err_))
return false;
Scope::KeyValueMap aliased_deps;
value->scope_value()->GetCurrentScopeValues(&aliased_deps);
for (const auto& pair : aliased_deps) {
Label dep_label =
Label::Resolve(scope_->GetSourceDir(),
scope_->settings()->build_settings()->root_path_utf8(),
ToolchainLabelForScope(scope_), pair.second, err_);
if (err_->has_error())
return false;
target_->rust_values().aliased_deps().emplace(std::move(dep_label),
pair.first);
}
return true;
}