summaryrefslogtreecommitdiff
path: root/gn
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-05-16 09:59:13 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-05-20 10:28:53 +0000
commit6c11fb357ec39bf087b8b632e2b1e375aef1b38b (patch)
treec8315530db18a8ee566521c39ab8a6af4f72bc03 /gn
parent3ffaed019d0772e59d6cdb2d0d32fe4834c31f72 (diff)
downloadqtwebengine-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.template2
-rw-r--r--gn/build/build_openbsd.ninja.template19
-rwxr-xr-xgn/build/gen.py7
-rw-r--r--gn/tools/gn/args.cc2
-rw-r--r--gn/tools/gn/command_gen.cc17
-rw-r--r--gn/tools/gn/compile_commands_writer.cc52
-rw-r--r--gn/tools/gn/compile_commands_writer.h15
-rw-r--r--gn/tools/gn/compile_commands_writer_unittest.cc53
-rw-r--r--gn/tools/gn/escape.cc199
-rw-r--r--gn/tools/gn/metadata_walk_unittest.cc4
-rw-r--r--gn/tools/gn/parser.cc11
-rw-r--r--gn/tools/gn/parser.h2
-rw-r--r--gn/tools/gn/target.cc14
-rw-r--r--gn/tools/gn/target_unittest.cc4
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();