diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-05-16 09:59:13 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-05-20 10:28:53 +0000 |
commit | 6c11fb357ec39bf087b8b632e2b1e375aef1b38b (patch) | |
tree | c8315530db18a8ee566521c39ab8a6af4f72bc03 /gn | |
parent | 3ffaed019d0772e59d6cdb2d0d32fe4834c31f72 (diff) | |
download | qtwebengine-chromium-6c11fb357ec39bf087b8b632e2b1e375aef1b38b.tar.gz |
BASELINE: Update Chromium to 74.0.3729.159
Change-Id: I8d2497da544c275415aedd94dd25328d555de811
Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'gn')
-rw-r--r-- | gn/build/build_mac.ninja.template | 2 | ||||
-rw-r--r-- | gn/build/build_openbsd.ninja.template | 19 | ||||
-rwxr-xr-x | gn/build/gen.py | 7 | ||||
-rw-r--r-- | gn/tools/gn/args.cc | 2 | ||||
-rw-r--r-- | gn/tools/gn/command_gen.cc | 17 | ||||
-rw-r--r-- | gn/tools/gn/compile_commands_writer.cc | 52 | ||||
-rw-r--r-- | gn/tools/gn/compile_commands_writer.h | 15 | ||||
-rw-r--r-- | gn/tools/gn/compile_commands_writer_unittest.cc | 53 | ||||
-rw-r--r-- | gn/tools/gn/escape.cc | 199 | ||||
-rw-r--r-- | gn/tools/gn/metadata_walk_unittest.cc | 4 | ||||
-rw-r--r-- | gn/tools/gn/parser.cc | 11 | ||||
-rw-r--r-- | gn/tools/gn/parser.h | 2 | ||||
-rw-r--r-- | gn/tools/gn/target.cc | 14 | ||||
-rw-r--r-- | gn/tools/gn/target_unittest.cc | 4 |
14 files changed, 298 insertions, 103 deletions
diff --git a/gn/build/build_mac.ninja.template b/gn/build/build_mac.ninja.template index ff82eb88c1d..e7dedac2f14 100644 --- a/gn/build/build_mac.ninja.template +++ b/gn/build/build_mac.ninja.template @@ -11,7 +11,7 @@ rule cxx deps = gcc rule alink_thin - command = rm -f $out && libtool -static -o $out $in + command = rm -f $out && $ar rcs $out $in description = AR $out rule link diff --git a/gn/build/build_openbsd.ninja.template b/gn/build/build_openbsd.ninja.template new file mode 100644 index 00000000000..f22ccb327a8 --- /dev/null +++ b/gn/build/build_openbsd.ninja.template @@ -0,0 +1,19 @@ +rule cc + command = $cc -MMD -MF $out.d $defines $includes $cflags $cflags_c -c $in -o $out + description = CC $out + depfile = $out.d + deps = gcc + +rule cxx + command = $cxx -MMD -MF $out.d $defines $includes $cflags $cflags_cc -c $in -o $out + description = CXX $out + depfile = $out.d + deps = gcc + +rule alink_thin + command = rm -f $out && $ar rcs $out $in + description = AR $out + +rule link + command = $ld $ldflags -o $out -Wl,--start-group $in $libs -Wl,--end-group $solibs + description = LINK $out diff --git a/gn/build/gen.py b/gn/build/gen.py index 3edefa7dc60..d547a8ff83e 100755 --- a/gn/build/gen.py +++ b/gn/build/gen.py @@ -41,10 +41,12 @@ class Platform(object): self._platform = 'fuchsia' elif self._platform.startswith('freebsd'): self._platform = 'freebsd' + elif self._platform.startswith('openbsd'): + self._platform = 'openbsd' @staticmethod def known_platforms(): - return ['linux', 'darwin', 'msvc', 'aix', 'fuchsia'] + return ['linux', 'darwin', 'msvc', 'aix', 'fuchsia', 'openbsd'] def platform(self): return self._platform @@ -68,7 +70,7 @@ class Platform(object): return self._platform == 'aix' def is_posix(self): - return self._platform in ['linux', 'freebsd', 'darwin', 'aix'] + return self._platform in ['linux', 'freebsd', 'darwin', 'aix', 'openbsd'] def main(argv): @@ -173,6 +175,7 @@ def WriteGenericNinja(path, static_libraries, executables, 'linux': 'build_linux.ninja.template', 'freebsd': 'build_linux.ninja.template', 'aix': 'build_aix.ninja.template', + 'openbsd': 'build_openbsd.ninja.template', }[platform.platform()]) with open(template_filename) as f: diff --git a/gn/tools/gn/args.cc b/gn/tools/gn/args.cc index 5889c8fcf68..d1d7611eb4d 100644 --- a/gn/tools/gn/args.cc +++ b/gn/tools/gn/args.cc @@ -298,6 +298,8 @@ void Args::SetSystemVarsLocked(Scope* dest) const { os = "freebsd"; #elif defined(OS_AIX) os = "aix"; +#elif defined(OS_OPENBSD) + os = "openbsd"; #else #error Unknown OS type. #endif diff --git a/gn/tools/gn/command_gen.cc b/gn/tools/gn/command_gen.cc index 46d8b897d4e..200aad80b29 100644 --- a/gn/tools/gn/command_gen.cc +++ b/gn/tools/gn/command_gen.cc @@ -294,9 +294,11 @@ bool RunCompileCommandsWriter(const BuildSettings* build_settings, base::ElapsedTimer timer; std::string file_name = "compile_commands.json"; + std::string target_filters = + command_line->GetSwitchValueASCII(kSwitchExportCompileCommands); - bool res = CompileCommandsWriter::RunAndWriteFiles(build_settings, builder, - file_name, quiet, err); + bool res = CompileCommandsWriter::RunAndWriteFiles( + build_settings, builder, file_name, target_filters, quiet, err); if (res && !quiet) { OutputString("Generating compile_commands took " + base::Int64ToString(timer.Elapsed().InMilliseconds()) + @@ -420,12 +422,15 @@ Generic JSON Output Compilation Database - --export-compile-commands + --export-compile-commands[=<target_name1,target_name2...>] Produces a compile_commands.json file in the root of the build directory containing an array of “command objects”, where each command object - specifies one way a translation unit is compiled in the project. This is - used for various Clang-based tooling, allowing for the replay of individual - compilations independent of the build system. + specifies one way a translation unit is compiled in the project. If a list + of target_name is supplied, only targets that are reachable from the list + of target_name will be used for “command objects” generation, otherwise + all available targets will be used. This is used for various Clang-based + tooling, allowing for the replay of individual compilations independent + of the build system. )"; int RunGen(const std::vector<std::string>& args) { diff --git a/gn/tools/gn/compile_commands_writer.cc b/gn/tools/gn/compile_commands_writer.cc index 0a545e8f1f4..00eb00a3298 100644 --- a/gn/tools/gn/compile_commands_writer.cc +++ b/gn/tools/gn/compile_commands_writer.cc @@ -8,8 +8,10 @@ #include "base/json/string_escape.h" #include "base/strings/stringprintf.h" +#include "base/strings/string_split.h" #include "tools/gn/builder.h" #include "tools/gn/config_values_extractors.h" +#include "tools/gn/deps_iterator.h" #include "tools/gn/escape.h" #include "tools/gn/filesystem_utils.h" #include "tools/gn/ninja_target_command_util.h" @@ -267,6 +269,7 @@ bool CompileCommandsWriter::RunAndWriteFiles( const BuildSettings* build_settings, const Builder& builder, const std::string& file_name, + const std::string& target_filters, bool quiet, Err* err) { SourceFile output_file = build_settings->build_dir().ResolveRelativeFile( @@ -278,9 +281,56 @@ bool CompileCommandsWriter::RunAndWriteFiles( std::vector<const Target*> all_targets = builder.GetAllResolvedTargets(); + std::set<std::string> target_filters_set; + for (auto& target : + base::SplitString(target_filters, ",", base::TRIM_WHITESPACE, + base::SPLIT_WANT_NONEMPTY)) { + target_filters_set.insert(target); + } std::string json; - RenderJSON(build_settings, all_targets, &json); + if (target_filters_set.empty()) { + RenderJSON(build_settings, all_targets, &json); + } else { + std::vector<const Target*> preserved_targets = + FilterTargets(all_targets, target_filters_set); + RenderJSON(build_settings, preserved_targets, &json); + } + if (!WriteFileIfChanged(output_path, json, err)) return false; return true; + } + +std::vector<const Target*> CompileCommandsWriter::FilterTargets( + const std::vector<const Target*>& all_targets, + const std::set<std::string>& target_filters_set) { + std::vector<const Target*> preserved_targets; + + std::set<const Target*> visited; + for (auto& target : all_targets) { + if (target_filters_set.count(target->label().name())) { + VisitDeps(target, &visited); + } + } + + preserved_targets.reserve(visited.size()); + // Preserve the original ordering of all_targets + // to allow easier debugging and testing. + for (auto& target : all_targets) { + if (visited.count(target)) { + preserved_targets.push_back(target); + } + } + return preserved_targets; +} + +void CompileCommandsWriter::VisitDeps(const Target* target, + std::set<const Target*>* visited) { + if (!visited->count(target)) { + visited->insert(target); + for (const auto& pair : target->GetDeps(Target::DEPS_ALL)) { + VisitDeps(pair.ptr, visited); + } + } +}
\ No newline at end of file diff --git a/gn/tools/gn/compile_commands_writer.h b/gn/tools/gn/compile_commands_writer.h index 2f1ec834877..5c9f0d5b0b0 100644 --- a/gn/tools/gn/compile_commands_writer.h +++ b/gn/tools/gn/compile_commands_writer.h @@ -13,14 +13,29 @@ class BuildSettings; class CompileCommandsWriter { public: + // Write compile commands into a json file located by parameter file_name. + // + // Parameter target_filters should be in "target_name1,target_name2..." + // format. If it is not empty, only targets that are reachable from targets + // in target_filters are used to generate compile commands. + // + // Parameter quiet is not used. static bool RunAndWriteFiles(const BuildSettings* build_setting, const Builder& builder, const std::string& file_name, + const std::string& target_filters, bool quiet, Err* err); static void RenderJSON(const BuildSettings* build_settings, std::vector<const Target*>& all_targets, std::string* compile_commands); + static std::vector<const Target*> FilterTargets( + const std::vector<const Target*>& all_targets, + const std::set<std::string>& target_filters_set); + + private: + // This fuction visits the deps graph of a target in a DFS fashion. + static void VisitDeps(const Target* target, std::set<const Target*>* visited); }; #endif // TOOLS_GN_COMPILE_COMMANDS_WRITER_H_ diff --git a/gn/tools/gn/compile_commands_writer_unittest.cc b/gn/tools/gn/compile_commands_writer_unittest.cc index b162ba5de83..90429a47155 100644 --- a/gn/tools/gn/compile_commands_writer_unittest.cc +++ b/gn/tools/gn/compile_commands_writer_unittest.cc @@ -588,3 +588,56 @@ TEST_F(CompileCommandsTest, EscapedFlags) { #endif EXPECT_EQ(expected, out); } + +TEST_F(CompileCommandsTest, CompDBFilter) { + Err err; + + std::vector<const Target*> targets; + Target target1(settings(), Label(SourceDir("//foo/"), "bar1")); + target1.set_output_type(Target::SOURCE_SET); + target1.sources().push_back(SourceFile("//foo/input1.c")); + target1.config_values().cflags_c().push_back("-DCONFIG=\"/config\""); + target1.SetToolchain(toolchain()); + ASSERT_TRUE(target1.OnResolved(&err)); + targets.push_back(&target1); + + Target target2(settings(), Label(SourceDir("//foo/"), "bar2")); + target2.set_output_type(Target::SOURCE_SET); + target2.sources().push_back(SourceFile("//foo/input2.c")); + target2.config_values().cflags_c().push_back("-DCONFIG=\"/config\""); + target2.SetToolchain(toolchain()); + ASSERT_TRUE(target2.OnResolved(&err)); + targets.push_back(&target2); + + Target target3(settings(), Label(SourceDir("//foo/"), "bar3")); + target3.set_output_type(Target::SOURCE_SET); + target3.sources().push_back(SourceFile("//foo/input3.c")); + target3.config_values().cflags_c().push_back("-DCONFIG=\"/config\""); + target3.SetToolchain(toolchain()); + ASSERT_TRUE(target3.OnResolved(&err)); + targets.push_back(&target3); + + target1.private_deps().push_back(LabelTargetPair(&target2)); + target1.private_deps().push_back(LabelTargetPair(&target3)); + + CompileCommandsWriter writer; + + std::set<std::string> filter1; + std::vector<const Target*> test_results1 = + writer.FilterTargets(targets, filter1); + ASSERT_TRUE(test_results1.empty()); + + std::set<std::string> filter2; + filter2.insert(target1.label().name()); + std::vector<const Target*> test_results2 = + writer.FilterTargets(targets, filter2); + ASSERT_EQ(test_results2, targets); + + std::set<std::string> filter3; + filter3.insert(target2.label().name()); + std::vector<const Target*> test_result3 = + writer.FilterTargets(targets, filter3); + std::vector<const Target*> expected_results3; + expected_results3.push_back(&target2); + ASSERT_EQ(test_result3, expected_results3); +} diff --git a/gn/tools/gn/escape.cc b/gn/tools/gn/escape.cc index 53c8d898c5b..aa6b967eb98 100644 --- a/gn/tools/gn/escape.cc +++ b/gn/tools/gn/escape.cc @@ -6,56 +6,85 @@ #include <stddef.h> +#include <memory> + +#include "base/compiler_specific.h" #include "base/logging.h" #include "util/build_config.h" namespace { +constexpr size_t kStackStringBufferSize = 1024; +#if defined(OS_WIN) +constexpr size_t kMaxEscapedCharsPerChar = 2; +#else +constexpr size_t kMaxEscapedCharsPerChar = 3; +#endif + // A "1" in this lookup table means that char is valid in the Posix shell. +// clang-format off const char kShellValid[0x80] = { - // 00-1f: all are invalid - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - // ' ' ! " # $ % & ' ( ) * + , - . / +// 00-1f: all are invalid + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// ' ' ! " # $ % & ' ( ) * + , - . / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, - // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? +// 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, - // @ A B C D E F G H I J K L M N O +// @ A B C D E F G H I J K L M N O 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - // P Q R S T U V W X Y Z [ \ ] ^ _ +// P Q R S T U V W X Y Z [ \ ] ^ _ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, - // ` a b c d e f g h i j k l m n o +// ` a b c d e f g h i j k l m n o 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - // p q r s t u v w x y z { | } ~ +// p q r s t u v w x y z { | } ~ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}; +// clang-format on + +// Uses the stack if the space needed is small and the heap otherwise. +class StackOrHeapBuffer { + public: + explicit StackOrHeapBuffer(size_t buf_size) { + if (UNLIKELY(buf_size > kStackStringBufferSize)) + heap_buf.reset(new char[buf_size]); + } + operator char*() { return heap_buf ? heap_buf.get() : stack_buf; } + + private: + char stack_buf[kStackStringBufferSize]; + std::unique_ptr<char[]> heap_buf; +}; -// Append one character to the given string, escaping it for Ninja. -// // Ninja's escaping rules are very simple. We always escape colons even // though they're OK in many places, in case the resulting string is used on // the left-hand-side of a rule. -inline void NinjaEscapeChar(char ch, std::string* dest) { - if (ch == '$' || ch == ' ' || ch == ':') - dest->push_back('$'); - dest->push_back(ch); +inline bool ShouldEscapeCharForNinja(char ch) { + return ch == '$' || ch == ' ' || ch == ':'; } -void EscapeStringToString_Ninja(const base::StringPiece& str, - const EscapeOptions& options, - std::string* dest, - bool* needed_quoting) { - for (const auto& elem : str) - NinjaEscapeChar(elem, dest); +size_t EscapeStringToString_Ninja(const base::StringPiece& str, + const EscapeOptions& options, + char* dest, + bool* needed_quoting) { + size_t i = 0; + for (const auto& elem : str) { + if (ShouldEscapeCharForNinja(elem)) + dest[i++] = '$'; + dest[i++] = elem; + } + return i; } -void EscapeStringToString_NinjaPreformatted(const base::StringPiece& str, - std::string* dest) { +size_t EscapeStringToString_NinjaPreformatted(const base::StringPiece& str, + char* dest) { // Only Ninja-escape $. + size_t i = 0; for (const auto& elem : str) { if (elem == '$') - dest->push_back('$'); - dest->push_back(elem); + dest[i++] = '$'; + dest[i++] = elem; } + return i; } // Escape for CommandLineToArgvW and additionally escape Ninja characters. @@ -66,119 +95,124 @@ void EscapeStringToString_NinjaPreformatted(const base::StringPiece& str, // See: // http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx // http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx -void EscapeStringToString_WindowsNinjaFork(const base::StringPiece& str, - const EscapeOptions& options, - std::string* dest, - bool* needed_quoting) { +size_t EscapeStringToString_WindowsNinjaFork(const base::StringPiece& str, + const EscapeOptions& options, + char* dest, + bool* needed_quoting) { // We assume we don't have any whitespace chars that aren't spaces. DCHECK(str.find_first_of("\r\n\v\t") == std::string::npos); + size_t i = 0; if (str.find_first_of(" \"") == std::string::npos) { // Simple case, don't quote. - EscapeStringToString_Ninja(str, options, dest, needed_quoting); + return EscapeStringToString_Ninja(str, options, dest, needed_quoting); } else { if (!options.inhibit_quoting) - dest->push_back('"'); + dest[i++] = '"'; - for (size_t i = 0; i < str.size(); i++) { + for (size_t j = 0; j < str.size(); j++) { // Count backslashes in case they're followed by a quote. size_t backslash_count = 0; - while (i < str.size() && str[i] == '\\') { - i++; + while (j < str.size() && str[j] == '\\') { + j++; backslash_count++; } - if (i == str.size()) { + if (j == str.size()) { // Backslashes at end of string. Backslash-escape all of them since // they'll be followed by a quote. - dest->append(backslash_count * 2, '\\'); - } else if (str[i] == '"') { + memset(dest + i, '\\', backslash_count * 2); + i += backslash_count * 2; + } else if (str[j] == '"') { // 0 or more backslashes followed by a quote. Backslash-escape the // backslashes, then backslash-escape the quote. - dest->append(backslash_count * 2 + 1, '\\'); - dest->push_back('"'); + memset(dest + i, '\\', backslash_count * 2 + 1); + i += backslash_count * 2 + 1; + dest[i++] = '"'; } else { // Non-special Windows character, just escape for Ninja. Also, add any // backslashes we read previously, these are literals. - dest->append(backslash_count, '\\'); - NinjaEscapeChar(str[i], dest); + memset(dest + i, '\\', backslash_count); + i += backslash_count; + if (ShouldEscapeCharForNinja(str[j])) + dest[i++] = '$'; + dest[i++] = str[j]; } } if (!options.inhibit_quoting) - dest->push_back('"'); + dest[i++] = '"'; if (needed_quoting) *needed_quoting = true; } + return i; } -void EscapeStringToString_PosixNinjaFork(const base::StringPiece& str, - const EscapeOptions& options, - std::string* dest, - bool* needed_quoting) { +size_t EscapeStringToString_PosixNinjaFork(const base::StringPiece& str, + const EscapeOptions& options, + char* dest, + bool* needed_quoting) { + size_t i = 0; for (const auto& elem : str) { if (elem == '$' || elem == ' ') { // Space and $ are special to both Ninja and the shell. '$' escape for // Ninja, then backslash-escape for the shell. - dest->push_back('\\'); - dest->push_back('$'); - dest->push_back(elem); + dest[i++] = '\\'; + dest[i++] = '$'; + dest[i++] = elem; } else if (elem == ':') { // Colon is the only other Ninja special char, which is not special to // the shell. - dest->push_back('$'); - dest->push_back(':'); + dest[i++] = '$'; + dest[i++] = ':'; } else if (static_cast<unsigned>(elem) >= 0x80 || !kShellValid[static_cast<int>(elem)]) { // All other invalid shell chars get backslash-escaped. - dest->push_back('\\'); - dest->push_back(elem); + dest[i++] = '\\'; + dest[i++] = elem; } else { // Everything else is a literal. - dest->push_back(elem); + dest[i++] = elem; } } + return i; } -void EscapeStringToString(const base::StringPiece& str, - const EscapeOptions& options, - std::string* dest, - bool* needed_quoting) { +// Escapes |str| into |dest| and returns the number of characters written. +size_t EscapeStringToString(const base::StringPiece& str, + const EscapeOptions& options, + char* dest, + bool* needed_quoting) { switch (options.mode) { case ESCAPE_NONE: - dest->append(str.data(), str.size()); - break; + strncpy(dest, str.data(), str.size()); + return str.size(); case ESCAPE_NINJA: - EscapeStringToString_Ninja(str, options, dest, needed_quoting); - break; + return EscapeStringToString_Ninja(str, options, dest, needed_quoting); case ESCAPE_NINJA_COMMAND: switch (options.platform) { case ESCAPE_PLATFORM_CURRENT: #if defined(OS_WIN) - EscapeStringToString_WindowsNinjaFork(str, options, dest, - needed_quoting); + return EscapeStringToString_WindowsNinjaFork(str, options, dest, + needed_quoting); #else - EscapeStringToString_PosixNinjaFork(str, options, dest, - needed_quoting); + return EscapeStringToString_PosixNinjaFork(str, options, dest, + needed_quoting); #endif - break; case ESCAPE_PLATFORM_WIN: - EscapeStringToString_WindowsNinjaFork(str, options, dest, - needed_quoting); - break; + return EscapeStringToString_WindowsNinjaFork(str, options, dest, + needed_quoting); case ESCAPE_PLATFORM_POSIX: - EscapeStringToString_PosixNinjaFork(str, options, dest, - needed_quoting); - break; + return EscapeStringToString_PosixNinjaFork(str, options, dest, + needed_quoting); default: NOTREACHED(); } - break; case ESCAPE_NINJA_PREFORMATTED_COMMAND: - EscapeStringToString_NinjaPreformatted(str, dest); - break; + return EscapeStringToString_NinjaPreformatted(str, dest); default: NOTREACHED(); } + return 0; } } // namespace @@ -186,17 +220,14 @@ void EscapeStringToString(const base::StringPiece& str, std::string EscapeString(const base::StringPiece& str, const EscapeOptions& options, bool* needed_quoting) { - std::string result; - result.reserve(str.size() + 4); // Guess we'll add a couple of extra chars. - EscapeStringToString(str, options, &result, needed_quoting); - return result; + StackOrHeapBuffer dest(str.size() * kMaxEscapedCharsPerChar); + return std::string(dest, + EscapeStringToString(str, options, dest, needed_quoting)); } void EscapeStringToStream(std::ostream& out, const base::StringPiece& str, const EscapeOptions& options) { - std::string escaped; - EscapeStringToString(str, options, &escaped, nullptr); - if (!escaped.empty()) - out.write(escaped.data(), escaped.size()); + StackOrHeapBuffer dest(str.size() * kMaxEscapedCharsPerChar); + out.write(dest, EscapeStringToString(str, options, dest, nullptr)); } diff --git a/gn/tools/gn/metadata_walk_unittest.cc b/gn/tools/gn/metadata_walk_unittest.cc index 634a2c564c1..a18a07e35d5 100644 --- a/gn/tools/gn/metadata_walk_unittest.cc +++ b/gn/tools/gn/metadata_walk_unittest.cc @@ -203,8 +203,8 @@ TEST(MetadataWalkTest, CollectWithError) { EXPECT_TRUE(result.empty()); EXPECT_TRUE(err.has_error()); EXPECT_EQ(err.message(), - "I was expecting //foo:missing to be a dependency of " - "//foo:one(//toolchain:default). " + "I was expecting //foo:missing(//toolchain:default) to be a " + "dependency of //foo:one(//toolchain:default). " "Make sure it's included in the deps or data_deps, and that you've " "specified the appropriate toolchain.") << err.message(); diff --git a/gn/tools/gn/parser.cc b/gn/tools/gn/parser.cc index e10ed41d159..0065afd7de7 100644 --- a/gn/tools/gn/parser.cc +++ b/gn/tools/gn/parser.cc @@ -221,6 +221,12 @@ Scopes always unequal by definition. )*"; +// Precedence constants. +// +// Currently all operators are left-associative so this list is sequential. To +// implement a right-assocative operators in a Pratt parser we would leave gaps +// in between the constants, and right-associative operators get a precedence +// of "<left-associated-precedence> - 1". enum Precedence { PRECEDENCE_ASSIGNMENT = 1, // Lowest precedence. PRECEDENCE_OR = 2, @@ -241,9 +247,8 @@ enum Precedence { // seen as either a prefix or infix operator, and if it's infix, what its // precedence is. // -// Refs: -// - http://javascript.crockford.com/tdop/tdop.html -// - +// References: +// http://javascript.crockford.com/tdop/tdop.html // http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ // Indexed by Token::Type. diff --git a/gn/tools/gn/parser.h b/gn/tools/gn/parser.h index 5ecbd9dc51e..a53717061b3 100644 --- a/gn/tools/gn/parser.h +++ b/gn/tools/gn/parser.h @@ -144,6 +144,8 @@ typedef std::unique_ptr<ParseNode> ( struct ParserHelper { PrefixFunc prefix; InfixFunc infix; + + // Used only for infix operators. int precedence; }; diff --git a/gn/tools/gn/target.cc b/gn/tools/gn/target.cc index 94fb994e277..376e09f0417 100644 --- a/gn/tools/gn/target.cc +++ b/gn/tools/gn/target.cc @@ -917,6 +917,7 @@ bool Target::GetMetadata(const std::vector<std::string>& keys_to_extract, // Gather walk keys and find the appropriate target. Targets identified in // the walk key set must be deps or data_deps of the declaring target. const DepsIteratorRange& all_deps = GetDeps(Target::DEPS_ALL); + const SourceDir current_dir("//"); for (const auto& next : next_walk_keys) { DCHECK(next.type() == Value::STRING); @@ -941,10 +942,19 @@ bool Target::GetMetadata(const std::vector<std::string>& keys_to_extract, } // Otherwise, look through the target's deps for the specified one. + // Canonicalize the label if possible. + Label next_label = + Label::Resolve(current_dir, settings()->toolchain_label(), next, err); + if (next_label.is_null()) { + *err = Err(next.origin(), std::string("Failed to canonicalize ") + + next.string_value() + std::string(".")); + } + std::string canonicalize_next_label = next_label.GetUserVisibleName(true); + bool found_next = false; for (const auto& dep : all_deps) { // Match against the label with the toolchain. - if (dep.label.GetUserVisibleName(true) == next.string_value()) { + if (dep.label.GetUserVisibleName(true) == canonicalize_next_label) { // If we haven't walked this dep yet, go down into it. auto pair = targets_walked->insert(dep.ptr); if (pair.second) { @@ -961,7 +971,7 @@ bool Target::GetMetadata(const std::vector<std::string>& keys_to_extract, // Propagate it back to the user. if (!found_next) { *err = Err(next.origin(), - std::string("I was expecting ") + next.string_value() + + std::string("I was expecting ") + canonicalize_next_label + std::string(" to be a dependency of ") + label().GetUserVisibleName(true) + ". Make sure it's included in the deps or data_deps, and " diff --git a/gn/tools/gn/target_unittest.cc b/gn/tools/gn/target_unittest.cc index 673422e92c8..b6ad0ff566b 100644 --- a/gn/tools/gn/target_unittest.cc +++ b/gn/tools/gn/target_unittest.cc @@ -1252,8 +1252,8 @@ TEST(TargetTest, CollectMetadataWithError) { &err); EXPECT_TRUE(err.has_error()); EXPECT_EQ(err.message(), - "I was expecting //foo:missing to be a dependency of " - "//foo:one(//toolchain:default). " + "I was expecting //foo:missing(//toolchain:default) to be a " + "dependency of //foo:one(//toolchain:default). " "Make sure it's included in the deps or data_deps, and that you've " "specified the appropriate toolchain.") << err.message(); |