mirror of
https://gitlab.alpinelinux.org/alpine/aports.git
synced 2026-05-13 08:36:23 +02:00
community/gn: backport changes needed for chromium M148
This commit is contained in:
parent
b27ea208cc
commit
2a2787f018
697
community/gn/0001-Add-function-expand_directory-to-gn.patch
Normal file
697
community/gn/0001-Add-function-expand_directory-to-gn.patch
Normal file
@ -0,0 +1,697 @@
|
||||
From 42ace47bb426ca9705175d866bb9bdf168d5535f Mon Sep 17 00:00:00 2001
|
||||
From: Matt Stark <msta@google.com>
|
||||
Date: Mon, 13 Apr 2026 11:10:13 +1000
|
||||
Subject: [PATCH] Add function `expand_directory` to gn.
|
||||
|
||||
This function expands a directory to a list of files.
|
||||
This will allow us to do a variety of things, such as:
|
||||
* Removing our `generate_libcxx_headers` script
|
||||
* Ensuring that our whole sysroot is in the inputs to a rule.
|
||||
|
||||
This is required because the contents of a sysroot are not able to be
|
||||
stored in the chrome source code because chromeos sysroots can be paths
|
||||
pointing to the chromeos checkout rather than the chrome checkout.
|
||||
|
||||
It also allows us to significantly improve the quality of our third
|
||||
party libraries, for which we would, after this change, no longer have
|
||||
to keep the source file list in sync, but instead simply use those third
|
||||
party libraries as the source of truth.
|
||||
|
||||
Bug: b:491242305
|
||||
Change-Id: Ib52107b2f877021d3e59c54c9a554fac6a6a6964
|
||||
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/21860
|
||||
Reviewed-by: Takuto Ikuta <tikuta@google.com>
|
||||
Commit-Queue: Matt Stark <msta@google.com>
|
||||
---
|
||||
build/gen.py | 2 +
|
||||
docs/reference.md | 35 ++++
|
||||
src/gn/build_settings.h | 11 ++
|
||||
src/gn/function_exec_script.cc | 14 +-
|
||||
src/gn/function_expand_directory.cc | 165 ++++++++++++++++++
|
||||
src/gn/function_expand_directory_unittest.cc | 168 +++++++++++++++++++
|
||||
src/gn/functions.cc | 1 +
|
||||
src/gn/functions.h | 8 +
|
||||
src/gn/setup.cc | 69 ++++++--
|
||||
src/gn/source_file.cc | 13 ++
|
||||
src/gn/source_file.h | 3 +
|
||||
11 files changed, 464 insertions(+), 25 deletions(-)
|
||||
create mode 100644 src/gn/function_expand_directory.cc
|
||||
create mode 100644 src/gn/function_expand_directory_unittest.cc
|
||||
|
||||
diff --git a/build/gen.py b/build/gen.py
|
||||
index e40627c8..2a7e7318 100755
|
||||
--- a/build/gen.py
|
||||
+++ b/build/gen.py
|
||||
@@ -698,6 +698,7 @@ def WriteGNNinja(path, platform, host, options, args_list):
|
||||
'src/gn/file_writer.cc',
|
||||
'src/gn/frameworks_utils.cc',
|
||||
'src/gn/function_exec_script.cc',
|
||||
+ 'src/gn/function_expand_directory.cc',
|
||||
'src/gn/function_filter.cc',
|
||||
'src/gn/function_filter_labels.cc',
|
||||
'src/gn/function_foreach.cc',
|
||||
@@ -842,6 +843,7 @@ def WriteGNNinja(path, platform, host, options, args_list):
|
||||
'src/gn/filesystem_utils_unittest.cc',
|
||||
'src/gn/file_writer_unittest.cc',
|
||||
'src/gn/frameworks_utils_unittest.cc',
|
||||
+ 'src/gn/function_expand_directory_unittest.cc',
|
||||
'src/gn/function_filter_unittest.cc',
|
||||
'src/gn/function_filter_labels_unittest.cc',
|
||||
'src/gn/function_foreach_unittest.cc',
|
||||
diff --git a/docs/reference.md b/docs/reference.md
|
||||
index 05329606..27d5af0f 100644
|
||||
--- a/docs/reference.md
|
||||
+++ b/docs/reference.md
|
||||
@@ -41,6 +41,7 @@
|
||||
* [declare_args: Declare build arguments.](#func_declare_args)
|
||||
* [defined: Returns whether an identifier is defined.](#func_defined)
|
||||
* [exec_script: Synchronously run a script and return the output.](#func_exec_script)
|
||||
+ * [expand_directory: Expand a source directory and return files.](#func_expand_directory)
|
||||
* [filter_exclude: Remove values that match a set of patterns.](#func_filter_exclude)
|
||||
* [filter_include: Remove values that do not match a set of patterns.](#func_filter_include)
|
||||
* [filter_labels_exclude: Remove labels that match a set of patterns.](#func_filter_labels_exclude)
|
||||
@@ -2611,6 +2612,25 @@
|
||||
# result.
|
||||
exec_script("//foo/bar/myscript.py")
|
||||
```
|
||||
+### <a name="func_expand_directory"></a>**expand_directory**: Expand a source directory and return files. [Back to Top](#gn-reference)
|
||||
+
|
||||
+```
|
||||
+ expand_directory(directory, recursive)
|
||||
+
|
||||
+ Returns a list of all files contained within the specified directory.
|
||||
+
|
||||
+ Arguments:
|
||||
+ directory: A string representing the directory to search, relative to
|
||||
+ the current BUILD file or source-absolute (starting with "//").
|
||||
+ recursive: A boolean indicating whether to search recursively.
|
||||
+
|
||||
+ Returns:
|
||||
+ A list of source-absolute paths representing the files found, sorted
|
||||
+ alphabetically.
|
||||
+
|
||||
+ Example:
|
||||
+ files = expand_directory("src/data", true)
|
||||
+```
|
||||
### <a name="func_filter_exclude"></a>**filter_exclude**: Remove values that match a set of patterns. [Back to Top](#gn-reference)
|
||||
|
||||
```
|
||||
@@ -7358,6 +7378,21 @@
|
||||
If both values are set, only the value in "exec_script_allowlist" will
|
||||
have any effect (so don't set both!).
|
||||
|
||||
+ expand_directory_allowlist [optional]
|
||||
+ A list of .gn/.gni files (not labels) that have permission to call the
|
||||
+ expand_directory function. If this list is defined, calls to
|
||||
+ expand_directory will be checked against this list and GN will fail if
|
||||
+ the current file isn't in the list.
|
||||
+
|
||||
+ The use of expand_directory is restricted because it encourages
|
||||
+ monolithic build targets with redundant inputs, which can slow down
|
||||
+ the build.
|
||||
+
|
||||
+ Example:
|
||||
+ expand_directory_allowlist = [
|
||||
+ "//base/BUILD.gn",
|
||||
+ ]
|
||||
+
|
||||
export_compile_commands [optional]
|
||||
A list of label patterns for which to generate a Clang compilation
|
||||
database (see "gn help label_pattern" for the string format).
|
||||
diff --git a/src/gn/build_settings.h b/src/gn/build_settings.h
|
||||
index 6c482845..0d4decb5 100644
|
||||
--- a/src/gn/build_settings.h
|
||||
+++ b/src/gn/build_settings.h
|
||||
@@ -144,6 +144,15 @@ class BuildSettings {
|
||||
exec_script_allowlist_ = std::move(list);
|
||||
}
|
||||
|
||||
+ // A list of files that can call expand_directory(). If the returned pointer
|
||||
+ // is null, expand_directory may be called from anywhere.
|
||||
+ const SourceFileSet* expand_directory_allowlist() const {
|
||||
+ return expand_directory_allowlist_.get();
|
||||
+ }
|
||||
+ void set_expand_directory_allowlist(std::unique_ptr<SourceFileSet> list) {
|
||||
+ expand_directory_allowlist_ = std::move(list);
|
||||
+ }
|
||||
+
|
||||
private:
|
||||
Label root_target_label_;
|
||||
std::vector<LabelPattern> root_patterns_;
|
||||
@@ -167,6 +176,8 @@ class BuildSettings {
|
||||
PrintCallback print_callback_;
|
||||
|
||||
std::unique_ptr<SourceFileSet> exec_script_allowlist_;
|
||||
+ std::unique_ptr<SourceFileSet> expand_directory_allowlist_ =
|
||||
+ std::make_unique<SourceFileSet>();
|
||||
|
||||
BuildSettings& operator=(const BuildSettings&) = delete;
|
||||
};
|
||||
diff --git a/src/gn/function_exec_script.cc b/src/gn/function_exec_script.cc
|
||||
index 01cdb661..966dbfcf 100644
|
||||
--- a/src/gn/function_exec_script.cc
|
||||
+++ b/src/gn/function_exec_script.cc
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "gn/input_file.h"
|
||||
#include "gn/parse_tree.h"
|
||||
#include "gn/scheduler.h"
|
||||
+#include "gn/source_file.h"
|
||||
#include "gn/trace.h"
|
||||
#include "gn/value.h"
|
||||
#include "util/build_config.h"
|
||||
@@ -27,17 +28,8 @@ namespace {
|
||||
bool CheckExecScriptPermissions(const BuildSettings* build_settings,
|
||||
const FunctionCallNode* function,
|
||||
Err* err) {
|
||||
- const SourceFileSet* allowlist = build_settings->exec_script_allowlist();
|
||||
- if (!allowlist)
|
||||
- return true; // No allowlist specified, don't check.
|
||||
-
|
||||
- LocationRange function_range = function->GetRange();
|
||||
- if (!function_range.begin().file())
|
||||
- return true; // No file, might be some internal thing, implicitly pass.
|
||||
-
|
||||
- if (allowlist->find(function_range.begin().file()->name()) !=
|
||||
- allowlist->end())
|
||||
- return true; // allowlisted, this is OK.
|
||||
+ if (InSourceAllowList(function, build_settings->exec_script_allowlist()))
|
||||
+ return true;
|
||||
|
||||
// Disallowed case.
|
||||
*err = Err(
|
||||
diff --git a/src/gn/function_expand_directory.cc b/src/gn/function_expand_directory.cc
|
||||
new file mode 100644
|
||||
index 00000000..4005098a
|
||||
--- /dev/null
|
||||
+++ b/src/gn/function_expand_directory.cc
|
||||
@@ -0,0 +1,165 @@
|
||||
+// Copyright 2026 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 <algorithm>
|
||||
+#include <map>
|
||||
+#include <mutex>
|
||||
+#include <string>
|
||||
+#include <string_view>
|
||||
+#include <utility>
|
||||
+#include <vector>
|
||||
+
|
||||
+#include "base/files/file_enumerator.h"
|
||||
+#include "base/files/file_util.h"
|
||||
+#include "base/strings/stringprintf.h"
|
||||
+#include "gn/err.h"
|
||||
+#include "gn/filesystem_utils.h"
|
||||
+#include "gn/functions.h"
|
||||
+#include "gn/scheduler.h"
|
||||
+#include "gn/scope.h"
|
||||
+#include "gn/value.h"
|
||||
+
|
||||
+namespace functions {
|
||||
+
|
||||
+const char kExpandDirectory[] = "expand_directory";
|
||||
+const char kExpandDirectory_HelpShort[] =
|
||||
+ "expand_directory: Expand a source directory and return files.";
|
||||
+const char kExpandDirectory_Help[] =
|
||||
+ R"(expand_directory: Expand a source directory and return files.
|
||||
+
|
||||
+ expand_directory(directory, recursive)
|
||||
+
|
||||
+ Returns a list of all files contained within the specified directory.
|
||||
+
|
||||
+ Arguments:
|
||||
+ directory: A string representing the directory to search, relative to
|
||||
+ the current BUILD file or source-absolute (starting with "//").
|
||||
+ recursive: A boolean indicating whether to search recursively.
|
||||
+
|
||||
+ Returns:
|
||||
+ A list of source-absolute paths representing the files found, sorted
|
||||
+ alphabetically.
|
||||
+
|
||||
+ Example:
|
||||
+ files = expand_directory("src/data", true)
|
||||
+)";
|
||||
+
|
||||
+namespace {
|
||||
+
|
||||
+Value ExpandDirectoryInternal(const ParseNode* function,
|
||||
+ SourceDir source_path,
|
||||
+ const base::FilePath& disk_path,
|
||||
+ bool recursive) {
|
||||
+ auto add_gen_dep = [&](const base::FilePath& path) {
|
||||
+ g_scheduler->AddGenDependency(
|
||||
+ path.StripTrailingSeparators().NormalizePathSeparatorsTo(
|
||||
+ base::FilePath::kSeparators[0]));
|
||||
+ };
|
||||
+
|
||||
+ add_gen_dep(disk_path);
|
||||
+
|
||||
+ std::string disk_path_utf8 = FilePathToUTF8(disk_path);
|
||||
+ Value files(function, Value::LIST);
|
||||
+
|
||||
+ base::FileEnumerator traverser(
|
||||
+ disk_path, recursive,
|
||||
+ base::FileEnumerator::FILES |
|
||||
+ (recursive ? base::FileEnumerator::DIRECTORIES : 0));
|
||||
+ for (base::FilePath current = traverser.Next(); !current.empty();
|
||||
+ current = traverser.Next()) {
|
||||
+ if (traverser.GetInfo().IsDirectory()) {
|
||||
+ add_gen_dep(current);
|
||||
+ } else {
|
||||
+ std::string full = source_path.value() +
|
||||
+ FilePathToUTF8(current).substr(disk_path_utf8.size());
|
||||
+ NormalizePath(&full);
|
||||
+ files.list_value().emplace_back(function, full);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ std::ranges::sort(files.list_value(), [](const auto& lhs, const auto& rhs) {
|
||||
+ return lhs.string_value() < rhs.string_value();
|
||||
+ });
|
||||
+
|
||||
+ return files;
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
+Value RunExpandDirectory(Scope* scope,
|
||||
+ const FunctionCallNode* function,
|
||||
+ const std::vector<Value>& args,
|
||||
+ Err* err) {
|
||||
+ if (args.size() != 2) {
|
||||
+ *err = Err(function, "Wrong number of arguments.",
|
||||
+ "expand_directory() takes exactly two arguments");
|
||||
+ return Value();
|
||||
+ }
|
||||
+
|
||||
+ if (!InSourceAllowList(
|
||||
+ function,
|
||||
+ scope->settings()->build_settings()->expand_directory_allowlist())) {
|
||||
+ *err = Err(
|
||||
+ function, "Disallowed expand_directory call.",
|
||||
+ "The use of expand_directory is restricted in this build.\n"
|
||||
+ "expand_directory is discouraged because it encourages monolithic \n"
|
||||
+ "build targets with redundant inputs, slowing down the build.\n"
|
||||
+ "\n"
|
||||
+ "The allowed callers of expand_directory is maintained in the "
|
||||
+ "\"//.gn\" file\n"
|
||||
+ "if you need to modify the allowlist.");
|
||||
+ return Value();
|
||||
+ }
|
||||
+
|
||||
+ if (!args[0].VerifyTypeIs(Value::STRING, err) ||
|
||||
+ !args[1].VerifyTypeIs(Value::BOOLEAN, err)) {
|
||||
+ return Value();
|
||||
+ }
|
||||
+
|
||||
+ std::string root_path = scope->settings()->build_settings()->root_path_utf8();
|
||||
+ SourceDir dir =
|
||||
+ scope->GetSourceDir().ResolveRelativeDir(args[0], err, root_path);
|
||||
+ if (err->has_error())
|
||||
+ return Value();
|
||||
+
|
||||
+ bool recursive = args[1].boolean_value();
|
||||
+
|
||||
+ base::FilePath dir_path =
|
||||
+ scope->settings()->build_settings()->GetFullPath(dir);
|
||||
+
|
||||
+ if (!base::DirectoryExists(dir_path)) {
|
||||
+ *err =
|
||||
+ Err(function, "Directory does not exist: " + FilePathToUTF8(dir_path));
|
||||
+ return Value();
|
||||
+ }
|
||||
+
|
||||
+ // This is highly likely to be called once per toolchain per directory.
|
||||
+ // Since this involves a file system scan, it's worth caching.
|
||||
+ struct CacheEntry {
|
||||
+ std::mutex mutex;
|
||||
+ Value result;
|
||||
+ };
|
||||
+
|
||||
+ static std::map<std::pair<base::FilePath, bool>, CacheEntry> cache;
|
||||
+ static std::mutex cache_mutex;
|
||||
+
|
||||
+ CacheEntry* entry;
|
||||
+ {
|
||||
+ std::lock_guard<std::mutex> lock(cache_mutex);
|
||||
+ entry = &cache[{dir_path, recursive}];
|
||||
+ }
|
||||
+
|
||||
+ // Now lock the per-entry mutex
|
||||
+ std::lock_guard<std::mutex> lock(entry->mutex);
|
||||
+ if (entry->result.type() != Value::NONE) {
|
||||
+ return entry->result;
|
||||
+ }
|
||||
+
|
||||
+ Value result = ExpandDirectoryInternal(function, dir, dir_path, recursive);
|
||||
+
|
||||
+ entry->result = result;
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+} // namespace functions
|
||||
diff --git a/src/gn/function_expand_directory_unittest.cc b/src/gn/function_expand_directory_unittest.cc
|
||||
new file mode 100644
|
||||
index 00000000..ecd467c6
|
||||
--- /dev/null
|
||||
+++ b/src/gn/function_expand_directory_unittest.cc
|
||||
@@ -0,0 +1,168 @@
|
||||
+// Copyright 2026 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 <algorithm>
|
||||
+
|
||||
+#include "base/files/file_util.h"
|
||||
+#include "base/files/scoped_temp_dir.h"
|
||||
+#include "gn/filesystem_utils.h"
|
||||
+#include "gn/functions.h"
|
||||
+#include "gn/input_file.h"
|
||||
+#include "gn/parse_tree.h"
|
||||
+#include "gn/test_with_scheduler.h"
|
||||
+#include "gn/test_with_scope.h"
|
||||
+#include "util/test/test.h"
|
||||
+
|
||||
+class ExpandDirectoryTest : public TestWithScheduler {
|
||||
+ protected:
|
||||
+ ExpandDirectoryTest() {
|
||||
+ CHECK(temp_dir_.CreateUniqueTempDir());
|
||||
+ setup.build_settings()->SetRootPath(temp_dir_.GetPath());
|
||||
+ }
|
||||
+
|
||||
+ base::ScopedTempDir temp_dir_;
|
||||
+ TestWithScope setup;
|
||||
+
|
||||
+ std::unique_ptr<FunctionCallNode> SetupDefaultDirAndFunction(
|
||||
+ InputFile* input_file,
|
||||
+ base::FilePath dir) {
|
||||
+ auto file1 = dir.AppendASCII("file1.txt");
|
||||
+ auto file2 = dir.AppendASCII("file2.txt");
|
||||
+ auto sub_dir = dir.AppendASCII("sub");
|
||||
+ auto file3 = sub_dir.AppendASCII("file3.txt");
|
||||
+
|
||||
+ EXPECT_TRUE(base::CreateDirectory(sub_dir));
|
||||
+ EXPECT_TRUE(WriteFile(file1, "content1", nullptr));
|
||||
+ EXPECT_TRUE(WriteFile(file2, "content2", nullptr));
|
||||
+ EXPECT_TRUE(WriteFile(file3, "content3", nullptr));
|
||||
+
|
||||
+ Location location(input_file, 1, 1);
|
||||
+ Token token(location, Token::IDENTIFIER, "expand_directory");
|
||||
+ auto function = std::make_unique<FunctionCallNode>();
|
||||
+ function->set_function(token);
|
||||
+
|
||||
+ auto args = std::make_unique<ListNode>();
|
||||
+ args->set_begin_token(token);
|
||||
+ args->set_end(std::make_unique<EndNode>(token));
|
||||
+ function->set_args(std::move(args));
|
||||
+
|
||||
+ auto allowlist = std::make_unique<SourceFileSet>();
|
||||
+ allowlist->insert(input_file->name());
|
||||
+ setup.build_settings()->set_expand_directory_allowlist(
|
||||
+ std::move(allowlist));
|
||||
+ return function;
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+TEST_F(ExpandDirectoryTest, Recursive) {
|
||||
+ auto dir_path = temp_dir_.GetPath().AppendASCII("foo").AppendASCII("bar");
|
||||
+ auto input_file = InputFile(SourceFile("//BUILD.gn"));
|
||||
+ auto function = SetupDefaultDirAndFunction(&input_file, dir_path);
|
||||
+
|
||||
+ Err err;
|
||||
+ Value result = functions::RunExpandDirectory(
|
||||
+ setup.scope(), function.get(),
|
||||
+ {Value(nullptr, "//foo/bar"), Value(nullptr, true)}, &err);
|
||||
+ ASSERT_FALSE(err.has_error()) << err.message();
|
||||
+
|
||||
+ ASSERT_EQ(result.type(), Value::LIST);
|
||||
+ ASSERT_EQ(result.list_value().size(), 3);
|
||||
+ EXPECT_EQ(result.list_value()[0].string_value(), "//foo/bar/file1.txt");
|
||||
+ EXPECT_EQ(result.list_value()[1].string_value(), "//foo/bar/file2.txt");
|
||||
+ EXPECT_EQ(result.list_value()[2].string_value(), "//foo/bar/sub/file3.txt");
|
||||
+
|
||||
+ std::vector<base::FilePath> deps = scheduler().GetGenDependencies();
|
||||
+ EXPECT_TRUE(std::ranges::find(deps, dir_path) != deps.end())
|
||||
+ << FilePathToUTF8(dir_path);
|
||||
+ auto sub = dir_path.AppendASCII("sub");
|
||||
+ EXPECT_TRUE(std::ranges::find(deps, sub) != deps.end())
|
||||
+ << FilePathToUTF8(sub);
|
||||
+}
|
||||
+
|
||||
+TEST_F(ExpandDirectoryTest, NonRecursive) {
|
||||
+ auto dir_path = temp_dir_.GetPath().AppendASCII("foo").AppendASCII("bar");
|
||||
+ auto input_file = InputFile(SourceFile("//foo/BUILD.gn"));
|
||||
+ auto function = SetupDefaultDirAndFunction(&input_file, dir_path);
|
||||
+ setup.scope()->set_source_dir(SourceDir("//foo/"));
|
||||
+
|
||||
+ Err err;
|
||||
+ Value result = functions::RunExpandDirectory(
|
||||
+ setup.scope(), function.get(),
|
||||
+ {Value(nullptr, "bar"), Value(nullptr, false)}, &err);
|
||||
+ ASSERT_FALSE(err.has_error()) << err.message();
|
||||
+ ASSERT_EQ(result.type(), Value::LIST);
|
||||
+ ASSERT_EQ(result.list_value().size(), 2);
|
||||
+ EXPECT_EQ(result.list_value()[0].string_value(), "//foo/bar/file1.txt");
|
||||
+ EXPECT_EQ(result.list_value()[1].string_value(), "//foo/bar/file2.txt");
|
||||
+
|
||||
+ std::vector<base::FilePath> deps = scheduler().GetGenDependencies();
|
||||
+ EXPECT_TRUE(std::ranges::find(deps, dir_path) != deps.end());
|
||||
+ EXPECT_TRUE(std::ranges::find(deps, dir_path.AppendASCII("sub")) ==
|
||||
+ deps.end());
|
||||
+}
|
||||
+
|
||||
+TEST_F(ExpandDirectoryTest, EmptyDir) {
|
||||
+ std::string dir_str = FilePathToUTF8(temp_dir_.GetPath());
|
||||
+
|
||||
+ FunctionCallNode function;
|
||||
+ Err err;
|
||||
+ Value result = functions::RunExpandDirectory(
|
||||
+ setup.scope(), &function, {Value(nullptr, dir_str), Value(nullptr, true)},
|
||||
+ &err);
|
||||
+ ASSERT_FALSE(err.has_error());
|
||||
+ ASSERT_EQ(result.type(), Value::LIST);
|
||||
+ ASSERT_EQ(result.list_value().size(), 0);
|
||||
+}
|
||||
+
|
||||
+TEST_F(ExpandDirectoryTest, NonExistentDir) {
|
||||
+ base::FilePath non_existent = temp_dir_.GetPath().AppendASCII("non_existent");
|
||||
+
|
||||
+ FunctionCallNode function;
|
||||
+ Err err;
|
||||
+ Value result = functions::RunExpandDirectory(
|
||||
+ setup.scope(), &function,
|
||||
+ {Value(nullptr, FilePathToUTF8(non_existent)), Value(nullptr, true)},
|
||||
+ &err);
|
||||
+ EXPECT_TRUE(err.has_error());
|
||||
+}
|
||||
+
|
||||
+TEST_F(ExpandDirectoryTest, Allowlist) {
|
||||
+ InputFile input_file(SourceFile("//BUILD.gn"));
|
||||
+ Location location(&input_file, 1, 1);
|
||||
+ Token token(location, Token::IDENTIFIER, "expand_directory");
|
||||
+ FunctionCallNode function;
|
||||
+ function.set_function(token);
|
||||
+
|
||||
+ auto args = std::make_unique<ListNode>();
|
||||
+ args->set_begin_token(token);
|
||||
+ args->set_end(std::make_unique<EndNode>(token));
|
||||
+ function.set_args(std::move(args));
|
||||
+
|
||||
+ // No allowlist
|
||||
+ {
|
||||
+ Err err;
|
||||
+ Value result = functions::RunExpandDirectory(
|
||||
+ setup.scope(), &function,
|
||||
+ {Value(nullptr, FilePathToUTF8(temp_dir_.GetPath())),
|
||||
+ Value(nullptr, true)},
|
||||
+ &err);
|
||||
+ EXPECT_TRUE(err.has_error());
|
||||
+ }
|
||||
+
|
||||
+ // Empty allowlist
|
||||
+ auto allowlist_owned = std::make_unique<SourceFileSet>();
|
||||
+ auto allowlist = allowlist_owned.get();
|
||||
+ setup.build_settings()->set_expand_directory_allowlist(
|
||||
+ std::move(allowlist_owned));
|
||||
+ allowlist->insert(SourceFile("//foo.gni"));
|
||||
+ {
|
||||
+ Err err;
|
||||
+ Value result = functions::RunExpandDirectory(
|
||||
+ setup.scope(), &function,
|
||||
+ {Value(nullptr, FilePathToUTF8(temp_dir_.GetPath())),
|
||||
+ Value(nullptr, true)},
|
||||
+ &err);
|
||||
+ EXPECT_TRUE(err.has_error());
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/gn/functions.cc b/src/gn/functions.cc
|
||||
index 830fcee7..d7099650 100644
|
||||
--- a/src/gn/functions.cc
|
||||
+++ b/src/gn/functions.cc
|
||||
@@ -1524,6 +1524,7 @@ struct FunctionInfoInitializer {
|
||||
INSERT_FUNCTION(DeclareArgs, false)
|
||||
INSERT_FUNCTION(Defined, false)
|
||||
INSERT_FUNCTION(ExecScript, false)
|
||||
+ INSERT_FUNCTION(ExpandDirectory, false)
|
||||
INSERT_FUNCTION(FilterExclude, false)
|
||||
INSERT_FUNCTION(FilterInclude, false)
|
||||
INSERT_FUNCTION(FilterLabelsInclude, false)
|
||||
diff --git a/src/gn/functions.h b/src/gn/functions.h
|
||||
index 787e6ed2..bf97b9e9 100644
|
||||
--- a/src/gn/functions.h
|
||||
+++ b/src/gn/functions.h
|
||||
@@ -146,6 +146,14 @@ Value RunExecutable(Scope* scope,
|
||||
BlockNode* block,
|
||||
Err* err);
|
||||
|
||||
+extern const char kExpandDirectory[];
|
||||
+extern const char kExpandDirectory_HelpShort[];
|
||||
+extern const char kExpandDirectory_Help[];
|
||||
+Value RunExpandDirectory(Scope* scope,
|
||||
+ const FunctionCallNode* function,
|
||||
+ const std::vector<Value>& args,
|
||||
+ Err* err);
|
||||
+
|
||||
extern const char kFilterExclude[];
|
||||
extern const char kFilterExclude_HelpShort[];
|
||||
extern const char kFilterExclude_Help[];
|
||||
diff --git a/src/gn/setup.cc b/src/gn/setup.cc
|
||||
index b29e2ff0..b83a2ea8 100644
|
||||
--- a/src/gn/setup.cc
|
||||
+++ b/src/gn/setup.cc
|
||||
@@ -127,6 +127,21 @@ Variables
|
||||
If both values are set, only the value in "exec_script_allowlist" will
|
||||
have any effect (so don't set both!).
|
||||
|
||||
+ expand_directory_allowlist [optional]
|
||||
+ A list of .gn/.gni files (not labels) that have permission to call the
|
||||
+ expand_directory function. If this list is defined, calls to
|
||||
+ expand_directory will be checked against this list and GN will fail if
|
||||
+ the current file isn't in the list.
|
||||
+
|
||||
+ The use of expand_directory is restricted because it encourages
|
||||
+ monolithic build targets with redundant inputs, which can slow down
|
||||
+ the build.
|
||||
+
|
||||
+ Example:
|
||||
+ expand_directory_allowlist = [
|
||||
+ "//base/BUILD.gn",
|
||||
+ ]
|
||||
+
|
||||
export_compile_commands [optional]
|
||||
A list of label patterns for which to generate a Clang compilation
|
||||
database (see "gn help label_pattern" for the string format).
|
||||
@@ -257,6 +272,28 @@ base::FilePath FindDotFile(const base::FilePath& current_dir) {
|
||||
return FindDotFile(up_one_dir);
|
||||
}
|
||||
|
||||
+std::unique_ptr<SourceFileSet> FillAllowlist(const Value* value,
|
||||
+ const SourceDir& current_dir,
|
||||
+ Err* err) {
|
||||
+ if (!value)
|
||||
+ return nullptr;
|
||||
+
|
||||
+ if (!value->VerifyTypeIs(Value::LIST, err)) {
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+ auto allowlist = std::make_unique<SourceFileSet>();
|
||||
+ for (const auto& item : value->list_value()) {
|
||||
+ if (!item.VerifyTypeIs(Value::STRING, err)) {
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+ allowlist->insert(current_dir.ResolveRelativeFile(item, err));
|
||||
+ if (err->has_error()) {
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+ }
|
||||
+ return allowlist;
|
||||
+}
|
||||
+
|
||||
// Called on any thread. Post the item to the builder on the main thread.
|
||||
void ItemDefinedCallback(MsgLoop* task_runner,
|
||||
Builder* builder_call_on_main_thread_only,
|
||||
@@ -1107,24 +1144,28 @@ bool Setup::FillOtherConfig(const base::CommandLine& cmdline, Err* err) {
|
||||
exec_script_allowlist_value =
|
||||
dotfile_scope_.GetValue("exec_script_whitelist", true);
|
||||
}
|
||||
-
|
||||
if (exec_script_allowlist_value) {
|
||||
- // Fill the list of targets to check.
|
||||
- if (!exec_script_allowlist_value->VerifyTypeIs(Value::LIST, err)) {
|
||||
+ build_settings_.set_exec_script_allowlist(
|
||||
+ FillAllowlist(exec_script_allowlist_value, current_dir, err));
|
||||
+ if (err->has_error()) {
|
||||
return false;
|
||||
}
|
||||
- std::unique_ptr<SourceFileSet> allowlist =
|
||||
- std::make_unique<SourceFileSet>();
|
||||
- for (const auto& item : exec_script_allowlist_value->list_value()) {
|
||||
- if (!item.VerifyTypeIs(Value::STRING, err)) {
|
||||
- return false;
|
||||
- }
|
||||
- allowlist->insert(current_dir.ResolveRelativeFile(item, err));
|
||||
- if (err->has_error()) {
|
||||
- return false;
|
||||
- }
|
||||
+ }
|
||||
+
|
||||
+ // Fill expand_directory_allowlist.
|
||||
+ const Value* expand_directory_allowlist_value =
|
||||
+ dotfile_scope_.GetValue("expand_directory_allowlist", true);
|
||||
+
|
||||
+ if (expand_directory_allowlist_value) {
|
||||
+ build_settings_.set_expand_directory_allowlist(
|
||||
+ FillAllowlist(expand_directory_allowlist_value, current_dir, err));
|
||||
+ if (err->has_error()) {
|
||||
+ return false;
|
||||
}
|
||||
- build_settings_.set_exec_script_allowlist(std::move(allowlist));
|
||||
+ } else {
|
||||
+ // Treat unspecified as empty.
|
||||
+ build_settings_.set_expand_directory_allowlist(
|
||||
+ std::make_unique<SourceFileSet>());
|
||||
}
|
||||
|
||||
// Fill optional default_args.
|
||||
diff --git a/src/gn/source_file.cc b/src/gn/source_file.cc
|
||||
index 3a9198b3..ecc2d1e9 100644
|
||||
--- a/src/gn/source_file.cc
|
||||
+++ b/src/gn/source_file.cc
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
+#include "gn/input_file.h"
|
||||
+#include "gn/parse_tree.h"
|
||||
#include "gn/source_file.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
@@ -222,3 +224,14 @@ bool SourceFileTypeSet::MixedSourceUsed() const {
|
||||
<< static_cast<int>(GoSourceUsed())
|
||||
<< static_cast<int>(SwiftSourceUsed())) > 2;
|
||||
}
|
||||
+
|
||||
+bool InSourceAllowList(const ParseNode* node, const SourceFileSet* allowlist) {
|
||||
+ if (!allowlist)
|
||||
+ return true;
|
||||
+
|
||||
+ LocationRange range = node->GetRange();
|
||||
+ if (!range.begin().file())
|
||||
+ return true;
|
||||
+
|
||||
+ return allowlist->find(range.begin().file()->name()) != allowlist->end();
|
||||
+}
|
||||
diff --git a/src/gn/source_file.h b/src/gn/source_file.h
|
||||
index f682f0d4..f63c5dc6 100644
|
||||
--- a/src/gn/source_file.h
|
||||
+++ b/src/gn/source_file.h
|
||||
@@ -154,6 +154,9 @@ struct hash<SourceFile> {
|
||||
// overall difference in "gn gen" time is about 10%.
|
||||
using SourceFileSet = base::flat_set<SourceFile, SourceFile::PtrCompare>;
|
||||
|
||||
+class ParseNode;
|
||||
+bool InSourceAllowList(const ParseNode* node, const SourceFileSet* allowlist);
|
||||
+
|
||||
// Represents a set of tool types.
|
||||
class SourceFileTypeSet {
|
||||
public:
|
||||
@ -0,0 +1,134 @@
|
||||
From 46fd0cdb48cf3d42e29e19112eb3f297b3127dfd Mon Sep 17 00:00:00 2001
|
||||
From: Nico Weber <thakis@chromium.org>
|
||||
Date: Mon, 9 Mar 2026 12:43:52 -0400
|
||||
Subject: [PATCH] Reject newlines in string config values (defines, cflags,
|
||||
etc.)
|
||||
|
||||
A literal newline in a define or flag value would be written verbatim
|
||||
into ninja files, breaking ninja's line-based parsing. Rather than
|
||||
trying to escape newlines (which would work on POSIX via $$'\n' but
|
||||
has no equivalent for cmd.exe on Windows), reject them with a clear
|
||||
error at GN time. A newline in a compiler flag is almost certainly
|
||||
a mistake anyway.
|
||||
|
||||
The validation is in GetStringList() so it covers all string config
|
||||
values: defines, cflags, cflags_c, cflags_cc, cflags_objc,
|
||||
cflags_objcc, asmflags, arflags, ldflags, rustflags, rustenv, and
|
||||
swiftflags.
|
||||
|
||||
Before, without the pkg-config.py change in the linked bug, things
|
||||
failed at build time:
|
||||
|
||||
```
|
||||
% autoninja -C out/gnlinux base_unittests
|
||||
offline mode
|
||||
ninja: Entering directory `out/gnlinux'
|
||||
0.20s load build.ninja failed:
|
||||
|
||||
1.47s Error: failed to load build.ninja: toolchain.ninja: line:61052: unexpected indent: " include_dirs =
|
||||
```
|
||||
|
||||
Now, the fail at `gn gen` time instead:
|
||||
|
||||
```
|
||||
% ~/src/gn/out/gn gen out/gnlinux
|
||||
//build/config/linux/pkg-config.py ["-s", "../../build/linux/debian_bullseye_amd64-sysroot", "-a", "x64"] []
|
||||
ERROR at //build/config/linux/atk/BUILD.gn:33:5: Newlines in defines values are not supported.
|
||||
"ATK_LIB_DIR=\"$atk_lib_dir\"",
|
||||
^-----------------------------
|
||||
The value `ATK_LIB_DIR="[[],[],[],[],[]]
|
||||
"` contains a newline.
|
||||
See //build/config/linux/atk/BUILD.gn:19:1: whence it was called.
|
||||
pkg_config("atk") {
|
||||
^------------------
|
||||
See //ui/accessibility/BUILD.gn:465:20: which caused the file to be included.
|
||||
configs += [ "//build/config/linux/atk" ]
|
||||
^-------------------------
|
||||
```
|
||||
|
||||
Bug: 40176116
|
||||
Change-Id: I870d625552087430f5a679b8668a1929662e7b4a
|
||||
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/21460
|
||||
Reviewed-by: Takuto Ikuta <tikuta@google.com>
|
||||
Commit-Queue: Nico Weber <thakis@chromium.org>
|
||||
Reviewed-by: Nico Weber <thakis@google.com>
|
||||
---
|
||||
src/gn/config_values_extractors_unittest.cc | 36 +++++++++++++++++++++
|
||||
src/gn/config_values_generator.cc | 13 ++++++++
|
||||
2 files changed, 49 insertions(+)
|
||||
|
||||
diff --git a/src/gn/config_values_extractors_unittest.cc b/src/gn/config_values_extractors_unittest.cc
|
||||
index 3db4bff9..d187daba 100644
|
||||
--- a/src/gn/config_values_extractors_unittest.cc
|
||||
+++ b/src/gn/config_values_extractors_unittest.cc
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "gn/config.h"
|
||||
#include "gn/config_values_extractors.h"
|
||||
+#include "gn/config_values_generator.h"
|
||||
#include "gn/target.h"
|
||||
#include "gn/test_with_scope.h"
|
||||
#include "util/test/test.h"
|
||||
@@ -147,3 +148,38 @@ TEST(ConfigValuesExtractors, IncludeOrdering) {
|
||||
"//target/ //target/config/ //target/all/ //target/direct/ "
|
||||
"//dep1/all/ //dep2/all/ //dep1/direct/ ");
|
||||
}
|
||||
+
|
||||
+TEST(ConfigValuesGenerator, DefinesWithNewlineError) {
|
||||
+ TestWithScope setup;
|
||||
+ Err err;
|
||||
+
|
||||
+ // Set up a scope with a defines list containing a newline.
|
||||
+ Value defines_value(nullptr, Value::LIST);
|
||||
+ defines_value.list_value().push_back(Value(nullptr, "GOOD"));
|
||||
+ defines_value.list_value().push_back(Value(nullptr, "BAD=a\nb"));
|
||||
+ setup.scope()->SetValue("defines", defines_value, nullptr);
|
||||
+
|
||||
+ ConfigValues config_values;
|
||||
+ ConfigValuesGenerator gen(&config_values, setup.scope(),
|
||||
+ SourceDir("//foo/"), &err);
|
||||
+ gen.Run();
|
||||
+ EXPECT_TRUE(err.has_error());
|
||||
+ EXPECT_EQ(err.message(), "Newlines in defines values are not supported.");
|
||||
+ EXPECT_EQ(err.help_text(), "The value `BAD=a\nb` contains a newline.");
|
||||
+}
|
||||
+
|
||||
+TEST(ConfigValuesGenerator, CflagsWithNewlineError) {
|
||||
+ TestWithScope setup;
|
||||
+ Err err;
|
||||
+
|
||||
+ Value cflags_value(nullptr, Value::LIST);
|
||||
+ cflags_value.list_value().push_back(Value(nullptr, "-Dfoo\nbar"));
|
||||
+ setup.scope()->SetValue("cflags", cflags_value, nullptr);
|
||||
+
|
||||
+ ConfigValues config_values;
|
||||
+ ConfigValuesGenerator gen(&config_values, setup.scope(),
|
||||
+ SourceDir("//foo/"), &err);
|
||||
+ gen.Run();
|
||||
+ EXPECT_TRUE(err.has_error());
|
||||
+ EXPECT_EQ(err.message(), "Newlines in cflags values are not supported.");
|
||||
+}
|
||||
diff --git a/src/gn/config_values_generator.cc b/src/gn/config_values_generator.cc
|
||||
index cf91a8ce..3d95f466 100644
|
||||
--- a/src/gn/config_values_generator.cc
|
||||
+++ b/src/gn/config_values_generator.cc
|
||||
@@ -27,6 +27,19 @@ void GetStringList(Scope* scope,
|
||||
return; // No value, empty input and succeed.
|
||||
|
||||
ExtractListOfStringValues(*value, &(config_values->*accessor)(), err);
|
||||
+ if (err->has_error())
|
||||
+ return;
|
||||
+
|
||||
+ const auto& strings = (config_values->*accessor)();
|
||||
+ for (size_t i = 0; i < strings.size(); i++) {
|
||||
+ if (strings[i].find('\n') != std::string::npos) {
|
||||
+ *err = Err(value->list_value()[i],
|
||||
+ "Newlines in " + std::string(var_name) + " values are not "
|
||||
+ "supported.",
|
||||
+ "The value `" + strings[i] + "` contains a newline.");
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
void GetDirList(Scope* scope,
|
||||
613
community/gn/0003-Add-inputs-parameter-to-tool.patch
Normal file
613
community/gn/0003-Add-inputs-parameter-to-tool.patch
Normal file
@ -0,0 +1,613 @@
|
||||
From d8fc9abd3a572ecce1ac9156eb790d1c1dbca74a Mon Sep 17 00:00:00 2001
|
||||
From: Matt Stark <msta@google.com>
|
||||
Date: Tue, 10 Mar 2026 00:24:21 +1100
|
||||
Subject: [PATCH] Add `inputs` parameter to `tool`.
|
||||
|
||||
This allows tools to specify what files are required for the tools
|
||||
itself, thus better supporting remote actions.
|
||||
|
||||
Eg. cxx rules might add inputs = [ clang ].
|
||||
A rule with command `python3 foo.py` (where foo.py imports bar.py) would
|
||||
specify both foo.py and bar.py.
|
||||
|
||||
BUG=b:491242305
|
||||
|
||||
Change-Id: If5381bb944aa616c2a5d2435b6cb8e416a6a6964
|
||||
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/21440
|
||||
Reviewed-by: Takuto Ikuta <tikuta@google.com>
|
||||
Commit-Queue: Matt Stark <msta@google.com>
|
||||
---
|
||||
docs/reference.md | 5 ++
|
||||
src/gn/config_values_extractors_unittest.cc | 8 +--
|
||||
src/gn/config_values_generator.cc | 5 +-
|
||||
src/gn/function_toolchain.cc | 5 ++
|
||||
src/gn/ninja_binary_target_writer.cc | 11 +++-
|
||||
src/gn/ninja_binary_target_writer.h | 2 +-
|
||||
src/gn/ninja_c_binary_target_writer.cc | 36 ++++++-----
|
||||
src/gn/ninja_c_binary_target_writer.h | 6 +-
|
||||
.../ninja_c_binary_target_writer_unittest.cc | 64 +++++++++++++++++++
|
||||
src/gn/ninja_rust_binary_target_writer.cc | 8 ++-
|
||||
src/gn/ninja_toolchain_writer.cc | 16 +++++
|
||||
src/gn/ninja_toolchain_writer.h | 1 +
|
||||
src/gn/ninja_toolchain_writer_unittest.cc | 25 ++++++++
|
||||
src/gn/tool.cc | 33 +++++++++-
|
||||
src/gn/tool.h | 15 +++++
|
||||
15 files changed, 210 insertions(+), 30 deletions(-)
|
||||
|
||||
diff --git a/docs/reference.md b/docs/reference.md
|
||||
index 7e848c7a..8fd26a5f 100644
|
||||
--- a/docs/reference.md
|
||||
+++ b/docs/reference.md
|
||||
@@ -4475,6 +4475,11 @@
|
||||
|
||||
This concept is somewhat inefficient to express in Ninja (it requires a lot
|
||||
of duplicate of rules) so should only be used when absolutely necessary.
|
||||
+
|
||||
+ inputs [string list]
|
||||
+ A list of files needed to execute the tool.
|
||||
+ For example, if your tool command is "python3 foo.py", and foo.py imports
|
||||
+ bar.py, you should set inputs to [ "foo.py", "bar.py" ].
|
||||
```
|
||||
|
||||
#### **Example of defining a toolchain**
|
||||
diff --git a/src/gn/config_values_extractors_unittest.cc b/src/gn/config_values_extractors_unittest.cc
|
||||
index d187daba..b1fda895 100644
|
||||
--- a/src/gn/config_values_extractors_unittest.cc
|
||||
+++ b/src/gn/config_values_extractors_unittest.cc
|
||||
@@ -160,8 +160,8 @@ TEST(ConfigValuesGenerator, DefinesWithNewlineError) {
|
||||
setup.scope()->SetValue("defines", defines_value, nullptr);
|
||||
|
||||
ConfigValues config_values;
|
||||
- ConfigValuesGenerator gen(&config_values, setup.scope(),
|
||||
- SourceDir("//foo/"), &err);
|
||||
+ ConfigValuesGenerator gen(&config_values, setup.scope(), SourceDir("//foo/"),
|
||||
+ &err);
|
||||
gen.Run();
|
||||
EXPECT_TRUE(err.has_error());
|
||||
EXPECT_EQ(err.message(), "Newlines in defines values are not supported.");
|
||||
@@ -177,8 +177,8 @@ TEST(ConfigValuesGenerator, CflagsWithNewlineError) {
|
||||
setup.scope()->SetValue("cflags", cflags_value, nullptr);
|
||||
|
||||
ConfigValues config_values;
|
||||
- ConfigValuesGenerator gen(&config_values, setup.scope(),
|
||||
- SourceDir("//foo/"), &err);
|
||||
+ ConfigValuesGenerator gen(&config_values, setup.scope(), SourceDir("//foo/"),
|
||||
+ &err);
|
||||
gen.Run();
|
||||
EXPECT_TRUE(err.has_error());
|
||||
EXPECT_EQ(err.message(), "Newlines in cflags values are not supported.");
|
||||
diff --git a/src/gn/config_values_generator.cc b/src/gn/config_values_generator.cc
|
||||
index 3d95f466..1f0f90c1 100644
|
||||
--- a/src/gn/config_values_generator.cc
|
||||
+++ b/src/gn/config_values_generator.cc
|
||||
@@ -34,8 +34,9 @@ void GetStringList(Scope* scope,
|
||||
for (size_t i = 0; i < strings.size(); i++) {
|
||||
if (strings[i].find('\n') != std::string::npos) {
|
||||
*err = Err(value->list_value()[i],
|
||||
- "Newlines in " + std::string(var_name) + " values are not "
|
||||
- "supported.",
|
||||
+ "Newlines in " + std::string(var_name) +
|
||||
+ " values are not "
|
||||
+ "supported.",
|
||||
"The value `" + strings[i] + "` contains a newline.");
|
||||
return;
|
||||
}
|
||||
diff --git a/src/gn/function_toolchain.cc b/src/gn/function_toolchain.cc
|
||||
index 2f9bf578..3fdddaeb 100644
|
||||
--- a/src/gn/function_toolchain.cc
|
||||
+++ b/src/gn/function_toolchain.cc
|
||||
@@ -134,6 +134,11 @@ Functions and variables
|
||||
This concept is somewhat inefficient to express in Ninja (it requires a lot
|
||||
of duplicate of rules) so should only be used when absolutely necessary.
|
||||
|
||||
+ inputs [string list]
|
||||
+ A list of files needed to execute the tool.
|
||||
+ For example, if your tool command is "python3 foo.py", and foo.py imports
|
||||
+ bar.py, you should set inputs to [ "foo.py", "bar.py" ].
|
||||
+
|
||||
Example of defining a toolchain
|
||||
|
||||
toolchain("32") {
|
||||
diff --git a/src/gn/ninja_binary_target_writer.cc b/src/gn/ninja_binary_target_writer.cc
|
||||
index ac45e976..abf5e153 100644
|
||||
--- a/src/gn/ninja_binary_target_writer.cc
|
||||
+++ b/src/gn/ninja_binary_target_writer.cc
|
||||
@@ -276,19 +276,24 @@ void NinjaBinaryTargetWriter::WriteCompilerBuildLine(
|
||||
const std::vector<SourceFile>& sources,
|
||||
const std::vector<OutputFile>& extra_deps,
|
||||
const std::vector<OutputFile>& order_only_deps,
|
||||
- const char* tool_name,
|
||||
+ const Tool* tool,
|
||||
const std::vector<OutputFile>& outputs,
|
||||
bool can_write_source_info,
|
||||
bool restat_output_allowed) {
|
||||
out_ << "build";
|
||||
WriteOutputs(outputs);
|
||||
|
||||
- out_ << ": " << rule_prefix_ << tool_name;
|
||||
+ out_ << ": " << rule_prefix_ << tool->name();
|
||||
path_output_.WriteFiles(out_, sources);
|
||||
|
||||
- if (!extra_deps.empty()) {
|
||||
+ if (!extra_deps.empty() || !tool->inputs().empty()) {
|
||||
out_ << " |";
|
||||
path_output_.WriteFiles(out_, extra_deps);
|
||||
+ if (auto phony = tool->inputs_phony_or_file(rule_prefix_,
|
||||
+ *settings_->build_settings())) {
|
||||
+ out_ << " ";
|
||||
+ path_output_.WriteFile(out_, *phony);
|
||||
+ }
|
||||
}
|
||||
|
||||
if (!order_only_deps.empty()) {
|
||||
diff --git a/src/gn/ninja_binary_target_writer.h b/src/gn/ninja_binary_target_writer.h
|
||||
index 29105b47..b64f8843 100644
|
||||
--- a/src/gn/ninja_binary_target_writer.h
|
||||
+++ b/src/gn/ninja_binary_target_writer.h
|
||||
@@ -56,7 +56,7 @@ class NinjaBinaryTargetWriter : public NinjaTargetWriter {
|
||||
void WriteCompilerBuildLine(const std::vector<SourceFile>& sources,
|
||||
const std::vector<OutputFile>& extra_deps,
|
||||
const std::vector<OutputFile>& order_only_deps,
|
||||
- const char* tool_name,
|
||||
+ const Tool* tool,
|
||||
const std::vector<OutputFile>& outputs,
|
||||
bool can_write_source_info = true,
|
||||
bool restat_output_allowed = false);
|
||||
diff --git a/src/gn/ninja_c_binary_target_writer.cc b/src/gn/ninja_c_binary_target_writer.cc
|
||||
index c864bc09..24852628 100644
|
||||
--- a/src/gn/ninja_c_binary_target_writer.cc
|
||||
+++ b/src/gn/ninja_c_binary_target_writer.cc
|
||||
@@ -229,14 +229,14 @@ void NinjaCBinaryTargetWriter::WritePCHCommands(
|
||||
const CTool* tool_c = target_->toolchain()->GetToolAsC(CTool::kCToolCc);
|
||||
if (tool_c && tool_c->precompiled_header_type() != CTool::PCH_NONE &&
|
||||
target_->source_types_used().Get(SourceFile::SOURCE_C)) {
|
||||
- WritePCHCommand(&CSubstitutionCFlagsC, CTool::kCToolCc,
|
||||
+ WritePCHCommand(&CSubstitutionCFlagsC, tool_c,
|
||||
tool_c->precompiled_header_type(), input_deps,
|
||||
order_only_deps, object_files, other_files);
|
||||
}
|
||||
const CTool* tool_cxx = target_->toolchain()->GetToolAsC(CTool::kCToolCxx);
|
||||
if (tool_cxx && tool_cxx->precompiled_header_type() != CTool::PCH_NONE &&
|
||||
target_->source_types_used().Get(SourceFile::SOURCE_CPP)) {
|
||||
- WritePCHCommand(&CSubstitutionCFlagsCc, CTool::kCToolCxx,
|
||||
+ WritePCHCommand(&CSubstitutionCFlagsCc, tool_cxx,
|
||||
tool_cxx->precompiled_header_type(), input_deps,
|
||||
order_only_deps, object_files, other_files);
|
||||
}
|
||||
@@ -244,7 +244,7 @@ void NinjaCBinaryTargetWriter::WritePCHCommands(
|
||||
const CTool* tool_objc = target_->toolchain()->GetToolAsC(CTool::kCToolObjC);
|
||||
if (tool_objc && tool_objc->precompiled_header_type() == CTool::PCH_GCC &&
|
||||
target_->source_types_used().Get(SourceFile::SOURCE_M)) {
|
||||
- WritePCHCommand(&CSubstitutionCFlagsObjC, CTool::kCToolObjC,
|
||||
+ WritePCHCommand(&CSubstitutionCFlagsObjC, tool_objc,
|
||||
tool_objc->precompiled_header_type(), input_deps,
|
||||
order_only_deps, object_files, other_files);
|
||||
}
|
||||
@@ -253,7 +253,7 @@ void NinjaCBinaryTargetWriter::WritePCHCommands(
|
||||
target_->toolchain()->GetToolAsC(CTool::kCToolObjCxx);
|
||||
if (tool_objcxx && tool_objcxx->precompiled_header_type() == CTool::PCH_GCC &&
|
||||
target_->source_types_used().Get(SourceFile::SOURCE_MM)) {
|
||||
- WritePCHCommand(&CSubstitutionCFlagsObjCc, CTool::kCToolObjCxx,
|
||||
+ WritePCHCommand(&CSubstitutionCFlagsObjCc, tool_objcxx,
|
||||
tool_objcxx->precompiled_header_type(), input_deps,
|
||||
order_only_deps, object_files, other_files);
|
||||
}
|
||||
@@ -261,7 +261,7 @@ void NinjaCBinaryTargetWriter::WritePCHCommands(
|
||||
|
||||
void NinjaCBinaryTargetWriter::WritePCHCommand(
|
||||
const Substitution* flag_type,
|
||||
- const char* tool_name,
|
||||
+ const Tool* tool,
|
||||
CTool::PrecompiledHeaderType header_type,
|
||||
const std::vector<OutputFile>& input_deps,
|
||||
const std::vector<OutputFile>& order_only_deps,
|
||||
@@ -269,11 +269,11 @@ void NinjaCBinaryTargetWriter::WritePCHCommand(
|
||||
std::vector<OutputFile>* other_files) {
|
||||
switch (header_type) {
|
||||
case CTool::PCH_MSVC:
|
||||
- WriteWindowsPCHCommand(flag_type, tool_name, input_deps, order_only_deps,
|
||||
+ WriteWindowsPCHCommand(flag_type, tool, input_deps, order_only_deps,
|
||||
object_files);
|
||||
break;
|
||||
case CTool::PCH_GCC:
|
||||
- WriteGCCPCHCommand(flag_type, tool_name, input_deps, order_only_deps,
|
||||
+ WriteGCCPCHCommand(flag_type, tool, input_deps, order_only_deps,
|
||||
other_files);
|
||||
break;
|
||||
case CTool::PCH_NONE:
|
||||
@@ -284,12 +284,13 @@ void NinjaCBinaryTargetWriter::WritePCHCommand(
|
||||
|
||||
void NinjaCBinaryTargetWriter::WriteGCCPCHCommand(
|
||||
const Substitution* flag_type,
|
||||
- const char* tool_name,
|
||||
+ const Tool* tool,
|
||||
const std::vector<OutputFile>& input_deps,
|
||||
const std::vector<OutputFile>& order_only_deps,
|
||||
std::vector<OutputFile>* gch_files) {
|
||||
// Compute the pch output file (it will be language-specific).
|
||||
std::vector<OutputFile> outputs;
|
||||
+ auto tool_name = tool->name();
|
||||
GetPCHOutputFiles(target_, tool_name, &outputs);
|
||||
if (outputs.empty())
|
||||
return;
|
||||
@@ -302,7 +303,7 @@ void NinjaCBinaryTargetWriter::WriteGCCPCHCommand(
|
||||
|
||||
// Build line to compile the file.
|
||||
WriteCompilerBuildLine({target_->config_values().precompiled_source()},
|
||||
- extra_deps, order_only_deps, tool_name, outputs);
|
||||
+ extra_deps, order_only_deps, tool, outputs);
|
||||
|
||||
// This build line needs a custom language-specific flags value. Rule-specific
|
||||
// variables are just indented underneath the rule line.
|
||||
@@ -340,13 +341,13 @@ void NinjaCBinaryTargetWriter::WriteGCCPCHCommand(
|
||||
|
||||
void NinjaCBinaryTargetWriter::WriteWindowsPCHCommand(
|
||||
const Substitution* flag_type,
|
||||
- const char* tool_name,
|
||||
+ const Tool* tool,
|
||||
const std::vector<OutputFile>& input_deps,
|
||||
const std::vector<OutputFile>& order_only_deps,
|
||||
std::vector<OutputFile>* object_files) {
|
||||
// Compute the pch output file (it will be language-specific).
|
||||
std::vector<OutputFile> outputs;
|
||||
- GetPCHOutputFiles(target_, tool_name, &outputs);
|
||||
+ GetPCHOutputFiles(target_, tool->name(), &outputs);
|
||||
if (outputs.empty())
|
||||
return;
|
||||
|
||||
@@ -358,7 +359,7 @@ void NinjaCBinaryTargetWriter::WriteWindowsPCHCommand(
|
||||
|
||||
// Build line to compile the file.
|
||||
WriteCompilerBuildLine({target_->config_values().precompiled_source()},
|
||||
- extra_deps, order_only_deps, tool_name, outputs);
|
||||
+ extra_deps, order_only_deps, tool, outputs);
|
||||
|
||||
// This build line needs a custom language-specific flags value. Rule-specific
|
||||
// variables are just indented underneath the rule line.
|
||||
@@ -435,7 +436,7 @@ void NinjaCBinaryTargetWriter::WriteSources(
|
||||
deps.push_back(module_dep.pcm);
|
||||
}
|
||||
|
||||
- WriteCompilerBuildLine({source}, deps, order_only_deps, tool_name,
|
||||
+ WriteCompilerBuildLine({source}, deps, order_only_deps, tool,
|
||||
tool_outputs);
|
||||
WritePool(out_);
|
||||
}
|
||||
@@ -480,8 +481,7 @@ void NinjaCBinaryTargetWriter::WriteSwiftSources(
|
||||
|
||||
const Tool* tool = target_->swift_values().GetTool(target_);
|
||||
WriteCompilerBuildLine(target_->sources(), input_deps,
|
||||
- swift_order_only_deps.vector(), tool->name(),
|
||||
- *output_files,
|
||||
+ swift_order_only_deps.vector(), tool, *output_files,
|
||||
/*can_write_source_info=*/false,
|
||||
/*restat_output_allowed=*/true);
|
||||
|
||||
@@ -591,6 +591,12 @@ void NinjaCBinaryTargetWriter::WriteLinkerStuff(
|
||||
std::copy(input_deps.begin(), input_deps.end(),
|
||||
std::back_inserter(implicit_deps));
|
||||
|
||||
+ if (auto phony = tool_->inputs_phony_or_file(rule_prefix_,
|
||||
+ *settings_->build_settings());
|
||||
+ phony) {
|
||||
+ implicit_deps.emplace_back(std::move(*phony));
|
||||
+ }
|
||||
+
|
||||
// Any C++ target which depends on a Rust .rlib has to depend on its entire
|
||||
// tree of transitive rlibs found inside the linking target (which excludes
|
||||
// rlibs only depended on inside a shared library dependency).
|
||||
diff --git a/src/gn/ninja_c_binary_target_writer.h b/src/gn/ninja_c_binary_target_writer.h
|
||||
index 3707f0eb..5436eeec 100644
|
||||
--- a/src/gn/ninja_c_binary_target_writer.h
|
||||
+++ b/src/gn/ninja_c_binary_target_writer.h
|
||||
@@ -51,7 +51,7 @@ class NinjaCBinaryTargetWriter : public NinjaBinaryTargetWriter {
|
||||
|
||||
// Writes a .pch compile build line for a language type.
|
||||
void WritePCHCommand(const Substitution* flag_type,
|
||||
- const char* tool_name,
|
||||
+ const Tool* tool,
|
||||
CTool::PrecompiledHeaderType header_type,
|
||||
const std::vector<OutputFile>& input_deps,
|
||||
const std::vector<OutputFile>& order_only_deps,
|
||||
@@ -59,13 +59,13 @@ class NinjaCBinaryTargetWriter : public NinjaBinaryTargetWriter {
|
||||
std::vector<OutputFile>* other_files);
|
||||
|
||||
void WriteGCCPCHCommand(const Substitution* flag_type,
|
||||
- const char* tool_name,
|
||||
+ const Tool* tool,
|
||||
const std::vector<OutputFile>& input_deps,
|
||||
const std::vector<OutputFile>& order_only_deps,
|
||||
std::vector<OutputFile>* gch_files);
|
||||
|
||||
void WriteWindowsPCHCommand(const Substitution* flag_type,
|
||||
- const char* tool_name,
|
||||
+ const Tool* tool,
|
||||
const std::vector<OutputFile>& input_deps,
|
||||
const std::vector<OutputFile>& order_only_deps,
|
||||
std::vector<OutputFile>* object_files);
|
||||
diff --git a/src/gn/ninja_c_binary_target_writer_unittest.cc b/src/gn/ninja_c_binary_target_writer_unittest.cc
|
||||
index f324d533..73804fde 100644
|
||||
--- a/src/gn/ninja_c_binary_target_writer_unittest.cc
|
||||
+++ b/src/gn/ninja_c_binary_target_writer_unittest.cc
|
||||
@@ -2847,3 +2847,67 @@ TEST_F(NinjaCBinaryTargetWriterTest, Pool) {
|
||||
std::string out_str = out.str();
|
||||
EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
|
||||
}
|
||||
+
|
||||
+TEST_F(NinjaCBinaryTargetWriterTest, ToolInputs) {
|
||||
+ Err err;
|
||||
+ TestWithScope setup;
|
||||
+
|
||||
+ Toolchain toolchain_with_inputs(
|
||||
+ setup.settings(),
|
||||
+ Label(SourceDir("//toolchain_with_inputs/"), "with_inputs"));
|
||||
+
|
||||
+ std::unique_ptr<Tool> cxx_tool = Tool::CreateTool(CTool::kCToolCxx);
|
||||
+ TestWithScope::SetCommandForTool(
|
||||
+ "c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} "
|
||||
+ "-o {{output}}",
|
||||
+ cxx_tool.get());
|
||||
+ cxx_tool->set_outputs(SubstitutionList::MakeForTest(
|
||||
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
|
||||
+ cxx_tool->set_inputs({SourceFile("//bin/clang++")});
|
||||
+ toolchain_with_inputs.SetTool(std::move(cxx_tool));
|
||||
+
|
||||
+ std::unique_ptr<Tool> link = Tool::CreateTool(CTool::kCToolLink);
|
||||
+ TestWithScope::SetCommandForTool(
|
||||
+ "ld -o {{target_output_name}} {{source}} {{ldflags}} {{libs}}",
|
||||
+ link.get());
|
||||
+ link->set_outputs(
|
||||
+ SubstitutionList::MakeForTest("{{root_out_dir}}/{{target_output_name}}"));
|
||||
+ link->set_inputs(
|
||||
+ {SourceFile("//bin/lld"), SourceFile("//bin/link_wrapper.py")});
|
||||
+ toolchain_with_inputs.SetTool(std::move(link));
|
||||
+
|
||||
+ toolchain_with_inputs.ToolchainSetupComplete();
|
||||
+
|
||||
+ Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
|
||||
+ target.sources().push_back(SourceFile("//foo/source.cc"));
|
||||
+ target.set_output_type(Target::EXECUTABLE);
|
||||
+ target.visibility().SetPublic();
|
||||
+ target.SetToolchain(&toolchain_with_inputs);
|
||||
+ ASSERT_TRUE(target.OnResolved(&err));
|
||||
+
|
||||
+ std::ostringstream out;
|
||||
+ NinjaBinaryTargetWriter writer(&target, out);
|
||||
+ writer.Run();
|
||||
+
|
||||
+ const char expected[] =
|
||||
+ "defines =\n"
|
||||
+ "include_dirs =\n"
|
||||
+ "root_out_dir = .\n"
|
||||
+ "target_output_name = bar\n"
|
||||
+ "\n"
|
||||
+ "build obj/foo/bar.source.o: cxx ../../foo/source.cc | "
|
||||
+ "../../bin/clang++\n"
|
||||
+ " source_file_part = source.cc\n"
|
||||
+ " source_name_part = source\n"
|
||||
+ "\n"
|
||||
+ "build ./bar: link obj/foo/bar.source.o | "
|
||||
+ "phony/link_inputs\n"
|
||||
+ " ldflags =\n"
|
||||
+ " libs =\n"
|
||||
+ " frameworks =\n"
|
||||
+ " swiftmodules =\n"
|
||||
+ " output_extension =\n"
|
||||
+ " output_dir =\n";
|
||||
+ std::string out_str = out.str();
|
||||
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
|
||||
+}
|
||||
diff --git a/src/gn/ninja_rust_binary_target_writer.cc b/src/gn/ninja_rust_binary_target_writer.cc
|
||||
index ba6b4169..cbb5e4ff 100644
|
||||
--- a/src/gn/ninja_rust_binary_target_writer.cc
|
||||
+++ b/src/gn/ninja_rust_binary_target_writer.cc
|
||||
@@ -139,6 +139,12 @@ void NinjaRustBinaryTargetWriter::Run() {
|
||||
implicit_deps.Append(classified_deps.extra_object_files.begin(),
|
||||
classified_deps.extra_object_files.end());
|
||||
|
||||
+ if (auto phony = tool_->inputs_phony_or_file(rule_prefix_,
|
||||
+ *settings_->build_settings());
|
||||
+ phony) {
|
||||
+ implicit_deps.emplace_back(std::move(*phony));
|
||||
+ }
|
||||
+
|
||||
std::vector<OutputFile> rustdeps;
|
||||
std::vector<OutputFile> nonrustdeps;
|
||||
std::vector<OutputFile> swiftmodules;
|
||||
@@ -213,7 +219,7 @@ void NinjaRustBinaryTargetWriter::Run() {
|
||||
SubstitutionWriter::ApplyListToLinkerAsOutputFile(
|
||||
target_, tool_, tool_->outputs(), &tool_outputs);
|
||||
WriteCompilerBuildLine({target_->rust_values().crate_root()},
|
||||
- implicit_deps.vector(), order_only_deps, tool_->name(),
|
||||
+ implicit_deps.vector(), order_only_deps, tool_,
|
||||
tool_outputs);
|
||||
|
||||
std::vector<const Target*> extern_deps(
|
||||
diff --git a/src/gn/ninja_toolchain_writer.cc b/src/gn/ninja_toolchain_writer.cc
|
||||
index 917d0681..fb04b954 100644
|
||||
--- a/src/gn/ninja_toolchain_writer.cc
|
||||
+++ b/src/gn/ninja_toolchain_writer.cc
|
||||
@@ -119,6 +119,22 @@ void NinjaToolchainWriter::WriteToolRule(Tool* tool,
|
||||
|
||||
if (tool->restat())
|
||||
out_ << kIndent << "restat = 1" << std::endl;
|
||||
+
|
||||
+ // If the size is exactly 1, we don't need a phony rule, since we just write
|
||||
+ // the input file directly in the build action.
|
||||
+ if (tool->inputs().size() > 1) {
|
||||
+ out_ << "build ";
|
||||
+ path_output_.WriteFile(
|
||||
+ out_,
|
||||
+ *tool->inputs_phony_or_file(rule_prefix, *settings_->build_settings()));
|
||||
+ out_ << ": phony";
|
||||
+ for (const auto& input : tool->inputs()) {
|
||||
+ out_ << " ";
|
||||
+ path_output_.WriteFile(out_,
|
||||
+ OutputFile(settings_->build_settings(), input));
|
||||
+ }
|
||||
+ out_ << std::endl;
|
||||
+ }
|
||||
}
|
||||
|
||||
void NinjaToolchainWriter::WriteRulePattern(const char* name,
|
||||
diff --git a/src/gn/ninja_toolchain_writer.h b/src/gn/ninja_toolchain_writer.h
|
||||
index cbc7c688..f734cfe5 100644
|
||||
--- a/src/gn/ninja_toolchain_writer.h
|
||||
+++ b/src/gn/ninja_toolchain_writer.h
|
||||
@@ -31,6 +31,7 @@ class NinjaToolchainWriter {
|
||||
private:
|
||||
FRIEND_TEST_ALL_PREFIXES(NinjaToolchainWriter, WriteToolRule);
|
||||
FRIEND_TEST_ALL_PREFIXES(NinjaToolchainWriter, WriteToolRuleWithLauncher);
|
||||
+ FRIEND_TEST_ALL_PREFIXES(NinjaToolchainWriter, WriteToolRuleWithInputsPhony);
|
||||
|
||||
NinjaToolchainWriter(const Settings* settings,
|
||||
const Toolchain* toolchain,
|
||||
diff --git a/src/gn/ninja_toolchain_writer_unittest.cc b/src/gn/ninja_toolchain_writer_unittest.cc
|
||||
index 863c1744..7c46dcd3 100644
|
||||
--- a/src/gn/ninja_toolchain_writer_unittest.cc
|
||||
+++ b/src/gn/ninja_toolchain_writer_unittest.cc
|
||||
@@ -38,3 +38,28 @@ TEST(NinjaToolchainWriter, WriteToolRuleWithLauncher) {
|
||||
"-o ${out}\n",
|
||||
stream.str());
|
||||
}
|
||||
+
|
||||
+TEST(NinjaToolchainWriter, WriteToolRuleWithInputsPhony) {
|
||||
+ TestWithScope setup;
|
||||
+
|
||||
+ std::unique_ptr<Tool> tool = Tool::CreateTool(CTool::kCToolCxx);
|
||||
+ TestWithScope::SetCommandForTool(
|
||||
+ "launcher c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} "
|
||||
+ "{{include_dirs}} -o {{output}}",
|
||||
+ tool.get());
|
||||
+ tool->set_inputs(
|
||||
+ {SourceFile("//bin/clang++"), SourceFile("//bin/plugin.so")});
|
||||
+
|
||||
+ std::ostringstream stream;
|
||||
+ NinjaToolchainWriter writer(setup.settings(), setup.toolchain(), stream);
|
||||
+ writer.WriteToolRule(tool.get(), std::string("prefix_"));
|
||||
+
|
||||
+ EXPECT_EQ(
|
||||
+ "rule prefix_cxx\n"
|
||||
+ " command = launcher c++ ${in} ${cflags} ${cflags_cc} ${defines} "
|
||||
+ "${include_dirs} "
|
||||
+ "-o ${out}\n"
|
||||
+ "build phony/prefix_cxx_inputs: phony ../../bin/clang++ "
|
||||
+ "../../bin/plugin.so\n",
|
||||
+ stream.str());
|
||||
+}
|
||||
diff --git a/src/gn/tool.cc b/src/gn/tool.cc
|
||||
index 684dc3e3..52b6c4ea 100644
|
||||
--- a/src/gn/tool.cc
|
||||
+++ b/src/gn/tool.cc
|
||||
@@ -4,12 +4,15 @@
|
||||
|
||||
#include "gn/tool.h"
|
||||
|
||||
+#include "base/strings/stringprintf.h"
|
||||
#include "gn/builtin_tool.h"
|
||||
#include "gn/c_tool.h"
|
||||
#include "gn/general_tool.h"
|
||||
+#include "gn/output_file.h"
|
||||
#include "gn/rust_tool.h"
|
||||
#include "gn/settings.h"
|
||||
#include "gn/target.h"
|
||||
+#include "gn/value_extractors.h"
|
||||
|
||||
const char* Tool::kToolNone = "";
|
||||
|
||||
@@ -199,6 +202,33 @@ bool Tool::ReadOutputExtension(Scope* scope, Err* err) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+bool Tool::ReadInputs(Scope* scope, Err* err) {
|
||||
+ DCHECK(!complete_);
|
||||
+ const Value* value = scope->GetValue("inputs", true);
|
||||
+ if (!value)
|
||||
+ return true; // Not present is fine.
|
||||
+
|
||||
+ std::vector<SourceFile> inputs;
|
||||
+ if (!ExtractListOfRelativeFiles(scope->settings()->build_settings(), *value,
|
||||
+ scope->GetSourceDir(), &inputs, err)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ set_inputs(std::move(inputs));
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+std::optional<OutputFile> Tool::inputs_phony_or_file(
|
||||
+ std::string_view rule_prefix,
|
||||
+ const BuildSettings& build_settings) const {
|
||||
+ if (inputs_.size() == 1) {
|
||||
+ return OutputFile(&build_settings, inputs_[0]);
|
||||
+ } else if (inputs_.size() > 1) {
|
||||
+ return OutputFile(base::StringPrintf(
|
||||
+ "phony/%s%s_inputs", std::string(rule_prefix).c_str(), name_));
|
||||
+ }
|
||||
+ return std::nullopt;
|
||||
+}
|
||||
+
|
||||
bool Tool::InitTool(Scope* scope, Toolchain* toolchain, Err* err) {
|
||||
if (!ReadPattern(scope, "command", &command_, err) ||
|
||||
!ReadString(scope, "command_launcher", &command_launcher_, err) ||
|
||||
@@ -211,7 +241,8 @@ bool Tool::InitTool(Scope* scope, Toolchain* toolchain, Err* err) {
|
||||
!ReadBool(scope, "restat", &restat_, err) ||
|
||||
!ReadPattern(scope, "rspfile", &rspfile_, err) ||
|
||||
!ReadPattern(scope, "rspfile_content", &rspfile_content_, err) ||
|
||||
- !ReadLabel(scope, "pool", toolchain->label(), &pool_, err)) {
|
||||
+ !ReadLabel(scope, "pool", toolchain->label(), &pool_, err) ||
|
||||
+ !ReadInputs(scope, err)) {
|
||||
return false;
|
||||
}
|
||||
const bool command_is_required = name_ != GeneralTool::kGeneralToolAction;
|
||||
diff --git a/src/gn/tool.h b/src/gn/tool.h
|
||||
index 68e919cd..d0825416 100644
|
||||
--- a/src/gn/tool.h
|
||||
+++ b/src/gn/tool.h
|
||||
@@ -5,11 +5,14 @@
|
||||
#ifndef TOOLS_GN_TOOL_H_
|
||||
#define TOOLS_GN_TOOL_H_
|
||||
|
||||
+#include <optional>
|
||||
#include <string>
|
||||
+#include <vector>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "gn/label.h"
|
||||
#include "gn/label_ptr.h"
|
||||
+#include "gn/output_file.h"
|
||||
#include "gn/scope.h"
|
||||
#include "gn/source_file.h"
|
||||
#include "gn/substitution_list.h"
|
||||
@@ -224,6 +227,16 @@ class Tool {
|
||||
const LabelPtrPair<Pool>& pool() const { return pool_; }
|
||||
void set_pool(LabelPtrPair<Pool> pool) { pool_ = std::move(pool); }
|
||||
|
||||
+ const std::vector<SourceFile>& inputs() const { return inputs_; }
|
||||
+ void set_inputs(std::vector<SourceFile> inputs) {
|
||||
+ DCHECK(!complete_);
|
||||
+ inputs_ = std::move(inputs);
|
||||
+ }
|
||||
+
|
||||
+ std::optional<OutputFile> inputs_phony_or_file(
|
||||
+ std::string_view rule_prefix,
|
||||
+ const BuildSettings& build_settings) const;
|
||||
+
|
||||
// Other functions ----------------------------------------------------------
|
||||
|
||||
// Function for the above override to call to complete the tool.
|
||||
@@ -277,6 +290,7 @@ class Tool {
|
||||
LabelPtrPair<Pool>* field,
|
||||
Err* err);
|
||||
bool ReadOutputExtension(Scope* scope, Err* err);
|
||||
+ bool ReadInputs(Scope* scope, Err* err);
|
||||
|
||||
const ParseNode* defined_from_ = nullptr;
|
||||
const char* name_ = nullptr;
|
||||
@@ -303,6 +317,7 @@ class Tool {
|
||||
SubstitutionPattern rspfile_;
|
||||
SubstitutionPattern rspfile_content_;
|
||||
LabelPtrPair<Pool> pool_;
|
||||
+ std::vector<SourceFile> inputs_;
|
||||
|
||||
bool complete_ = false;
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
maintainer="lauren n. liberda <lauren@selfisekai.rocks>"
|
||||
pkgname=gn
|
||||
pkgver=0_git20251217
|
||||
pkgrel=0
|
||||
pkgrel=1
|
||||
_commit=64d35867ca0a1088f13de8f4ccaf1a5687d7f1ce
|
||||
pkgdesc="Meta-build system that generates build files for Ninja"
|
||||
arch="all"
|
||||
@ -12,6 +12,9 @@ depends="samurai"
|
||||
makedepends="python3 zstd"
|
||||
# gitiles has no clones
|
||||
source="https://ab-sn.lnl.gay/gn-$_commit.tar.zst
|
||||
0001-Add-function-expand_directory-to-gn.patch
|
||||
0002-Reject-newlines-in-string-config-values-defines-cfla.patch
|
||||
0003-Add-inputs-parameter-to-tool.patch
|
||||
"
|
||||
builddir="$srcdir/gn"
|
||||
|
||||
@ -56,4 +59,7 @@ package() {
|
||||
|
||||
sha512sums="
|
||||
a9377c649fb0b6c88ac409d64c3aa8c8e2ca9230cde80e653a51bd4ac086a91a6a293331b9cfcf9900c8856ca803b5abd81195329d2fa0530382e1572aa4474e gn-64d35867ca0a1088f13de8f4ccaf1a5687d7f1ce.tar.zst
|
||||
56640817f1e22e6ae067bc6f9b740434b93b3cc24b9786396c8563f20fbff8006c6e2c220966c517a1d26850b7609f5b237109e6d1441d2caa198cfdcdde707c 0001-Add-function-expand_directory-to-gn.patch
|
||||
30b164da79fe76cf78c6c78879ccb075c0c999c69ca71e52bc7f9b498bf739041110a5d69509fc1fee50714a667ddddb0afcf0d9892e6d5993fd6d803e014503 0002-Reject-newlines-in-string-config-values-defines-cfla.patch
|
||||
1d4dfa33fbc320a00caf54004c6f20ac026f70ab78dd3873231d51911e8486e203be530d5591a38801da806b0541b25797e95a954d5c173f42212d931b408bf1 0003-Add-inputs-parameter-to-tool.patch
|
||||
"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user