[metadata] Adding metadata variable to target
This adds the `metadata` variable to targets.
Change-Id: Iddb8adada4323f6e44011bc315fa20674dcbcaff
Reviewed-on: https://gn-review.googlesource.com/c/3300
Commit-Queue: Julie Hockett <juliehockett@google.com>
Reviewed-by: Brett Wilson <brettw@chromium.org>
diff --git a/build/gen.py b/build/gen.py
index 56a6566..e32a609 100755
--- a/build/gen.py
+++ b/build/gen.py
@@ -568,6 +568,7 @@
'tools/gn/label_pattern_unittest.cc',
'tools/gn/label_unittest.cc',
'tools/gn/loader_unittest.cc',
+ 'tools/gn/metadata_unittest.cc',
'tools/gn/ninja_action_target_writer_unittest.cc',
'tools/gn/ninja_binary_target_writer_unittest.cc',
'tools/gn/ninja_build_writer_unittest.cc',
diff --git a/tools/gn/functions_target.cc b/tools/gn/functions_target.cc
index 2339e17..008b47e 100644
--- a/tools/gn/functions_target.cc
+++ b/tools/gn/functions_target.cc
@@ -16,9 +16,10 @@
#define DEPENDENT_CONFIG_VARS \
" Dependent configs: all_dependent_configs, public_configs\n"
#define DEPS_VARS " Deps: data_deps, deps, public_deps\n"
-#define GENERAL_TARGET_VARS \
- " General: check_includes, configs, data, friend, inputs, output_name,\n" \
- " output_extension, public, sources, testonly, visibility\n"
+#define GENERAL_TARGET_VARS \
+ " General: check_includes, configs, data, friend, inputs, metadata,\n" \
+ " output_name, output_extension, public, sources, testonly,\n" \
+ " visibility\n"
namespace functions {
@@ -138,7 +139,7 @@
R"(
Variables
- args, data, data_deps, depfile, deps, inputs, outputs*, pool,
+ args, data, data_deps, depfile, deps, inputs, metadata, outputs*, pool,
response_file_contents, script*, sources
* = required
@@ -208,7 +209,7 @@
R"(
Variables
- args, data, data_deps, depfile, deps, inputs, outputs*, pool,
+ args, data, data_deps, depfile, deps, inputs, metadata, outputs*, pool,
response_file_contents, script*, sources*
* = required
@@ -272,7 +273,7 @@
Variables
- sources*, outputs*, deps, data_deps, public_deps, visibility
+ sources*, outputs*, deps, data_deps, metadata, public_deps, visibility
* = required
Examples
@@ -361,7 +362,8 @@
bundle_executable_dir*, bundle_plugins_dir*, bundle_deps_filter, deps,
data_deps, public_deps, visibility, product_type, code_signing_args,
code_signing_script, code_signing_sources, code_signing_outputs,
- xcode_extra_attributes, xcode_test_application_name, partial_info_plist
+ xcode_extra_attributes, xcode_test_application_name, partial_info_plist,
+ metadata
* = required
Example
diff --git a/tools/gn/metadata.h b/tools/gn/metadata.h
new file mode 100644
index 0000000..fe66ff6
--- /dev/null
+++ b/tools/gn/metadata.h
@@ -0,0 +1,55 @@
+// Copyright 2018 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.
+
+#ifndef TOOLS_GN_METADATA_H_
+#define TOOLS_GN_METADATA_H_
+
+#include <memory>
+
+#include "tools/gn/scope.h"
+#include "tools/gn/source_dir.h"
+
+// Metadata about a particular target.
+//
+// Metadata is a collection of keys and values relating to a particular target.
+// Generally, these keys will include three categories of strings: ordinary
+// strings, filenames intended to be rebased according to their particular
+// source directory, and target labels intended to be used as barriers to the
+// walk. Verfication of these categories occurs at walk time, not creation
+// time (since it is not clear until the walk which values are intended for
+// which purpose).
+//
+// Represented as a scope in the expression language, here it is reduced to just
+// the KeyValueMap (since it doesn't need the logical overhead of a full scope).
+// Values must be lists of strings, as the walking collection logic contatenates
+// their values across targets.
+class Metadata {
+ public:
+ using Contents = Scope::KeyValueMap;
+
+ // Members must be set explicitly.
+ Metadata() = default;
+
+ const ParseNode* origin() const { return origin_; }
+ void set_origin(const ParseNode* origin) { origin_ = origin; }
+
+ // The contents of this metadata varaiable.
+ const Contents& contents() const { return contents_; }
+ Contents& contents() { return contents_; }
+ void set_contents(Contents&& contents) { contents_.swap(contents); }
+
+ // The relative source directory to use when rebasing.
+ const SourceDir& source_dir() const { return source_dir_; }
+ SourceDir& source_dir() { return source_dir_; }
+ void set_source_dir(const SourceDir& d) { source_dir_ = d; }
+
+ private:
+ const ParseNode* origin_;
+ Contents contents_;
+ SourceDir source_dir_;
+
+ DISALLOW_COPY_AND_ASSIGN(Metadata);
+};
+
+#endif // TOOLS_GN_METADATA_H_
diff --git a/tools/gn/metadata_unittest.cc b/tools/gn/metadata_unittest.cc
new file mode 100644
index 0000000..cb94911
--- /dev/null
+++ b/tools/gn/metadata_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright 2018 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/metadata.h"
+#include "tools/gn/test_with_scope.h"
+#include "util/test/test.h"
+
+TEST(MetadataTest, SetContents) {
+ Metadata metadata;
+
+ ASSERT_TRUE(metadata.contents().empty());
+
+ Value a_expected(nullptr, Value::LIST);
+ a_expected.list_value().push_back(Value(nullptr, "foo"));
+ Value b_expected(nullptr, Value::LIST);
+ b_expected.list_value().push_back(Value(nullptr, true));
+
+ Metadata::Contents contents;
+ contents.insert(std::pair<base::StringPiece, Value>("a", a_expected));
+ contents.insert(std::pair<base::StringPiece, Value>("b", b_expected));
+
+ metadata.set_contents(std::move(contents));
+
+ ASSERT_EQ(metadata.contents().size(), 2);
+ auto a_actual = metadata.contents().find("a");
+ auto b_actual = metadata.contents().find("b");
+ ASSERT_FALSE(a_actual == metadata.contents().end());
+ ASSERT_FALSE(b_actual == metadata.contents().end());
+ ASSERT_EQ(a_actual->second, a_expected);
+ ASSERT_EQ(b_actual->second, b_expected);
+}
diff --git a/tools/gn/target.h b/tools/gn/target.h
index 8754b61..5421cca 100644
--- a/tools/gn/target.h
+++ b/tools/gn/target.h
@@ -20,6 +20,7 @@
#include "tools/gn/label_pattern.h"
#include "tools/gn/label_ptr.h"
#include "tools/gn/lib_file.h"
+#include "tools/gn/metadata.h"
#include "tools/gn/ordered_set.h"
#include "tools/gn/output_file.h"
#include "tools/gn/source_file.h"
@@ -144,6 +145,10 @@
complete_static_lib_ = complete;
}
+ // Metadata. Target takes ownership of the resulting scope.
+ const Metadata& metadata() const { return metadata_; }
+ Metadata& metadata() { return metadata_; }
+
bool testonly() const { return testonly_; }
void set_testonly(bool value) { testonly_ = value; }
@@ -388,6 +393,8 @@
OutputFile dependency_output_file_;
std::vector<OutputFile> runtime_outputs_;
+ Metadata metadata_;
+
DISALLOW_COPY_AND_ASSIGN(Target);
};
diff --git a/tools/gn/target_generator.cc b/tools/gn/target_generator.cc
index 4bc693c..c7a9f08 100644
--- a/tools/gn/target_generator.cc
+++ b/tools/gn/target_generator.cc
@@ -20,6 +20,7 @@
#include "tools/gn/filesystem_utils.h"
#include "tools/gn/functions.h"
#include "tools/gn/group_target_generator.h"
+#include "tools/gn/metadata.h"
#include "tools/gn/parse_tree.h"
#include "tools/gn/scheduler.h"
#include "tools/gn/scope.h"
@@ -50,6 +51,9 @@
if (!FillDependencies())
return;
+ if (!FillMetadata())
+ return;
+
if (!FillTestonly())
return;
@@ -254,6 +258,36 @@
return true;
}
+bool TargetGenerator::FillMetadata() {
+ // Need to get a mutable value to mark all values in the scope as used. This
+ // cannot be done on a const Scope.
+ Value* value = scope_->GetMutableValue(variables::kMetadata,
+ Scope::SEARCH_CURRENT, true);
+
+ if (!value)
+ return true;
+
+ if (!value->VerifyTypeIs(Value::SCOPE, err_))
+ return false;
+
+ Scope* scope_value = value->scope_value();
+
+ scope_value->GetCurrentScopeValues(&target_->metadata().contents());
+ scope_value->MarkAllUsed();
+
+ // Metadata values should always hold lists of Values, such that they can be
+ // collected and concatenated. Any additional specific type verification is
+ // done at walk time.
+ for (const auto& iter : target_->metadata().contents()) {
+ if (!iter.second.VerifyTypeIs(Value::LIST, err_))
+ return false;
+ }
+
+ target_->metadata().set_source_dir(scope_->GetSourceDir());
+ target_->metadata().set_origin(value->origin());
+ return true;
+}
+
bool TargetGenerator::FillTestonly() {
const Value* value = scope_->GetValue(variables::kTestonly, true);
if (value) {
diff --git a/tools/gn/target_generator.h b/tools/gn/target_generator.h
index 549f2cd..627505d 100644
--- a/tools/gn/target_generator.h
+++ b/tools/gn/target_generator.h
@@ -68,6 +68,7 @@
bool FillDependentConfigs(); // Includes all types of dependent configs.
bool FillData();
bool FillDependencies(); // Includes data dependencies.
+ bool FillMetadata();
bool FillTestonly();
bool FillAssertNoDeps();
bool FillWriteRuntimeDeps();
diff --git a/tools/gn/variables.cc b/tools/gn/variables.cc
index a405d9d..16de86f 100644
--- a/tools/gn/variables.cc
+++ b/tools/gn/variables.cc
@@ -1337,6 +1337,31 @@
libs = [ "ld" ]
)";
+const char kMetadata[] = "metadata";
+const char kMetadata_HelpShort[] = "metadata: [scope] Metadata of this target.";
+const char kMetadata_Help[] =
+ R"(metadata: Metadata of this target.
+
+ Metadata is a collection of keys and values relating to a particular target.
+ Generally, these keys will include three categories of strings: ordinary
+ strings, filenames intended to be rebased according to their particular
+ source directory, and target labels intended to be used as barriers to the
+ walk. Verfication of these categories occurs at walk time, not creation
+ time (since it is not clear until the walk which values are intended for
+ which purpose).
+
+ Example
+
+ group("doom_melon") {
+ metadata = {
+ # These keys are not built in to GN but are interpreted when consuming
+ # metadata.
+ my_barrier = []
+ my_files = [ "a.txt", "b.txt" ]
+ }
+ }
+)";
+
const char kOutputExtension[] = "output_extension";
const char kOutputExtension_HelpShort[] =
"output_extension: [string] Value to use for the output's file extension.";
@@ -2092,6 +2117,7 @@
INSERT_VARIABLE(Ldflags)
INSERT_VARIABLE(Libs)
INSERT_VARIABLE(LibDirs)
+ INSERT_VARIABLE(Metadata)
INSERT_VARIABLE(OutputDir)
INSERT_VARIABLE(OutputExtension)
INSERT_VARIABLE(OutputName)
diff --git a/tools/gn/variables.h b/tools/gn/variables.h
index 080989b..a90cb00 100644
--- a/tools/gn/variables.h
+++ b/tools/gn/variables.h
@@ -219,6 +219,10 @@
extern const char kLibs_HelpShort[];
extern const char kLibs_Help[];
+extern const char kMetadata[];
+extern const char kMetadata_HelpShort[];
+extern const char kMetadata_Help[];
+
extern const char kOutputDir[];
extern const char kOutputDir_HelpShort[];
extern const char kOutputDir_Help[];