Commit 7380ca75 authored by brettw@chromium.org's avatar brettw@chromium.org

Add GN function get_label_info

This function retrieves information about a label like the name, directory, etc.

R=cjhopman@chromium.org

Review URL: https://codereview.chromium.org/279023002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@270130 0039d316-1c4b-4281-b951-d872f2087c98
parent a80b2ed4
......@@ -52,6 +52,7 @@ static_library("gn_lib") {
"functions.h",
"functions_target.cc",
"function_exec_script.cc",
"function_get_label_info.cc",
"function_get_target_outputs.cc",
"function_process_file_template.cc",
"function_read_file.cc",
......@@ -178,6 +179,7 @@ test("gn_unittests") {
"escape_unittest.cc",
"filesystem_utils_unittest.cc",
"file_template_unittest.cc",
"function_get_label_info_unittest.cc",
"function_get_target_outputs_unittest.cc",
"function_rebase_path_unittest.cc",
"functions_unittest.cc",
......
......@@ -178,7 +178,7 @@ TEST_F(BuilderTest, ShouldGenerate) {
DefineToolchain();
// Define a secondary toolchain.
Settings settings2(&build_settings_, "secondary");
Settings settings2(&build_settings_, "secondary/");
Label toolchain_label2(SourceDir("//tc/"), "secondary");
settings2.set_toolchain_label(toolchain_label2);
Toolchain* tc2 = new Toolchain(&settings2, toolchain_label2);
......
......@@ -667,6 +667,16 @@ SourceDir SourceDirForCurrentDirectory(const base::FilePath& source_root) {
return SourceDirForPath(source_root, cd);
}
std::string GetOutputSubdirName(const Label& toolchain_label, bool is_default) {
// The default toolchain has no subdir.
if (is_default)
return std::string();
// For now just assume the toolchain name is always a valid dir name. We may
// want to clean up the in the future.
return toolchain_label.name() + "/";
}
SourceDir GetToolchainOutputDir(const Settings* settings) {
const OutputFile& toolchain_subdir = settings->toolchain_output_subdir();
......@@ -677,6 +687,13 @@ SourceDir GetToolchainOutputDir(const Settings* settings) {
return SourceDir(SourceDir::SWAP_IN, &result);
}
SourceDir GetToolchainOutputDir(const BuildSettings* build_settings,
const Label& toolchain_label, bool is_default) {
std::string result = build_settings->build_dir().value();
result.append(GetOutputSubdirName(toolchain_label, is_default));
return SourceDir(SourceDir::SWAP_IN, &result);
}
SourceDir GetToolchainGenDir(const Settings* settings) {
const OutputFile& toolchain_subdir = settings->toolchain_output_subdir();
......@@ -688,6 +705,14 @@ SourceDir GetToolchainGenDir(const Settings* settings) {
return SourceDir(SourceDir::SWAP_IN, &result);
}
SourceDir GetToolchainGenDir(const BuildSettings* build_settings,
const Label& toolchain_label, bool is_default) {
std::string result = GetToolchainOutputDir(
build_settings, toolchain_label, is_default).value();
result.append("gen/");
return SourceDir(SourceDir::SWAP_IN, &result);
}
SourceDir GetOutputDirForSourceDir(const Settings* settings,
const SourceDir& source_dir) {
SourceDir toolchain = GetToolchainOutputDir(settings);
......
......@@ -166,11 +166,21 @@ SourceDir SourceDirForPath(const base::FilePath& source_root,
// directory.
SourceDir SourceDirForCurrentDirectory(const base::FilePath& source_root);
// Given the label of a toolchain and whether that toolchain is the default
// toolchain, returns the name of the subdirectory for that toolchain's
// output. This will be the empty string to indicate that the toolchain outputs
// go in the root build directory. Otherwise, the result will end in a slash.
std::string GetOutputSubdirName(const Label& toolchain_label, bool is_default);
// -----------------------------------------------------------------------------
// These functions return the various flavors of output and gen directories.
SourceDir GetToolchainOutputDir(const Settings* settings);
SourceDir GetToolchainOutputDir(const BuildSettings* build_settings,
const Label& label, bool is_default);
SourceDir GetToolchainGenDir(const Settings* settings);
SourceDir GetToolchainGenDir(const BuildSettings* build_settings,
const Label& toolchain_label, bool is_default);
SourceDir GetOutputDirForSourceDir(const Settings* settings,
const SourceDir& source_dir);
SourceDir GetGenDirForSourceDir(const Settings* settings,
......
......@@ -336,7 +336,7 @@ TEST(FilesystemUtils, GetToolchainDirs) {
EXPECT_EQ("//out/Debug/gen/",
GetToolchainGenDir(&default_settings).value());
Settings other_settings(&build_settings, "two");
Settings other_settings(&build_settings, "two/");
EXPECT_EQ("//out/Debug/two/",
GetToolchainOutputDir(&other_settings).value());
EXPECT_EQ("//out/Debug/two/gen/",
......@@ -357,7 +357,7 @@ TEST(FilesystemUtils, GetOutDirForSourceDir) {
SourceDir("//foo/bar/")).value());
// Secondary toolchain.
Settings other_settings(&build_settings, "two");
Settings other_settings(&build_settings, "two/");
EXPECT_EQ("//out/Debug/two/obj/",
GetOutputDirForSourceDir(&other_settings, SourceDir("//")).value());
EXPECT_EQ("//out/Debug/two/obj/foo/bar/",
......@@ -378,7 +378,7 @@ TEST(FilesystemUtils, GetGenDirForSourceDir) {
SourceDir("//foo/bar/")).value());
// Secondary toolchain.
Settings other_settings(&build_settings, "two");
Settings other_settings(&build_settings, "two/");
EXPECT_EQ("//out/Debug/two/gen/",
GetGenDirForSourceDir(&other_settings, SourceDir("//")).value());
EXPECT_EQ("//out/Debug/two/gen/foo/bar/",
......
// Copyright 2014 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/err.h"
#include "tools/gn/filesystem_utils.h"
#include "tools/gn/functions.h"
#include "tools/gn/label.h"
#include "tools/gn/parse_tree.h"
#include "tools/gn/value.h"
namespace functions {
const char kGetLabelInfo[] = "get_label_info";
const char kGetLabelInfo_HelpShort[] =
"get_label_info: Get an attribute from a target's label.";
const char kGetLabelInfo_Help[] =
"get_label_info: Get an attribute from a target's label.\n"
"\n"
" get_label_info(target_label, what)\n"
"\n"
" Given the label of a target, returns some attribute of that target.\n"
" The target need not have been previously defined in the same file,\n"
" since none of the attributes depend on the actual target definition,\n"
" only the label itself.\n"
"\n"
" See also \"gn help get_target_outputs\".\n"
"\n"
"Possible values for the \"what\" parameter\n"
"\n"
" \"name\"\n"
" The short name of the target. This will match the value of the\n"
" \"target_name\" variable inside that target's declaration. For the\n"
" label \"//foo/bar:baz\" this will return \"baz\".\n"
"\n"
" \"dir\"\n"
" The directory containing the target's definition, with no slash at\n"
" the end. For the label \"//foo/bar:baz\" this will return\n"
" \"//foo/bar\".\n"
"\n"
" \"target_gen_dir\"\n"
" The generated file directory for the target. This will match the\n"
" value of the \"target_gen_dir\" variable when inside that target's\n"
" declaration.\n"
"\n"
" \"root_gen_dir\"\n"
" The root of the generated file tree for the target. This will\n"
" match the value of the \"root_gen_dir\" variable when inside that\n"
" target's declaration.\n"
"\n"
" \"target_out_dir\n"
" The output directory for the target. This will match the\n"
" value of the \"target_out_dir\" variable when inside that target's\n"
" declaration.\n"
"\n"
" \"root_out_dir\"\n"
" The root of the output file tree for the target. This will\n"
" match the value of the \"root_gen_dir\" variable when inside that\n"
" target's declaration.\n"
"\n"
" \"label_no_toolchain\"\n"
" The fully qualified version of this label, not including the\n"
" toolchain. For the input \":bar\" it might return\n"
" \"//foo:bar\".\n"
"\n"
" \"label_with_toolchain\"\n"
" The fully qualified version of this label, including the\n"
" toolchain. For the input \":bar\" it might return\n"
" \"//foo:bar(//toolchain:x64)\".\n"
"\n"
" \"toolchain\"\n"
" The label of the toolchain. This will match the value of the\n"
" \"current_toolchain\" variable when inside that target's\n"
" declaration.\n"
"\n"
"Examples\n"
"\n"
" get_label_info(\":foo\", \"name\")\n"
" # Returns string \"foo\".\n"
"\n"
" get_label_info(\"//foo/bar:baz\", \"gen_dir\")\n"
" # Returns string \"//out/Debug/gen/foo/bar\".\n";
Value RunGetLabelInfo(Scope* scope,
const FunctionCallNode* function,
const std::vector<Value>& args,
Err* err) {
if (args.size() != 2) {
*err = Err(function, "Expected two arguments.");
return Value();
}
// Resolve the requested label.
Label label = Label::Resolve(scope->GetSourceDir(),
ToolchainLabelForScope(scope), args[0], err);
if (label.is_null())
return Value();
// Extract the "what" parameter.
if (!args[1].VerifyTypeIs(Value::STRING, err))
return Value();
const std::string& what = args[1].string_value();
Value result(function, Value::STRING);
if (what == "name") {
result.string_value() = label.name();
} else if (what == "dir") {
result.string_value() = DirectoryWithNoLastSlash(label.dir());
} else if (what == "target_gen_dir") {
result.string_value() = DirectoryWithNoLastSlash(
GetGenDirForSourceDir(scope->settings(), label.dir()));
} else if (what == "root_gen_dir") {
Label toolchain_label = label.GetToolchainLabel();
bool is_default =
scope->settings()->default_toolchain_label() == toolchain_label;
result.string_value() = DirectoryWithNoLastSlash(
GetToolchainGenDir(scope->settings()->build_settings(),
toolchain_label, is_default));
} else if (what == "target_out_dir") {
result.string_value() = DirectoryWithNoLastSlash(
GetOutputDirForSourceDir(scope->settings(), label.dir()));
} else if (what == "root_out_dir") {
Label toolchain_label = label.GetToolchainLabel();
bool is_default =
scope->settings()->default_toolchain_label() == toolchain_label;
result.string_value() = DirectoryWithNoLastSlash(
GetToolchainOutputDir(scope->settings()->build_settings(),
toolchain_label, is_default));
} else if (what == "toolchain") {
result.string_value() = label.GetToolchainLabel().GetUserVisibleName(false);
} else if (what == "label_no_toolchain") {
result.string_value() =
label.GetWithNoToolchain().GetUserVisibleName(false);
} else if (what == "label_with_toolchain") {
result.string_value() = label.GetUserVisibleName(true);
} else {
*err = Err(args[1], "Unknown value for \"what\" parameter.");
return Value();
}
return result;
}
} // namespace functions
// Copyright 2014 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 "testing/gtest/include/gtest/gtest.h"
#include "tools/gn/functions.h"
#include "tools/gn/test_with_scope.h"
namespace {
class GetLabelInfoTest : public testing::Test {
public:
GetLabelInfoTest() : testing::Test() {
setup_.scope()->set_source_dir(SourceDir("//src/foo/"));
}
// Convenience wrapper to call GetLabelInfo.
std::string Call(const std::string& label, const std::string& what) {
FunctionCallNode function;
std::vector<Value> args;
args.push_back(Value(NULL, label));
args.push_back(Value(NULL, what));
Err err;
Value result = functions::RunGetLabelInfo(setup_.scope(), &function,
args, &err);
if (err.has_error()) {
EXPECT_TRUE(result.type() == Value::NONE);
return std::string();
}
return result.string_value();
}
protected:
// Note: TestWithScope's default toolchain is "//toolchain:default" and
// output dir is "//out/Debug".
TestWithScope setup_;
};
} // namespace
TEST_F(GetLabelInfoTest, BadInput) {
EXPECT_EQ("", Call(":name", "incorrect_value"));
EXPECT_EQ("", Call("", "name"));
}
TEST_F(GetLabelInfoTest, Name) {
EXPECT_EQ("name", Call(":name", "name"));
EXPECT_EQ("name", Call("//foo/bar:name", "name"));
}
TEST_F(GetLabelInfoTest, Dir) {
EXPECT_EQ("//src/foo", Call(":name", "dir"));
EXPECT_EQ("//foo/bar", Call("//foo/bar:baz", "dir"));
}
TEST_F(GetLabelInfoTest, RootOutDir) {
EXPECT_EQ("//out/Debug", Call(":name", "root_out_dir"));
EXPECT_EQ("//out/Debug/random",
Call(":name(//toolchain:random)", "root_out_dir"));
}
TEST_F(GetLabelInfoTest, RootGetDir) {
EXPECT_EQ("//out/Debug/gen", Call(":name", "root_gen_dir"));
EXPECT_EQ("//out/Debug/random/gen",
Call(":name(//toolchain:random)", "root_gen_dir"));
}
TEST_F(GetLabelInfoTest, TargetOutDir) {
EXPECT_EQ("//out/Debug/obj/src/foo", Call(":name", "target_out_dir"));
EXPECT_EQ("//out/Debug", Call(":name", "root_out_dir"));
}
TEST_F(GetLabelInfoTest, LabelNoToolchain) {
EXPECT_EQ("//src/foo:name", Call(":name", "label_no_toolchain"));
EXPECT_EQ("//src/foo:name",
Call("//src/foo:name(//toolchain:random)", "label_no_toolchain"));
}
TEST_F(GetLabelInfoTest, LabelWithToolchain) {
EXPECT_EQ("//src/foo:name(//toolchain:default)",
Call(":name", "label_with_toolchain"));
EXPECT_EQ("//src/foo:name(//toolchain:random)",
Call(":name(//toolchain:random)", "label_with_toolchain"));
}
TEST_F(GetLabelInfoTest, Toolchain) {
EXPECT_EQ("//toolchain:default", Call(":name", "toolchain"));
EXPECT_EQ("//toolchain:random",
Call(":name(//toolchain:random)", "toolchain"));
}
......@@ -652,6 +652,7 @@ struct FunctionInfoInitializer {
INSERT_FUNCTION(Defined, false)
INSERT_FUNCTION(ExecScript, false)
INSERT_FUNCTION(GetEnv, false)
INSERT_FUNCTION(GetLabelInfo, false)
INSERT_FUNCTION(GetTargetOutputs, false)
INSERT_FUNCTION(Import, false)
INSERT_FUNCTION(Print, false)
......
......@@ -147,6 +147,14 @@ Value RunGetEnv(Scope* scope,
const std::vector<Value>& args,
Err* err);
extern const char kGetLabelInfo[];
extern const char kGetLabelInfo_HelpShort[];
extern const char kGetLabelInfo_Help[];
Value RunGetLabelInfo(Scope* scope,
const FunctionCallNode* function,
const std::vector<Value>& args,
Err* err);
extern const char kGetTargetOutputs[];
extern const char kGetTargetOutputs_HelpShort[];
extern const char kGetTargetOutputs_Help[];
......
......@@ -56,6 +56,7 @@
'functions.cc',
'functions.h',
'function_exec_script.cc',
'function_get_label_info.cc',
'function_get_target_outputs.cc',
'function_process_file_template.cc',
'function_read_file.cc',
......@@ -179,6 +180,7 @@
'escape_unittest.cc',
'filesystem_utils_unittest.cc',
'file_template_unittest.cc',
'function_get_label_info_unittest.cc',
'function_get_target_outputs_unittest.cc',
'function_rebase_path_unittest.cc',
'functions_unittest.cc',
......
......@@ -19,20 +19,6 @@
#include "tools/gn/source_file.h"
#include "tools/gn/trace.h"
namespace {
std::string GetOutputSubdirName(const Label& toolchain_label, bool is_default) {
// The default toolchain has no subdir.
if (is_default)
return std::string();
// For now just assume the toolchain name is always a valid dir name. We may
// want to clean up the in the future.
return toolchain_label.name();
}
} // namespace
// Identifies one time a file is loaded in a given toolchain so we don't load
// it more than once.
struct LoaderImpl::LoadID {
......
......@@ -35,7 +35,7 @@ TEST(ScopePerFileProvider, Expected) {
// Test some with an alternate toolchain.
{
Settings settings(test.build_settings(), "tc");
Settings settings(test.build_settings(), "tc/");
Toolchain toolchain(&settings, Label(SourceDir("//toolchain/"), "tc"));
settings.set_toolchain_label(toolchain.label());
......
......@@ -14,13 +14,12 @@ Settings::Settings(const BuildSettings* build_settings,
import_manager_(),
base_config_(this),
greedy_target_generation_(false) {
DCHECK(output_subdir_name.find('/') == std::string::npos);
if (output_subdir_name.empty()) {
toolchain_output_dir_ = build_settings->build_dir();
} else {
// We guarantee this ends in a slash.
DCHECK(output_subdir_name[output_subdir_name.size() - 1] == '/');
toolchain_output_subdir_.value().append(output_subdir_name);
toolchain_output_subdir_.value().push_back('/');
DCHECK(!build_settings->build_dir().is_null());
toolchain_output_dir_ = SourceDir(build_settings->build_dir().value() +
......
......@@ -33,10 +33,12 @@ class Settings {
WIN
};
// Constructs a toolchain settings. The output_subdir_name is the name we
// should use for the subdirectory in the build output directory for this
// toolchain's outputs. It should have no slashes in it. The default
// toolchain should use an empty string.
// Constructs a toolchain settings.
//
// The output_subdir_name is the name we should use for the subdirectory in
// the build output directory for this toolchain's outputs. The default
// toolchain would use an empty string (it goes in the root build dir).
// Otherwise, it must end in a slash.
Settings(const BuildSettings* build_settings,
const std::string& output_subdir_name);
~Settings();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment