This source file includes following definitions.
- DirWithNoTrailingSlash
- ComputeBuildLocationFromDep
- ComputeTargetNameFromDep
- Resolve
- toolchain_dir_
- Resolve
- GetToolchainLabel
- GetWithNoToolchain
- GetUserVisibleName
- GetUserVisibleName
#include "tools/gn/label.h"
#include "base/logging.h"
#include "tools/gn/err.h"
#include "tools/gn/parse_tree.h"
#include "tools/gn/value.h"
namespace {
std::string DirWithNoTrailingSlash(const SourceDir& dir) {
if (dir.value().size() > 2)
return dir.value().substr(0, dir.value().size() - 1);
return dir.value();
}
bool ComputeBuildLocationFromDep(const Value& input_value,
const SourceDir& current_dir,
const base::StringPiece& input,
SourceDir* result,
Err* err) {
if (input.empty()) {
*result = current_dir;
return true;
}
if (input[0] == '/' && (input.size() == 1 || input[1] != '/')) {
*err = Err(input_value, "Label can't start with a single slash",
"Labels must be either relative (no slash at the beginning) or be "
"absolute\ninside the source root (two slashes at the beginning).");
return false;
}
*result = current_dir.ResolveRelativeDir(input);
return true;
}
bool ComputeTargetNameFromDep(const Value& input_value,
const SourceDir& computed_location,
const base::StringPiece& input,
std::string* result,
Err* err) {
if (!input.empty()) {
result->assign(input.data(), input.size());
return true;
}
const std::string& loc = computed_location.value();
if (loc.size() <= 2) {
*err = Err(input_value, "This dependency name is empty");
return false;
}
size_t next_to_last_slash = loc.rfind('/', loc.size() - 2);
DCHECK(next_to_last_slash != std::string::npos);
result->assign(&loc[next_to_last_slash + 1],
loc.size() - next_to_last_slash - 2);
return true;
}
bool Resolve(const SourceDir& current_dir,
const Label& current_toolchain,
const Value& original_value,
const base::StringPiece& input,
SourceDir* out_dir,
std::string* out_name,
SourceDir* out_toolchain_dir,
std::string* out_toolchain_name,
Err* err) {
const char* input_str = input.data();
size_t path_separator = input.find_first_of(":(");
base::StringPiece location_piece;
base::StringPiece name_piece;
base::StringPiece toolchain_piece;
if (path_separator == std::string::npos) {
location_piece = input;
} else {
location_piece = base::StringPiece(&input_str[0], path_separator);
size_t toolchain_separator = input.find('(', path_separator);
if (toolchain_separator == std::string::npos) {
name_piece = base::StringPiece(&input_str[path_separator + 1],
input.size() - path_separator - 1);
} else if (!out_toolchain_dir) {
*err = Err(original_value, "Toolchain has a toolchain.",
"Your toolchain definition (inside the parens) seems to itself "
"have a\ntoolchain. Don't do this.");
return false;
} else {
if (toolchain_separator > path_separator) {
name_piece = base::StringPiece(
&input_str[path_separator + 1],
toolchain_separator - path_separator - 1);
}
if (input[input.size() - 1] != ')') {
*err = Err(original_value, "Bad toolchain name.",
"Toolchain name must end in a \")\" at the end of the label.");
return false;
}
toolchain_piece = base::StringPiece(
&input_str[toolchain_separator + 1],
input.size() - toolchain_separator - 2);
}
}
if (location_piece.empty() && name_piece.empty()) {
*err = Err(original_value, "This doesn't specify a dependency.");
return false;
}
if (!ComputeBuildLocationFromDep(original_value, current_dir, location_piece,
out_dir, err))
return false;
if (!ComputeTargetNameFromDep(original_value, *out_dir, name_piece,
out_name, err))
return false;
if (out_toolchain_dir) {
if (toolchain_piece.empty()) {
*out_toolchain_dir = current_toolchain.dir();
*out_toolchain_name = current_toolchain.name();
return true;
} else {
return Resolve(current_dir, current_toolchain,
original_value, toolchain_piece,
out_toolchain_dir, out_toolchain_name, NULL, NULL, err);
}
}
return true;
}
}
Label::Label() {
}
Label::Label(const SourceDir& dir,
const base::StringPiece& name,
const SourceDir& toolchain_dir,
const base::StringPiece& toolchain_name)
: dir_(dir),
toolchain_dir_(toolchain_dir) {
name_.assign(name.data(), name.size());
toolchain_name_.assign(toolchain_name.data(), toolchain_name.size());
}
Label::Label(const SourceDir& dir, const base::StringPiece& name)
: dir_(dir) {
name_.assign(name.data(), name.size());
}
Label::~Label() {
}
Label Label::Resolve(const SourceDir& current_dir,
const Label& current_toolchain,
const Value& input,
Err* err) {
Label ret;
if (input.type() != Value::STRING) {
*err = Err(input, "Dependency is not a string.");
return ret;
}
const std::string& input_string = input.string_value();
if (input_string.empty()) {
*err = Err(input, "Dependency string is empty.");
return ret;
}
if (!::Resolve(current_dir, current_toolchain, input, input_string,
&ret.dir_, &ret.name_,
&ret.toolchain_dir_, &ret.toolchain_name_,
err))
return Label();
return ret;
}
Label Label::GetToolchainLabel() const {
return Label(toolchain_dir_, toolchain_name_);
}
Label Label::GetWithNoToolchain() const {
return Label(dir_, name_);
}
std::string Label::GetUserVisibleName(bool include_toolchain) const {
std::string ret;
ret.reserve(dir_.value().size() + name_.size() + 1);
if (dir_.is_null())
return ret;
ret = DirWithNoTrailingSlash(dir_);
ret.push_back(':');
ret.append(name_);
if (include_toolchain) {
ret.push_back('(');
if (!toolchain_dir_.is_null() && !toolchain_name_.empty()) {
ret.append(DirWithNoTrailingSlash(toolchain_dir_));
ret.push_back(':');
ret.append(toolchain_name_);
}
ret.push_back(')');
}
return ret;
}
std::string Label::GetUserVisibleName(const Label& default_toolchain) const {
bool include_toolchain =
default_toolchain.dir() != toolchain_dir_ ||
default_toolchain.name() != toolchain_name_;
return GetUserVisibleName(include_toolchain);
}