shaka-packager/tools/gn/target_generator.cc

230 lines
7.3 KiB
C++

// Copyright (c) 2013 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/target_generator.h"
#include "tools/gn/binary_target_generator.h"
#include "tools/gn/build_settings.h"
#include "tools/gn/config.h"
#include "tools/gn/copy_target_generator.h"
#include "tools/gn/err.h"
#include "tools/gn/functions.h"
#include "tools/gn/group_target_generator.h"
#include "tools/gn/item_node.h"
#include "tools/gn/parse_tree.h"
#include "tools/gn/scheduler.h"
#include "tools/gn/scope.h"
#include "tools/gn/script_target_generator.h"
#include "tools/gn/target_manager.h"
#include "tools/gn/token.h"
#include "tools/gn/value.h"
#include "tools/gn/value_extractors.h"
#include "tools/gn/variables.h"
TargetGenerator::TargetGenerator(Target* target,
Scope* scope,
const Token& function_token,
Err* err)
: target_(target),
scope_(scope),
function_token_(function_token),
err_(err),
input_directory_(function_token.location().file()->dir()) {
}
TargetGenerator::~TargetGenerator() {
}
void TargetGenerator::Run() {
// All target types use these.
FillDependentConfigs();
FillData();
FillDependencies();
// To type-specific generation.
DoRun();
// Mark the target as complete.
if (!err_->has_error()) {
target_->SetGenerated(&function_token_);
GetBuildSettings()->target_manager().TargetGenerationComplete(
target_->label(), err_);
}
}
// static
void TargetGenerator::GenerateTarget(Scope* scope,
const Token& function_token,
const std::vector<Value>& args,
const std::string& output_type,
Err* err) {
// Name is the argument to the function.
if (args.size() != 1u || args[0].type() != Value::STRING) {
*err = Err(function_token,
"Target generator requires one string argument.",
"Otherwise I'm not sure what to call this target.");
return;
}
// 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(function_token.location().file()->dir(),
args[0].string_value(),
toolchain_label.dir(), toolchain_label.name());
if (g_scheduler->verbose_logging())
g_scheduler->Log("Generating target", label.GetUserVisibleName(true));
Target* target =
scope->settings()->build_settings()->target_manager().GetTarget(
label, function_token.range(), NULL, err);
if (err->has_error())
return;
// Create and call out to the proper generator.
if (output_type == functions::kCopy) {
CopyTargetGenerator generator(target, scope, function_token, err);
generator.Run();
} else if (output_type == functions::kCustom) {
ScriptTargetGenerator generator(target, scope, function_token, err);
generator.Run();
} else if (output_type == functions::kExecutable) {
BinaryTargetGenerator generator(target, scope, function_token,
Target::EXECUTABLE, err);
generator.Run();
} else if (output_type == functions::kGroup) {
GroupTargetGenerator generator(target, scope, function_token, err);
generator.Run();
} else if (output_type == functions::kSharedLibrary) {
BinaryTargetGenerator generator(target, scope, function_token,
Target::SHARED_LIBRARY, err);
generator.Run();
} else if (output_type == functions::kStaticLibrary) {
BinaryTargetGenerator generator(target, scope, function_token,
Target::STATIC_LIBRARY, err);
generator.Run();
} else {
*err = Err(function_token, "Not a known output type",
"I am very confused.");
}
}
const BuildSettings* TargetGenerator::GetBuildSettings() const {
return scope_->settings()->build_settings();
}
void TargetGenerator::FillSources() {
const Value* value = scope_->GetValue(variables::kSources, true);
if (!value)
return;
Target::FileList dest_sources;
if (!ExtractListOfRelativeFiles(*value, input_directory_, &dest_sources,
err_))
return;
target_->swap_in_sources(&dest_sources);
}
void TargetGenerator::FillConfigs() {
FillGenericConfigs(variables::kConfigs, &Target::swap_in_configs);
}
void TargetGenerator::FillDependentConfigs() {
FillGenericConfigs(variables::kAllDependentConfigs,
&Target::swap_in_all_dependent_configs);
FillGenericConfigs(variables::kDirectDependentConfigs,
&Target::swap_in_direct_dependent_configs);
}
void TargetGenerator::FillData() {
// TODO(brettW) hook this up to the constant when we have cleaned up
// how data files are used.
const Value* value = scope_->GetValue("data", true);
if (!value)
return;
Target::FileList dest_data;
if (!ExtractListOfRelativeFiles(*value, input_directory_, &dest_data,
err_))
return;
target_->swap_in_data(&dest_data);
}
void TargetGenerator::FillDependencies() {
FillGenericDeps(variables::kDeps, &Target::swap_in_deps);
FillGenericDeps(variables::kDatadeps, &Target::swap_in_datadeps);
}
void TargetGenerator::SetToolchainDependency() {
// TODO(brettw) currently we lock separately for each config, dep, and
// toolchain we add which is bad! Do this in one lock.
ItemTree* tree = &GetBuildSettings()->item_tree();
base::AutoLock lock(tree->lock());
ItemNode* tc_node =
tree->GetExistingNodeLocked(ToolchainLabelForScope(scope_));
tree->GetExistingNodeLocked(target_->label())->AddDependency(
GetBuildSettings(), function_token_.range(), tc_node, err_);
}
void TargetGenerator::FillGenericConfigs(
const char* var_name,
void (Target::*setter)(std::vector<const Config*>*)) {
const Value* value = scope_->GetValue(var_name, true);
if (!value)
return;
std::vector<Label> labels;
if (!ExtractListOfLabels(*value, input_directory_,
ToolchainLabelForScope(scope_), &labels, err_))
return;
std::vector<const Config*> dest_configs;
dest_configs.resize(labels.size());
for (size_t i = 0; i < labels.size(); i++) {
dest_configs[i] = Config::GetConfig(
scope_->settings(),
value->list_value()[i].origin()->GetRange(),
labels[i], target_, err_);
if (err_->has_error())
return;
}
(target_->*setter)(&dest_configs);
}
void TargetGenerator::FillGenericDeps(
const char* var_name,
void (Target::*setter)(std::vector<const Target*>*)) {
const Value* value = scope_->GetValue(var_name, true);
if (!value)
return;
std::vector<Label> labels;
if (!ExtractListOfLabels(*value, input_directory_,
ToolchainLabelForScope(scope_), &labels, err_))
return;
std::vector<const Target*> dest_deps;
dest_deps.resize(labels.size());
for (size_t i = 0; i < labels.size(); i++) {
dest_deps[i] = GetBuildSettings()->target_manager().GetTarget(
labels[i], value->list_value()[i].origin()->GetRange(), target_, err_);
if (err_->has_error())
return;
}
(target_->*setter)(&dest_deps);
}