summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-23 17:59:22 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-23 17:59:22 +0000
commitea3690cf973006fd3829c7032f71d4e8e4c47402 (patch)
treedaf2613a3b856cbc8e38480e4654ffa14181582e
parent7191e2211c96f02000bed9c449af72332e412ac0 (diff)
downloadchromium_src-ea3690cf973006fd3829c7032f71d4e8e4c47402.zip
chromium_src-ea3690cf973006fd3829c7032f71d4e8e4c47402.tar.gz
chromium_src-ea3690cf973006fd3829c7032f71d4e8e4c47402.tar.bz2
Replace to_build_path() with the more general rebase_path(). Use rebase_path to (finally) make grit paths work properly.
Add more colors to help, yay! I also removed a bunch of colons from headings since they look stupid with the colors. Add a new variable root_build_dir. Fix some bugs in the scope_per_file_provider that didn't include the toolchain subdirectory. Add some more tests for this. Add a --no-exec command-line option to skip executing scripts so one can see how fast things run without forking out to grit and friends. Add non-Linux build for expat. Other Windows build stuff for SSL, base BUG= R=scottmg@chromium.org Review URL: https://codereview.chromium.org/23618064 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@224747 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--tools/gn/BUILD.gn4
-rw-r--r--tools/gn/args.cc6
-rw-r--r--tools/gn/command_help.cc59
-rw-r--r--tools/gn/file_template.cc4
-rw-r--r--tools/gn/filesystem_utils.cc39
-rw-r--r--tools/gn/filesystem_utils.h5
-rw-r--r--tools/gn/filesystem_utils_unittest.cc50
-rw-r--r--tools/gn/function_exec_script.cc14
-rw-r--r--tools/gn/function_read_file.cc4
-rw-r--r--tools/gn/function_rebase_path.cc332
-rw-r--r--tools/gn/function_rebase_path_unittest.cc148
-rw-r--r--tools/gn/function_to_build_path.cc140
-rw-r--r--tools/gn/function_to_build_path_unittest.cc110
-rw-r--r--tools/gn/function_write_file.cc2
-rw-r--r--tools/gn/functions.cc2
-rw-r--r--tools/gn/functions.h14
-rw-r--r--tools/gn/functions_target.cc22
-rw-r--r--tools/gn/gn.gyp4
-rw-r--r--tools/gn/pattern.cc3
-rw-r--r--tools/gn/scope_per_file_provider.cc41
-rw-r--r--tools/gn/scope_per_file_provider.h7
-rw-r--r--tools/gn/scope_per_file_provider_unittest.cc55
-rw-r--r--tools/gn/secondary/base/BUILD.gn4
-rw-r--r--tools/gn/secondary/chrome/BUILD.gn5
-rw-r--r--tools/gn/secondary/crypto/ssl/BUILD.gn26
-rw-r--r--tools/gn/secondary/crypto/ssl/flags.gni4
-rw-r--r--tools/gn/secondary/skia/BUILD.gn1
-rw-r--r--tools/gn/secondary/third_party/expat/BUILD.gn24
-rw-r--r--tools/gn/secondary/third_party/icu/BUILD.gn2
-rw-r--r--tools/gn/secondary/third_party/libusb/BUILD.gn9
-rw-r--r--tools/gn/secondary/tools/grit/grit_rule.gni28
-rw-r--r--tools/gn/settings.cc1
-rw-r--r--tools/gn/setup.cc9
-rw-r--r--tools/gn/variables.cc13
-rw-r--r--tools/gn/variables.h4
35 files changed, 840 insertions, 355 deletions
diff --git a/tools/gn/BUILD.gn b/tools/gn/BUILD.gn
index 0b46d5a..2c38661 100644
--- a/tools/gn/BUILD.gn
+++ b/tools/gn/BUILD.gn
@@ -38,10 +38,10 @@ static_library("gn_lib") {
"function_exec_script.cc",
"function_process_file_template.cc",
"function_read_file.cc",
+ "function_rebase_path.cc",
"function_set_default_toolchain.cc",
"function_set_defaults.cc",
"function_template.cc",
- "function_to_build_path.cc",
"function_toolchain.cc",
"function_write_file.cc",
"group_target_generator.cc",
@@ -156,7 +156,7 @@ test("gn_unittests") {
"escape_unittest.cc",
"file_template_unittest.cc",
"filesystem_utils_unittest.cc",
- "function_to_build_path_unittest.cc",
+ "function_rebase_path_unittest.cc",
"input_conversion_unittest.cc",
"label_unittest.cc",
"ninja_copy_target_writer_unittest.cc",
diff --git a/tools/gn/args.cc b/tools/gn/args.cc
index d11892bc..64069f4 100644
--- a/tools/gn/args.cc
+++ b/tools/gn/args.cc
@@ -7,12 +7,12 @@
#include "tools/gn/variables.h"
const char kBuildArgs_Help[] =
- "Build Arguments Overview.\n"
+ "Build Arguments Overview\n"
"\n"
" Build arguments are variables passed in from outside of the build\n"
" that build files can query to determine how the build works.\n"
"\n"
- "How build arguments are set:\n"
+ "How build arguments are set\n"
"\n"
" First, system default arguments are set based on the current system.\n"
" The built-in arguments are:\n"
@@ -36,7 +36,7 @@ const char kBuildArgs_Help[] =
" It is an error to specify an override for a build argument that never\n"
" appears in a \"declare_args\" call.\n"
"\n"
- "How build arguments are used:\n"
+ "How build arguments are used\n"
"\n"
" If you want to use an argument, you use declare_args() and specify\n"
" default values. These default values will apply if none of the steps\n"
diff --git a/tools/gn/command_help.cc b/tools/gn/command_help.cc
index 5232a9b..f378e80 100644
--- a/tools/gn/command_help.cc
+++ b/tools/gn/command_help.cc
@@ -5,6 +5,7 @@
#include <algorithm>
#include <iostream>
+#include "base/strings/string_split.h"
#include "tools/gn/args.h"
#include "tools/gn/commands.h"
#include "tools/gn/err.h"
@@ -49,6 +50,44 @@ void PrintShortHelp(const std::string& line) {
OutputString(line.substr(first_normal) + "\n");
}
+// Rules:
+// - Lines beginning with non-whitespace are highlighted up to the first
+// colon (or the whole line if not).
+// - Lines whose first non-whitespace character is a # are dimmed.
+void PrintLongHelp(const std::string& text) {
+ std::vector<std::string> lines;
+ base::SplitStringDontTrim(text, '\n', &lines);
+
+ for (size_t i = 0; i < lines.size(); i++) {
+ const std::string& line = lines[i];
+
+ // Check for a heading line.
+ if (!line.empty() && line[0] != ' ') {
+ // Highlight up to the colon (if any).
+ size_t chars_to_highlight = line.find(':');
+ if (chars_to_highlight == std::string::npos)
+ chars_to_highlight = line.size();
+ OutputString(line.substr(0, chars_to_highlight), DECORATION_YELLOW);
+ OutputString(line.substr(chars_to_highlight) + "\n");
+ continue;
+ }
+
+ // Check for a comment.
+ TextDecoration dec = DECORATION_NONE;
+ for (size_t char_i = 0; char_i < line.size(); char_i++) {
+ if (line[char_i] == '#') {
+ // Got a comment, draw dimmed.
+ dec = DECORATION_DIM;
+ break;
+ } else if (line[char_i] != ' ') {
+ break;
+ }
+ }
+
+ OutputString(line + "\n", dec);
+ }
+}
+
void PrintToplevelHelp() {
OutputString("Commands (type \"gn help <command>\" for more details):\n");
@@ -65,6 +104,8 @@ void PrintToplevelHelp() {
PrintShortHelp(
"--args: Specifies build args overrides. See \"gn help buildargs\".");
PrintShortHelp(
+ "--no-exec: Skips exec_script calls (for performance testing).");
+ PrintShortHelp(
"-q: Quiet mode, don't print anything on success.");
PrintShortHelp(
"--output: Directory for build output (relative to source root).");
@@ -135,7 +176,7 @@ int RunHelp(const std::vector<std::string>& args) {
commands::CommandInfoMap::const_iterator found_command =
command_map.find(args[0]);
if (found_command != command_map.end()) {
- OutputString(found_command->second.help);
+ PrintLongHelp(found_command->second.help);
return 0;
}
@@ -144,7 +185,7 @@ int RunHelp(const std::vector<std::string>& args) {
functions::FunctionInfoMap::const_iterator found_function =
function_map.find(args[0]);
if (found_function != function_map.end()) {
- OutputString(found_function->second.help);
+ PrintLongHelp(found_function->second.help);
return 0;
}
@@ -154,7 +195,7 @@ int RunHelp(const std::vector<std::string>& args) {
variables::VariableInfoMap::const_iterator found_builtin_var =
builtin_vars.find(args[0]);
if (found_builtin_var != builtin_vars.end()) {
- OutputString(found_builtin_var->second.help);
+ PrintLongHelp(found_builtin_var->second.help);
return 0;
}
@@ -164,29 +205,29 @@ int RunHelp(const std::vector<std::string>& args) {
variables::VariableInfoMap::const_iterator found_target_var =
target_vars.find(args[0]);
if (found_target_var != target_vars.end()) {
- OutputString(found_target_var->second.help);
+ PrintLongHelp(found_target_var->second.help);
return 0;
}
// Random other topics.
if (args[0] == "buildargs") {
- OutputString(kBuildArgs_Help);
+ PrintLongHelp(kBuildArgs_Help);
return 0;
}
if (args[0] == "dotfile") {
- OutputString(kDotfile_Help);
+ PrintLongHelp(kDotfile_Help);
return 0;
}
if (args[0] == "input_conversion") {
- OutputString(kInputConversion_Help);
+ PrintLongHelp(kInputConversion_Help);
return 0;
}
if (args[0] == "patterns") {
- OutputString(kPattern_Help);
+ PrintLongHelp(kPattern_Help);
return 0;
}
if (args[0] == "source_expansion") {
- OutputString(kSourceExpansion_Help);
+ PrintLongHelp(kSourceExpansion_Help);
return 0;
}
diff --git a/tools/gn/file_template.cc b/tools/gn/file_template.cc
index 62235c4..1616c52 100644
--- a/tools/gn/file_template.cc
+++ b/tools/gn/file_template.cc
@@ -35,7 +35,7 @@ const char kSourceExpansion_Help[] =
" See \"gn help copy\" and \"gn help custom\" for more on how this is\n"
" applied.\n"
"\n"
- "Placeholders:\n"
+ "Placeholders\n"
"\n"
" {{source}}\n"
" The name of the source file relative to the root build output\n"
@@ -54,7 +54,7 @@ const char kSourceExpansion_Help[] =
" same name but different extension. For the source \"foo/bar.txt\"\n"
" the source name part will be \"bar\".\n"
"\n"
- "Examples:\n"
+ "Examples\n"
"\n"
" Non-varying outputs:\n"
" script(\"hardcoded_outputs\") {\n"
diff --git a/tools/gn/filesystem_utils.cc b/tools/gn/filesystem_utils.cc
index 3ecdc97..ee7c5d5 100644
--- a/tools/gn/filesystem_utils.cc
+++ b/tools/gn/filesystem_utils.cc
@@ -4,6 +4,8 @@
#include "tools/gn/filesystem_utils.h"
+#include <algorithm>
+
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -507,3 +509,40 @@ std::string PathToSystem(const std::string& path) {
return ret;
}
+std::string RebaseSourceAbsolutePath(const std::string& input,
+ const SourceDir& dest_dir) {
+ CHECK(input.size() >= 2 && input[0] == '/' && input[1] == '/')
+ << "Input to rebase isn't source-absolute: " << input;
+ CHECK(dest_dir.is_source_absolute())
+ << "Dir to rebase to isn't source-absolute: " << dest_dir.value();
+
+ const std::string& dest = dest_dir.value();
+
+ // Skip the common prefixes of the source and dest as long as they end in
+ // a [back]slash.
+ size_t common_prefix_len = 2; // The beginning two "//" are always the same.
+ size_t max_common_length = std::min(input.size(), dest.size());
+ for (size_t i = common_prefix_len; i < max_common_length; i++) {
+ if ((input[i] == '/' || input[i] == '\\') &&
+ (dest[i] == '/' || dest[i] == '\\'))
+ common_prefix_len = i + 1;
+ else if (input[i] != dest[i])
+ break;
+ }
+
+ // Invert the dest dir starting from the end of the common prefix.
+ std::string ret;
+ for (size_t i = common_prefix_len; i < dest.size(); i++) {
+ if (dest[i] == '/' || dest[i] == '\\')
+ ret.append("../");
+ }
+
+ // Append any remaining unique input.
+ ret.append(&input[common_prefix_len], input.size() - common_prefix_len);
+
+ // If the result is still empty, the paths are the same.
+ if (ret.empty())
+ ret.push_back('.');
+
+ return ret;
+}
diff --git a/tools/gn/filesystem_utils.h b/tools/gn/filesystem_utils.h
index bf214dc..9899cae 100644
--- a/tools/gn/filesystem_utils.h
+++ b/tools/gn/filesystem_utils.h
@@ -133,4 +133,9 @@ void NormalizePath(std::string* path);
void ConvertPathToSystem(std::string* path);
std::string PathToSystem(const std::string& path);
+// Takes a source-absolute path (must begin with "//") and makes it relative
+// to the given directory, which also must be source-absolute.
+std::string RebaseSourceAbsolutePath(const std::string& input,
+ const SourceDir& dest_dir);
+
#endif // TOOLS_GN_FILESYSTEM_UTILS_H_
diff --git a/tools/gn/filesystem_utils_unittest.cc b/tools/gn/filesystem_utils_unittest.cc
index 6c80cdb..aeb09a4 100644
--- a/tools/gn/filesystem_utils_unittest.cc
+++ b/tools/gn/filesystem_utils_unittest.cc
@@ -195,3 +195,53 @@ TEST(FilesystemUtils, NormalizePath) {
NormalizePath(&input);
EXPECT_EQ("../", input);
}
+
+TEST(FilesystemUtils, RebaseSourceAbsolutePath) {
+ // Degenerate case.
+ EXPECT_EQ(".", RebaseSourceAbsolutePath("//", SourceDir("//")));
+ EXPECT_EQ(".",
+ RebaseSourceAbsolutePath("//foo/bar/", SourceDir("//foo/bar/")));
+
+ // Going up the tree.
+ EXPECT_EQ("../foo",
+ RebaseSourceAbsolutePath("//foo", SourceDir("//bar/")));
+ EXPECT_EQ("../foo/",
+ RebaseSourceAbsolutePath("//foo/", SourceDir("//bar/")));
+ EXPECT_EQ("../../foo",
+ RebaseSourceAbsolutePath("//foo", SourceDir("//bar/moo")));
+ EXPECT_EQ("../../foo/",
+ RebaseSourceAbsolutePath("//foo/", SourceDir("//bar/moo")));
+
+ // Going down the tree.
+ EXPECT_EQ("foo/bar",
+ RebaseSourceAbsolutePath("//foo/bar", SourceDir("//")));
+ EXPECT_EQ("foo/bar/",
+ RebaseSourceAbsolutePath("//foo/bar/", SourceDir("//")));
+
+ // Going up and down the tree.
+ EXPECT_EQ("../../foo/bar",
+ RebaseSourceAbsolutePath("//foo/bar", SourceDir("//a/b/")));
+ EXPECT_EQ("../../foo/bar/",
+ RebaseSourceAbsolutePath("//foo/bar/", SourceDir("//a/b/")));
+
+ // Sharing prefix.
+ EXPECT_EQ("foo",
+ RebaseSourceAbsolutePath("//a/foo", SourceDir("//a/")));
+ EXPECT_EQ("foo/",
+ RebaseSourceAbsolutePath("//a/foo/", SourceDir("//a/")));
+ EXPECT_EQ("foo",
+ RebaseSourceAbsolutePath("//a/b/foo", SourceDir("//a/b/")));
+ EXPECT_EQ("foo/",
+ RebaseSourceAbsolutePath("//a/b/foo/", SourceDir("//a/b/")));
+ EXPECT_EQ("foo/bar",
+ RebaseSourceAbsolutePath("//a/b/foo/bar", SourceDir("//a/b/")));
+ EXPECT_EQ("foo/bar/",
+ RebaseSourceAbsolutePath("//a/b/foo/bar/", SourceDir("//a/b/")));
+
+ // One could argue about this case. Since the input doesn't have a slash it
+ // would normally not be treated like a directory and we'd go up, which is
+ // simpler. However, since it matches the output directory's name, we could
+ // potentially infer that it's the same and return "." for this.
+ EXPECT_EQ("../bar",
+ RebaseSourceAbsolutePath("//foo/bar", SourceDir("//foo/bar/")));
+}
diff --git a/tools/gn/function_exec_script.cc b/tools/gn/function_exec_script.cc
index 0ffe90b..c00579a 100644
--- a/tools/gn/function_exec_script.cc
+++ b/tools/gn/function_exec_script.cc
@@ -38,6 +38,8 @@ namespace functions {
namespace {
+const char kNoExecSwitch[] = "no-exec";
+
#if defined(OS_WIN)
bool ExecProcess(const CommandLine& cmdline,
const base::FilePath& startup_dir,
@@ -350,11 +352,13 @@ Value RunExecScript(Scope* scope,
std::string output;
std::string stderr_output; // TODO(brettw) not hooked up, see above.
int exit_code = 0;
- if (!ExecProcess(cmdline, startup_dir,
- &output, &stderr_output, &exit_code)) {
- *err = Err(function->function(), "Could not execute python.",
- "I was trying to execute \"" + FilePathToUTF8(python_path) + "\".");
- return Value();
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(kNoExecSwitch)) {
+ if (!ExecProcess(cmdline, startup_dir,
+ &output, &stderr_output, &exit_code)) {
+ *err = Err(function->function(), "Could not execute python.",
+ "I was trying to execute \"" + FilePathToUTF8(python_path) + "\".");
+ return Value();
+ }
}
if (g_scheduler->verbose_logging()) {
g_scheduler->Log("Pythoning", script_source.value() + " took " +
diff --git a/tools/gn/function_read_file.cc b/tools/gn/function_read_file.cc
index 1067d9b..e510267 100644
--- a/tools/gn/function_read_file.cc
+++ b/tools/gn/function_read_file.cc
@@ -25,7 +25,7 @@ const char kReadFile_Help[] =
" Whitespace will be trimmed from the end of the file. Throws an error\n"
" if the file can not be opened.\n"
"\n"
- "Arguments:\n"
+ "Arguments\n"
"\n"
" filename\n"
" Filename to read, relative to the build file.\n"
@@ -34,7 +34,7 @@ const char kReadFile_Help[] =
" Controls how the file is read and parsed.\n"
" See \"gn help input_conversion\".\n"
"\n"
- "Example:\n"
+ "Example\n"
" lines = read_file(\"foo.txt\", \"list lines\")\n";
Value RunReadFile(Scope* scope,
diff --git a/tools/gn/function_rebase_path.cc b/tools/gn/function_rebase_path.cc
new file mode 100644
index 0000000..68c6f1f
--- /dev/null
+++ b/tools/gn/function_rebase_path.cc
@@ -0,0 +1,332 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tools/gn/build_settings.h"
+#include "tools/gn/filesystem_utils.h"
+#include "tools/gn/functions.h"
+#include "tools/gn/parse_tree.h"
+#include "tools/gn/scope.h"
+#include "tools/gn/settings.h"
+#include "tools/gn/source_dir.h"
+#include "tools/gn/source_file.h"
+#include "tools/gn/value.h"
+
+namespace functions {
+
+namespace {
+
+enum SeparatorConversion {
+ SEP_NO_CHANGE, // Don't change.
+ SEP_TO_SYSTEM, // Slashes to system ones.
+ SEP_FROM_SYSTEM // System ones to slashes.
+};
+
+// Does the specified path separator conversion in-place.
+void ConvertSlashes(std::string* str, SeparatorConversion mode) {
+#if defined(OS_WIN)
+ switch (mode) {
+ case SEP_NO_CHANGE:
+ break;
+ case SEP_TO_SYSTEM:
+ for (size_t i = 0; i < str->size(); i++) {
+ if ((*str)[i] == '/')
+ (*str)[i] = '\\';
+ }
+ break;
+ case SEP_FROM_SYSTEM:
+ for (size_t i = 0; i < str->size(); i++) {
+ if ((*str)[i] == '\\')
+ (*str)[i] = '/';
+ }
+ break;
+ }
+#else
+ DCHECK(str->find('\\') == std::string::npos)
+ << "Filename contains a backslash on a non-Windows platform.";
+#endif
+}
+
+bool EndsInSlash(const std::string& s) {
+ return !s.empty() && (s[s.size() - 1] == '/' || s[s.size() - 1] == '\\');
+}
+
+// We want the output to match the input in terms of ending in a slash or not.
+// Through all the transformations, these can get added or removed in various
+// cases.
+void MakeSlashEndingMatchInput(const std::string& input, std::string* output) {
+ if (EndsInSlash(input)) {
+ if (!EndsInSlash(*output)) // Preserve same slash type as input.
+ output->push_back(input[input.size() - 1]);
+ } else {
+ if (EndsInSlash(*output))
+ output->resize(output->size() - 1);
+ }
+}
+
+// Returns true if the given value looks like a directory, otherwise we'll
+// assume it's a file.
+bool ValueLooksLikeDir(const std::string& value) {
+ if (value.empty())
+ return true;
+ size_t value_size = value.size();
+
+ // Count the number of dots at the end of the string.
+ size_t num_dots = 0;
+ while (num_dots < value_size && value[value_size - num_dots - 1] == '.')
+ num_dots++;
+
+ if (num_dots == value.size())
+ return true; // String is all dots.
+
+ if (value[value_size - num_dots - 1] == '/' ||
+ value[value_size - num_dots - 1] == '\\')
+ return true; // String is a [back]slash followed by 0 or more dots.
+
+ // Anything else.
+ return false;
+}
+
+Value ConvertOnePath(const Scope* scope,
+ const FunctionCallNode* function,
+ const Value& value,
+ const SourceDir& from_dir,
+ const SourceDir& to_dir,
+ bool convert_to_system_absolute,
+ SeparatorConversion separator_conversion,
+ Err* err) {
+ Value result; // Ensure return value optimization.
+
+ if (!value.VerifyTypeIs(Value::STRING, err))
+ return result;
+ const std::string& string_value = value.string_value();
+
+ bool looks_like_dir = ValueLooksLikeDir(string_value);
+
+ // System-absolute output special case.
+ if (convert_to_system_absolute) {
+ base::FilePath system_path;
+ if (looks_like_dir) {
+ system_path = scope->settings()->build_settings()->GetFullPath(
+ from_dir.ResolveRelativeDir(string_value));
+ } else {
+ system_path = scope->settings()->build_settings()->GetFullPath(
+ from_dir.ResolveRelativeFile(string_value));
+ }
+ result = Value(function, FilePathToUTF8(system_path));
+ if (looks_like_dir)
+ MakeSlashEndingMatchInput(string_value, &result.string_value());
+ ConvertPathToSystem(&result.string_value());
+ return result;
+ }
+
+ if (from_dir.is_system_absolute() || to_dir.is_system_absolute()) {
+ *err = Err(function, "System-absolute directories are not supported for "
+ "the source or dest dir for rebase_path. It would be nice to add this "
+ "if you're so inclined!");
+ return result;
+ }
+
+ result = Value(function, Value::STRING);
+ if (looks_like_dir) {
+ result.string_value() = RebaseSourceAbsolutePath(
+ from_dir.ResolveRelativeDir(string_value).value(),
+ to_dir);
+ MakeSlashEndingMatchInput(string_value, &result.string_value());
+ } else {
+ result.string_value() = RebaseSourceAbsolutePath(
+ from_dir.ResolveRelativeFile(string_value).value(),
+ to_dir);
+ }
+
+ ConvertSlashes(&result.string_value(), separator_conversion);
+ return result;
+}
+
+} // namespace
+
+const char kRebasePath[] = "rebase_path";
+const char kRebasePath_Help[] =
+ "rebase_path: Rebase a file or directory to another location.\n"
+ "\n"
+ " converted = rebase_path(input, current_base, new_base,\n"
+ " [path_separators])\n"
+ "\n"
+ " Takes a string argument representing a file name, or a list of such\n"
+ " strings and converts it/them to be relative to a different base\n"
+ " directory.\n"
+ "\n"
+ " When invoking the compiler or scripts, GN will automatically convert\n"
+ " sources and include directories to be relative to the build directory.\n"
+ " However, if you're passing files directly in the \"args\" array or\n"
+ " doing other manual manipulations where GN doesn't know something is\n"
+ " a file name, you will need to convert paths to be relative to what\n"
+ " your tool is expecting.\n"
+ "\n"
+ " The common case is to use this to convert paths relative to the\n"
+ " current directory to be relative to the build directory (which will\n"
+ " be the current directory when executing scripts).\n"
+ "\n"
+ "Arguments\n"
+ "\n"
+ " input\n"
+ " A string or list of strings representing file or directory names\n"
+ " These can be relative paths (\"foo/bar.txt\", system absolte paths\n"
+ " (\"/foo/bar.txt\"), or source absolute paths (\"//foo/bar.txt\").\n"
+ "\n"
+ " current_base\n"
+ " Directory representing the base for relative paths in the input.\n"
+ " If this is not an absolute path, it will be treated as being\n"
+ " relative to the current build file. Use \".\" to convert paths\n"
+ " from the current BUILD-file's directory.\n"
+ "\n"
+ " new_base\n"
+ " The directory to convert the paths to be relative to. As with the\n"
+ " current_base, this can be a relative path, which will be treated\n"
+ " as being relative to the current BUILD-file's directory.\n"
+ "\n"
+ " As a special case, if new_base is the empty string, all paths\n"
+ " will be converted to system-absolute native style paths with\n"
+ " system path separators. This is useful for invoking external\n"
+ " programs.\n"
+ "\n"
+ " path_separators\n"
+ " On Windows systems, indicates whether and how path separators\n"
+ " should be converted as part of the transformation. It can be one\n"
+ " of the following strings:\n"
+ " - \"none\" Perform no changes on path separators. This is the\n"
+ " default if this argument is unspecified.\n"
+ " - \"to_system\" Convert to the system path separators\n"
+ " (backslashes on Windows).\n"
+ " - \"from_system\" Convert system path separators to forward\n"
+ " slashes.\n"
+ "\n"
+ " On Posix systems there are no path separator transformations\n"
+ " applied. If the new_base is empty (specifying absolute output)\n"
+ " this parameter should not be supplied since paths will always be\n"
+ " converted,\n"
+ "\n"
+ "Return value\n"
+ "\n"
+ " The return value will be the same type as the input value (either a\n"
+ " string or a list of strings). All relative and source-absolute file\n"
+ " names will be converted to be relative to the requested output\n"
+ " System-absolute paths will be unchanged.\n"
+ "\n"
+ "Example\n"
+ "\n"
+ " # Convert a file in the current directory to be relative to the build\n"
+ " # directory (the current dir when executing compilers and scripts).\n"
+ " foo = rebase_path(\"myfile.txt\", \".\", root_build_dir)\n"
+ " # might produce \"../../project/myfile.txt\".\n"
+ "\n"
+ " # Convert a file to be system absolute:\n"
+ " foo = rebase_path(\"myfile.txt\", \".\", \"\")\n"
+ " # Might produce \"D:\\source\\project\\myfile.txt\" on Windows or\n"
+ " # \"/home/you/source/project/myfile.txt\" on Linux.\n"
+ "\n"
+ " # Convert a file's path separators from forward slashes to system\n"
+ " # slashes.\n"
+ " foo = rebase_path(\"source/myfile.txt\", \".\", \".\", \"to_system\")\n"
+ "\n"
+ " # Typical usage for converting to the build directory for a script.\n"
+ " custom(\"myscript\") {\n"
+ " # Don't convert sources, GN will automatically convert these to be\n"
+ " # relative to the build directory when it contructs the command\n"
+ " # line for your script.\n"
+ " sources = [ \"foo.txt\", \"bar.txt\" ]\n"
+ "\n"
+ " # Extra file args passed manually need to be explicitly converted\n"
+ " # to be relative to the build directory:\n"
+ " args = [\n"
+ " \"--data\",\n"
+ " rebase_path(\"//mything/data/input.dat\", \".\", root_build_dir),\n"
+ " \"--rel\",\n"
+ " rebase_path(\"relative_path.txt\", \".\", root_build_dir)\n"
+ " ]\n"
+ " }\n";
+
+Value RunRebasePath(Scope* scope,
+ const FunctionCallNode* function,
+ const std::vector<Value>& args,
+ Err* err) {
+ Value result;
+
+ // Inputs.
+ if (args.size() != 3 && args.size() != 4) {
+ *err = Err(function->function(), "rebase_path takes 3 or 4 args.");
+ return result;
+ }
+ const Value& inputs = args[0];
+
+ // From path.
+ if (!args[1].VerifyTypeIs(Value::STRING, err))
+ return result;
+ const SourceDir& current_dir = scope->GetSourceDir();
+ SourceDir from_dir = current_dir.ResolveRelativeDir(args[1].string_value());
+
+ // To path.
+ if (!args[2].VerifyTypeIs(Value::STRING, err))
+ return result;
+ bool convert_to_system_absolute = false;
+ SourceDir to_dir;
+ if (args[2].string_value().empty()) {
+ convert_to_system_absolute = true;
+ } else {
+ to_dir = current_dir.ResolveRelativeDir(args[2].string_value());
+ }
+
+ // Path conversion.
+ SeparatorConversion sep_conversion = SEP_NO_CHANGE;
+ if (args.size() == 4) {
+ if (convert_to_system_absolute) {
+ *err = Err(function, "Can't specify slash conversion.",
+ "You specified absolute system path output by using an empty string "
+ "for the desination directory on rebase_path(). In this case, you "
+ "can't specify slash conversion.");
+ return result;
+ }
+
+ if (!args[3].VerifyTypeIs(Value::STRING, err))
+ return result;
+ const std::string& sep_string = args[3].string_value();
+ if (sep_string == "to_system") {
+ sep_conversion = SEP_TO_SYSTEM;
+ } else if (sep_string == "from_system") {
+ sep_conversion = SEP_FROM_SYSTEM;
+ } else if (sep_string != "none") {
+ *err = Err(args[3], "Invalid path separator conversion mode.",
+ "I was expecting \"none\", \"to_system\", or \"from_system\" and\n"
+ "you gave me \"" + args[3].string_value() + "\".");
+ return result;
+ }
+ }
+
+ if (inputs.type() == Value::STRING) {
+ return ConvertOnePath(scope, function, inputs,
+ from_dir, to_dir, convert_to_system_absolute,
+ sep_conversion, err);
+
+ } else if (inputs.type() == Value::LIST) {
+ result = Value(function, Value::LIST);
+ result.list_value().reserve(inputs.list_value().size());
+
+ for (size_t i = 0; i < inputs.list_value().size(); i++) {
+ result.list_value().push_back(
+ ConvertOnePath(scope, function, inputs.list_value()[i],
+ from_dir, to_dir, convert_to_system_absolute,
+ sep_conversion, err));
+ if (err->has_error()) {
+ result = Value();
+ return result;
+ }
+ }
+ return result;
+ }
+
+ *err = Err(function->function(),
+ "rebase_path requires a list or a string.");
+ return result;
+}
+
+} // namespace functions
diff --git a/tools/gn/function_rebase_path_unittest.cc b/tools/gn/function_rebase_path_unittest.cc
new file mode 100644
index 0000000..19e0692
--- /dev/null
+++ b/tools/gn/function_rebase_path_unittest.cc
@@ -0,0 +1,148 @@
+// Copyright (c) 2013 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 "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "tools/gn/functions.h"
+#include "tools/gn/parse_tree.h"
+#include "tools/gn/test_with_scope.h"
+
+namespace {
+
+std::string RebaseOne(Scope scope,
+ const char* input,
+ const char* from_dir,
+ const char* to_dir,
+ const char* sep = NULL) {
+ std::vector<Value> args;
+ args.push_back(Value(NULL, input));
+ args.push_back(Value(NULL, from_dir));
+ args.push_back(Value(NULL, to_dir));
+ if (sep)
+ args.push_back(Value(NULL, sep));
+
+ Err err;
+ FunctionCallNode function;
+ Value result = functions::RunRebasePath(&scope, &function, args, &err);
+ bool is_string = result.type() == Value::STRING;
+ EXPECT_TRUE(is_string);
+
+ return result.string_value();
+}
+
+} // namespace
+
+TEST(RebasePath, Strings) {
+ TestWithScope setup;
+ setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
+ Scope* scope = setup.scope();
+ scope->set_source_dir(SourceDir("//tools/gn/"));
+
+ // Build-file relative paths.
+ EXPECT_EQ("../../tools/gn", RebaseOne(scope, ".", ".", "//out/Debug"));
+ EXPECT_EQ("../../tools/gn/", RebaseOne(scope, "./", ".", "//out/Debug"));
+ EXPECT_EQ("../../tools/gn/foo", RebaseOne(scope, "foo", ".", "//out/Debug"));
+ EXPECT_EQ("../..", RebaseOne(scope, "../..", ".", "//out/Debug"));
+ EXPECT_EQ("../../", RebaseOne(scope, "../../", ".", "//out/Debug"));
+
+ // We don't allow going above the root source dir.
+ EXPECT_EQ("../..", RebaseOne(scope, "../../..", ".", "//out/Debug"));
+
+ // Source-absolute input paths.
+ EXPECT_EQ("./", RebaseOne(scope, "//", "//", "//"));
+ EXPECT_EQ("foo", RebaseOne(scope, "//foo", "//", "//"));
+ EXPECT_EQ("foo/", RebaseOne(scope, "//foo/", "//", "//"));
+ EXPECT_EQ("../../foo/bar", RebaseOne(scope, "//foo/bar", ".", "//out/Debug"));
+ EXPECT_EQ("./", RebaseOne(scope, "//foo/", "//", "//foo/"));
+ // Thie one is technically correct but could be simplified to "." if
+ // necessary.
+ EXPECT_EQ("../foo", RebaseOne(scope, "//foo", "//", "//foo"));
+
+ // Test slash conversion.
+#if defined(OS_WIN)
+ EXPECT_EQ("foo/bar", RebaseOne(scope, "foo/bar", ".", ".", "none"));
+ EXPECT_EQ("foo\\bar", RebaseOne(scope, "foo/bar", ".", ".", "to_system"));
+ EXPECT_EQ("foo/bar", RebaseOne(scope, "foo/bar", ".", ".", "from_system"));
+
+ EXPECT_EQ("foo\\bar", RebaseOne(scope, "foo\\bar", ".", ".", "none"));
+ EXPECT_EQ("foo\\bar", RebaseOne(scope, "foo\\bar", ".", ".", "to_system"));
+ EXPECT_EQ("foo/bar", RebaseOne(scope, "foo\\bar", ".", ".", "from_system"));
+#else // No transformations on Posix.
+ EXPECT_EQ("foo/bar", RebaseOne(scope, "foo/bar", ".", ".", "none"));
+ EXPECT_EQ("foo/bar", RebaseOne(scope, "foo/bar", ".", ".", "to_system"));
+ EXPECT_EQ("foo/bar", RebaseOne(scope, "foo/bar", ".", ".", "from_system"));
+
+ EXPECT_EQ("foo\\bar", RebaseOne(scope, "foo\\bar", ".", ".", "none"));
+ EXPECT_EQ("foo\\bar", RebaseOne(scope, "foo\\bar", ".", ".", "to_system"));
+ EXPECT_EQ("foo\\bar", RebaseOne(scope, "foo\\bar", ".", ".", "from_system"));
+#endif
+
+ // Test system path output.
+#if defined(OS_WIN)
+ setup.build_settings()->SetRootPath(base::FilePath(L"C:\\source"));
+ EXPECT_EQ("C:\\source", RebaseOne(scope, ".", "//", ""));
+ EXPECT_EQ("C:\\source\\", RebaseOne(scope, "//", "//", ""));
+ EXPECT_EQ("C:\\source\\foo", RebaseOne(scope, "foo", "//", ""));
+ EXPECT_EQ("C:\\source\\foo\\", RebaseOne(scope, "foo/", "//", ""));
+ EXPECT_EQ("C:\\source\\tools\\gn\\foo", RebaseOne(scope, "foo", ".", ""));
+#else
+ setup.build_settings()->SetRootPath(base::FilePath("/source"));
+ EXPECT_EQ("/source", RebaseOne(scope, ".", "//", ""));
+ EXPECT_EQ("/source/", RebaseOne(scope, "//", "//", ""));
+ EXPECT_EQ("/source/foo", RebaseOne(scope, "foo", "//", ""));
+ EXPECT_EQ("/source/foo/", RebaseOne(scope, "foo/", "//", ""));
+ EXPECT_EQ("/source/tools/gn/foo", RebaseOne(scope, "foo", ".", ""));
+#endif
+}
+
+// Test list input.
+TEST(RebasePath, List) {
+ TestWithScope setup;
+ setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
+ setup.scope()->set_source_dir(SourceDir("//tools/gn/"));
+
+ std::vector<Value> args;
+ args.push_back(Value(NULL, Value::LIST));
+ args[0].list_value().push_back(Value(NULL, "foo.txt"));
+ args[0].list_value().push_back(Value(NULL, "bar.txt"));
+ args.push_back(Value(NULL, "."));
+ args.push_back(Value(NULL, "//out/Debug/"));
+
+ Err err;
+ FunctionCallNode function;
+ Value ret = functions::RunRebasePath(setup.scope(), &function, args, &err);
+ EXPECT_FALSE(err.has_error());
+
+ ASSERT_EQ(Value::LIST, ret.type());
+ ASSERT_EQ(2u, ret.list_value().size());
+
+ EXPECT_EQ("../../tools/gn/foo.txt", ret.list_value()[0].string_value());
+ EXPECT_EQ("../../tools/gn/bar.txt", ret.list_value()[1].string_value());
+}
+
+TEST(RebasePath, Errors) {
+ TestWithScope setup;
+ setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
+
+ // No arg input should issue an error.
+ Err err;
+ std::vector<Value> args;
+ FunctionCallNode function;
+ Value ret = functions::RunRebasePath(setup.scope(), &function, args, &err);
+ EXPECT_TRUE(err.has_error());
+
+ // One arg int input.
+ args.push_back(Value(NULL, static_cast<int64>(5)));
+ err = Err();
+ ret = functions::RunRebasePath(setup.scope(), &function, args, &err);
+ EXPECT_TRUE(err.has_error());
+
+ // Two arg string input.
+ args.clear();
+ args.push_back(Value(NULL, "hello"));
+ args.push_back(Value(NULL, "world"));
+ err = Err();
+ ret = functions::RunRebasePath(setup.scope(), &function, args, &err);
+ EXPECT_TRUE(err.has_error());
+}
diff --git a/tools/gn/function_to_build_path.cc b/tools/gn/function_to_build_path.cc
deleted file mode 100644
index 362f8c9..0000000
--- a/tools/gn/function_to_build_path.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "tools/gn/build_settings.h"
-#include "tools/gn/functions.h"
-#include "tools/gn/parse_tree.h"
-#include "tools/gn/path_output.h"
-#include "tools/gn/scope.h"
-#include "tools/gn/settings.h"
-#include "tools/gn/source_dir.h"
-#include "tools/gn/source_file.h"
-#include "tools/gn/value.h"
-
-namespace functions {
-
-namespace {
-
-// Returns true if the given value looks like a directory, otherwise we'll
-// assume it's a file.
-bool ValueLooksLikeDir(const std::string& value) {
- if (value.empty())
- return true;
- size_t value_size = value.size();
-
- // Count the number of dots at the end of the string.
- size_t num_dots = 0;
- while (num_dots < value_size && value[value_size - num_dots - 1] == '.')
- num_dots++;
-
- if (num_dots == value.size())
- return true; // String is all dots.
-
- if (value[value_size - num_dots - 1] == '/' ||
- value[value_size - num_dots - 1] == '\\')
- return true; // String is a [back]slash followed by 0 or more dots.
-
- // Anything else.
- return false;
-}
-
-Value ConvertOneBuildPath(const Scope* scope,
- const FunctionCallNode* function,
- const Value& value,
- const PathOutput& path_output,
- Err* err) {
- if (!value.VerifyTypeIs(Value::STRING, err))
- return Value();
-
- const std::string& string_value = value.string_value();
-
- std::ostringstream buffer;
- if (ValueLooksLikeDir(string_value)) {
- SourceDir absolute =
- scope->GetSourceDir().ResolveRelativeDir(string_value);
- path_output.WriteDir(buffer, absolute, PathOutput::DIR_NO_LAST_SLASH);
- } else {
- SourceFile absolute =
- scope->GetSourceDir().ResolveRelativeFile(string_value);
- path_output.WriteFile(buffer, absolute);
- }
- return Value(function, buffer.str());
-}
-
-} // namespace
-
-const char kToBuildPath[] = "to_build_path";
-const char kToBuildPath_Help[] =
- "to_build_path: Rebase a file or directory to the build output dir.\n"
- "\n"
- " <converted> = to_build_path(<file_or_path_string_or_list>)\n"
- "\n"
- " Takes a string argument representing a file name, or a list of such\n"
- " strings and converts it/them to be relative to the root build output\n"
- " directory (which is the current directory when running scripts).\n"
- "\n"
- " The input can be:\n"
- " - Paths relative to the BUILD file like \"foo.txt\".\n"
- " - Source-root absolute paths like \"//foo/bar/foo.txt\".\n"
- " - System absolute paths like \"/usr/include/foo.h\" or\n"
- " \"/C:/foo/bar.h\" (these will be passed unchanged).\n"
- " - A list of such values (the result will be a list of each item\n"
- " converted as per the above description).\n"
- "\n"
- " Normally for sources and in cases where GN is providing file names\n"
- " to a tool, the paths will automatically be converted to be relative\n"
- " to the build directory. However, if you pass additional arguments,\n"
- " GN won't know that the string is actually a file path. These will\n"
- " need to be manually converted to be relative to the build dir using\n"
- " to_build_path().\n"
- "\n"
- " Trailing slashes will not be reflected in the output.\n"
- "\n"
- " Additionally, on Windows, slashes will be converted to backslashes.\n"
- "\n"
- "Example:\n"
- " custom(\"myscript\") {\n"
- " # Don't use for sources, GN will automatically convert these since\n"
- " # it knows they're files.\n"
- " sources = [ \"foo.txt\", \"bar.txt\" ]\n"
- "\n"
- " # Extra file args passed manually need to be explicitly converted:\n"
- " args = [ \"--data\", to_build_path(\"//mything/data/input.dat\"),\n"
- " \"--rel\", to_build_path(\"relative_path.txt\") ]\n"
- " }\n";
-
-Value RunToBuildPath(Scope* scope,
- const FunctionCallNode* function,
- const std::vector<Value>& args,
- Err* err) {
- if (args.size() != 1) {
- *err = Err(function->function(), "to_build_path takes one argument.");
- return Value();
- }
-
- const Value& value = args[0];
- PathOutput path_output(scope->settings()->build_settings()->build_dir(),
- ESCAPE_NONE, true);
-
- if (value.type() == Value::STRING) {
- return ConvertOneBuildPath(scope, function, value, path_output, err);
-
- } else if (value.type() == Value::LIST) {
- Value ret(function, Value::LIST);
- ret.list_value().reserve(value.list_value().size());
-
- for (size_t i = 0; i < value.list_value().size(); i++) {
- ret.list_value().push_back(
- ConvertOneBuildPath(scope, function, value.list_value()[i],
- path_output, err));
- }
- return ret;
- }
-
- *err = Err(function->function(),
- "to_build_path requires a list or a string.");
- return Value();
-}
-
-} // namespace functions
diff --git a/tools/gn/function_to_build_path_unittest.cc b/tools/gn/function_to_build_path_unittest.cc
deleted file mode 100644
index 7e01912..0000000
--- a/tools/gn/function_to_build_path_unittest.cc
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "tools/gn/functions.h"
-#include "tools/gn/parse_tree.h"
-#include "tools/gn/test_with_scope.h"
-
-namespace {
-
-void ExpectCallEqualsString(Scope* scope,
- const std::string& input,
- const std::string& expected) {
- std::vector<Value> args;
- args.push_back(Value(NULL, input));
-
- Err err;
- FunctionCallNode function;
- Value result = functions::RunToBuildPath(scope, &function, args, &err);
-
- EXPECT_FALSE(err.has_error());
- EXPECT_EQ(Value::STRING, result.type());
- EXPECT_EQ(expected, result.string_value());
-}
-
-} // namespace
-
-TEST(ToBuildPath, Strings) {
- TestWithScope setup;
- setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
-
- Scope* scope = setup.scope();
- scope->set_source_dir(SourceDir("//tools/gn/"));
-
- // Absolute system paths are unchanged.
- ExpectCallEqualsString(scope, "/", "/");
- ExpectCallEqualsString(scope, "/foo", "/foo");
- ExpectCallEqualsString(scope, "/foo/", "/foo");
- ExpectCallEqualsString(scope, "/foo/bar.txt", "/foo/bar.txt");
-
- // Build-file relative paths.
- ExpectCallEqualsString(scope, ".", "../../tools/gn");
- ExpectCallEqualsString(scope, "foo.txt", "../../tools/gn/foo.txt");
- ExpectCallEqualsString(scope, "..", "../../tools");
- ExpectCallEqualsString(scope, "../", "../../tools");
- ExpectCallEqualsString(scope, "../foo.txt", "../../tools/foo.txt");
-
- // Source-root paths.
- ExpectCallEqualsString(scope, "//", "../..");
- ExpectCallEqualsString(scope, "//foo/", "../../foo");
- ExpectCallEqualsString(scope, "//foo.txt", "../../foo.txt");
- ExpectCallEqualsString(scope, "//foo/bar.txt", "../../foo/bar.txt");
-
- // Source-root paths. It might be nice if we detected the strings start
- // with the build dir and collapse, but this is the current behavior.
- ExpectCallEqualsString(scope, "//out/Debug/",
- "../../out/Debug"); // Could be ".".
- ExpectCallEqualsString(scope, "//out/Debug/foo/",
- "../../out/Debug/foo"); // Could be "foo".
-}
-
-// Test list input.
-TEST(ToBuildPath, List) {
- TestWithScope setup;
- setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
- setup.scope()->set_source_dir(SourceDir("//tools/gn/"));
-
- std::vector<Value> args;
- args.push_back(Value(NULL, Value::LIST));
- args[0].list_value().push_back(Value(NULL, "foo.txt"));
- args[0].list_value().push_back(Value(NULL, "bar.txt"));
-
- Err err;
- FunctionCallNode function;
- Value ret = functions::RunToBuildPath(setup.scope(), &function, args, &err);
- EXPECT_FALSE(err.has_error());
-
- ASSERT_EQ(Value::LIST, ret.type());
- ASSERT_EQ(2u, ret.list_value().size());
-
- EXPECT_EQ("../../tools/gn/foo.txt", ret.list_value()[0].string_value());
- EXPECT_EQ("../../tools/gn/bar.txt", ret.list_value()[1].string_value());
-}
-
-TEST(ToBuildPath, Errors) {
- TestWithScope setup;
- setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
-
- // No arg input should issue an error.
- Err err;
- std::vector<Value> args;
- FunctionCallNode function;
- Value ret = functions::RunToBuildPath(setup.scope(), &function, args, &err);
- EXPECT_TRUE(err.has_error());
-
- // One arg int input.
- args.push_back(Value(NULL, static_cast<int64>(5)));
- err = Err();
- ret = functions::RunToBuildPath(setup.scope(), &function, args, &err);
- EXPECT_TRUE(err.has_error());
-
- // Two arg string input.
- args.clear();
- args.push_back(Value(NULL, "hello"));
- args.push_back(Value(NULL, "world"));
- err = Err();
- ret = functions::RunToBuildPath(setup.scope(), &function, args, &err);
- EXPECT_TRUE(err.has_error());
-}
diff --git a/tools/gn/function_write_file.cc b/tools/gn/function_write_file.cc
index ea42100..f794168 100644
--- a/tools/gn/function_write_file.cc
+++ b/tools/gn/function_write_file.cc
@@ -29,7 +29,7 @@ const char kWriteFile_Help[] =
" TODO(brettw) we probably need an optional third argument to control\n"
" list formatting.\n"
"\n"
- "Arguments:\n"
+ "Arguments\n"
"\n"
" filename\n"
" Filename to write. This must be within the output directory.\n"
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc
index ade3643..bac4b8e 100644
--- a/tools/gn/functions.cc
+++ b/tools/gn/functions.cc
@@ -562,6 +562,7 @@ struct FunctionInfoInitializer {
INSERT_FUNCTION(Print)
INSERT_FUNCTION(ProcessFileTemplate)
INSERT_FUNCTION(ReadFile)
+ INSERT_FUNCTION(RebasePath)
INSERT_FUNCTION(SetDefaults)
INSERT_FUNCTION(SetDefaultToolchain)
INSERT_FUNCTION(SetSourcesAssignmentFilter)
@@ -569,7 +570,6 @@ struct FunctionInfoInitializer {
INSERT_FUNCTION(StaticLibrary)
INSERT_FUNCTION(Template)
INSERT_FUNCTION(Test)
- INSERT_FUNCTION(ToBuildPath)
INSERT_FUNCTION(Tool)
INSERT_FUNCTION(Toolchain)
INSERT_FUNCTION(ToolchainArgs)
diff --git a/tools/gn/functions.h b/tools/gn/functions.h
index 0ced17c..9c419cc 100644
--- a/tools/gn/functions.h
+++ b/tools/gn/functions.h
@@ -157,6 +157,13 @@ Value RunReadFile(Scope* scope,
const std::vector<Value>& args,
Err* err);
+extern const char kRebasePath[];
+extern const char kRebasePath_Help[];
+Value RunRebasePath(Scope* scope,
+ const FunctionCallNode* function,
+ const std::vector<Value>& args,
+ Err* err);
+
extern const char kSetDefaults[];
extern const char kSetDefaults_Help[];
Value RunSetDefaults(Scope* scope,
@@ -211,13 +218,6 @@ Value RunTest(Scope* scope,
BlockNode* block,
Err* err);
-extern const char kToBuildPath[];
-extern const char kToBuildPath_Help[];
-Value RunToBuildPath(Scope* scope,
- const FunctionCallNode* function,
- const std::vector<Value>& args,
- Err* err);
-
extern const char kTool[];
extern const char kTool_Help[];
Value RunTool(Scope* scope,
diff --git a/tools/gn/functions_target.cc b/tools/gn/functions_target.cc
index eba5073..62b7645 100644
--- a/tools/gn/functions_target.cc
+++ b/tools/gn/functions_target.cc
@@ -133,7 +133,8 @@ const char kCopy_Help[] =
" expansion (see \"gn help source_expansion\"). The placeholders will\n"
" will look like \"{{source_name_part}}\", for example.\n"
"\n"
- "Examples:\n"
+ "Examples\n"
+ "\n"
" # Write a rule that copies a checked-in DLL to the output directory.\n"
" copy(\"mydll\") {\n"
" sources = [ \"mydll.dll\" ]\n"
@@ -207,12 +208,12 @@ const char kCustom_Help[] =
" will look like \"{{source}}\", for example, and can appear in\n"
" either the outputs or the args lists.\n"
"\n"
- "Variables:\n"
+ "Variables\n"
"\n"
" args, deps, outputs, script*, source_prereqs, sources\n"
" * = required\n"
"\n"
- "Examples:\n"
+ "Examples\n"
"\n"
" # Runs the script over each IDL file. The IDL script will generate\n"
" # both a .cc and a .h file for each input.\n"
@@ -254,7 +255,8 @@ const char kExecutable[] = "executable";
const char kExecutable_Help[] =
"executable: Declare an executable target.\n"
"\n"
- "Variables:\n"
+ "Variables\n"
+ "\n"
CONFIG_VALUES_VARS_HELP
DEPS_VARS
DEPENDENT_CONFIG_VARS
@@ -284,12 +286,14 @@ const char kGroup_Help[] =
" through the group so you shouldn't need to use\n"
" \"forward_dependent_configs_from.\n"
"\n"
- "Variables:\n"
+ "Variables\n"
+ "\n"
DEPS_VARS
DEPENDENT_CONFIG_VARS
" Other variables: external\n"
"\n"
- "Example:\n"
+ "Example\n"
+ "\n"
" group(\"all\") {\n"
" deps = [\n"
" \"//project:runner\",\n"
@@ -317,7 +321,8 @@ const char kSharedLibrary_Help[] =
" (say you dynamically load the library at runtime), then you should\n"
" depend on the shared library via \"datadeps\" instead.\n"
"\n"
- "Variables:\n"
+ "Variables\n"
+ "\n"
CONFIG_VALUES_VARS_HELP
DEPS_VARS
DEPENDENT_CONFIG_VARS
@@ -338,7 +343,8 @@ const char kStaticLibrary[] = "static_library";
const char kStaticLibrary_Help[] =
"static_library: Declare a static library target.\n"
"\n"
- "Variables:\n"
+ "Variables\n"
+ "\n"
CONFIG_VALUES_VARS_HELP
DEPS_VARS
DEPENDENT_CONFIG_VARS
diff --git a/tools/gn/gn.gyp b/tools/gn/gn.gyp
index 4411c52..52c928e 100644
--- a/tools/gn/gn.gyp
+++ b/tools/gn/gn.gyp
@@ -48,10 +48,10 @@
'function_exec_script.cc',
'function_process_file_template.cc',
'function_read_file.cc',
+ 'function_rebase_path.cc',
'function_set_default_toolchain.cc',
'function_set_defaults.cc',
'function_template.cc',
- 'function_to_build_path.cc',
'function_toolchain.cc',
'function_write_file.cc',
'group_target_generator.cc',
@@ -166,7 +166,7 @@
'escape_unittest.cc',
'file_template_unittest.cc',
'filesystem_utils_unittest.cc',
- 'function_to_build_path_unittest.cc',
+ 'function_rebase_path_unittest.cc',
'input_conversion_unittest.cc',
'label_unittest.cc',
'ninja_helper_unittest.cc',
diff --git a/tools/gn/pattern.cc b/tools/gn/pattern.cc
index b7f4229..7a198e9 100644
--- a/tools/gn/pattern.cc
+++ b/tools/gn/pattern.cc
@@ -26,7 +26,8 @@ const char kPattern_Help[] =
" \\b Matches a path boundary. This will match the beginning or end of\n"
" a string, or a slash.\n"
"\n"
- "Examples:\n"
+ "Examples\n"
+ "\n"
" \"*asdf*\"\n"
" Matches a string containing \"asdf\" anywhere.\n"
"\n"
diff --git a/tools/gn/scope_per_file_provider.cc b/tools/gn/scope_per_file_provider.cc
index 1990193..525aab6 100644
--- a/tools/gn/scope_per_file_provider.cc
+++ b/tools/gn/scope_per_file_provider.cc
@@ -27,6 +27,8 @@ const Value* ScopePerFileProvider::GetProgrammaticValue(
if (ident == variables::kPythonPath)
return GetPythonPath();
+ if (ident == variables::kRootBuildDir)
+ return GetRootBuildDir();
if (ident == variables::kRootGenDir)
return GetRootGenDir();
if (ident == variables::kRootOutDir)
@@ -65,10 +67,18 @@ const Value* ScopePerFileProvider::GetPythonPath() {
return python_path_.get();
}
+const Value* ScopePerFileProvider::GetRootBuildDir() {
+ if (!root_build_dir_) {
+ root_build_dir_.reset(new Value(NULL,
+ "/" + GetRootOutputDirWithNoLastSlash(scope_->settings())));
+ }
+ return root_build_dir_.get();
+}
+
const Value* ScopePerFileProvider::GetRootGenDir() {
if (!root_gen_dir_) {
root_gen_dir_.reset(new Value(NULL,
- "/" + GetRootGenDirWithNoLastSlash(scope_->settings())));
+ "/" + GetToolchainGenDirWithNoLastSlash(scope_->settings())));
}
return root_gen_dir_.get();
}
@@ -76,7 +86,7 @@ const Value* ScopePerFileProvider::GetRootGenDir() {
const Value* ScopePerFileProvider::GetRootOutDir() {
if (!root_out_dir_) {
root_out_dir_.reset(new Value(NULL,
- "/" + GetRootOutputDirWithNoLastSlash(scope_->settings())));
+ "/" + GetToolchainOutputDirWithNoLastSlash(scope_->settings())));
}
return root_out_dir_.get();
}
@@ -85,7 +95,7 @@ const Value* ScopePerFileProvider::GetTargetGenDir() {
if (!target_gen_dir_) {
target_gen_dir_.reset(new Value(NULL,
"/" +
- GetRootGenDirWithNoLastSlash(scope_->settings()) +
+ GetToolchainGenDirWithNoLastSlash(scope_->settings()) +
GetFileDirWithNoLastSlash()));
}
return target_gen_dir_.get();
@@ -95,7 +105,7 @@ const Value* ScopePerFileProvider::GetTargetOutDir() {
if (!target_out_dir_) {
target_out_dir_.reset(new Value(NULL,
"/" +
- GetRootOutputDirWithNoLastSlash(scope_->settings()) + "/obj" +
+ GetToolchainOutputDirWithNoLastSlash(scope_->settings()) + "/obj" +
GetFileDirWithNoLastSlash()));
}
return target_out_dir_.get();
@@ -117,9 +127,28 @@ std::string ScopePerFileProvider::GetRootOutputDirWithNoLastSlash(
}
// static
-std::string ScopePerFileProvider::GetRootGenDirWithNoLastSlash(
+std::string ScopePerFileProvider::GetToolchainOutputDirWithNoLastSlash(
+ const Settings* settings) {
+ const OutputFile& toolchain_subdir = settings->toolchain_output_subdir();
+
+ std::string result;
+ if (toolchain_subdir.value().empty()) {
+ result = GetRootOutputDirWithNoLastSlash(settings);
+ } else {
+ // The toolchain subdir ends in a slash, trim it.
+ result = GetRootOutputDirWithNoLastSlash(settings) + "/" +
+ toolchain_subdir.value();
+ DCHECK(toolchain_subdir.value()[toolchain_subdir.value().size() - 1] ==
+ '/');
+ result.resize(result.size() - 1);
+ }
+ return result;
+}
+
+// static
+std::string ScopePerFileProvider::GetToolchainGenDirWithNoLastSlash(
const Settings* settings) {
- return GetRootOutputDirWithNoLastSlash(settings) + "/gen";
+ return GetToolchainOutputDirWithNoLastSlash(settings) + "/gen";
}
std::string ScopePerFileProvider::GetFileDirWithNoLastSlash() const {
diff --git a/tools/gn/scope_per_file_provider.h b/tools/gn/scope_per_file_provider.h
index d406c2f..362ac6a 100644
--- a/tools/gn/scope_per_file_provider.h
+++ b/tools/gn/scope_per_file_provider.h
@@ -25,13 +25,17 @@ class ScopePerFileProvider : public Scope::ProgrammaticProvider {
const Value* GetCurrentToolchain();
const Value* GetDefaultToolchain();
const Value* GetPythonPath();
+ const Value* GetRootBuildDir();
const Value* GetRootGenDir();
const Value* GetRootOutDir();
const Value* GetTargetGenDir();
const Value* GetTargetOutDir();
static std::string GetRootOutputDirWithNoLastSlash(const Settings* settings);
- static std::string GetRootGenDirWithNoLastSlash(const Settings* settings);
+ static std::string GetToolchainOutputDirWithNoLastSlash(
+ const Settings* settings);
+ static std::string GetToolchainGenDirWithNoLastSlash(
+ const Settings* settings);
std::string GetFileDirWithNoLastSlash() const;
@@ -39,6 +43,7 @@ class ScopePerFileProvider : public Scope::ProgrammaticProvider {
scoped_ptr<Value> current_toolchain_;
scoped_ptr<Value> default_toolchain_;
scoped_ptr<Value> python_path_;
+ scoped_ptr<Value> root_build_dir_;
scoped_ptr<Value> root_gen_dir_;
scoped_ptr<Value> root_out_dir_;
scoped_ptr<Value> target_gen_dir_;
diff --git a/tools/gn/scope_per_file_provider_unittest.cc b/tools/gn/scope_per_file_provider_unittest.cc
index 4abada8..1137d3b 100644
--- a/tools/gn/scope_per_file_provider_unittest.cc
+++ b/tools/gn/scope_per_file_provider_unittest.cc
@@ -20,23 +20,40 @@ TEST(ScopePerFileProvider, Expected) {
build_settings.SetBuildDir(SourceDir("//out/Debug/"));
- Toolchain toolchain(Label(SourceDir("//toolchain/"), "tc", SourceDir(), ""));
- Settings settings(&build_settings, &toolchain, std::string());
- Scope scope(&settings);
- scope.set_source_dir(SourceDir("//source/"));
-
- ScopePerFileProvider provider(&scope);
-
- EXPECT_EQ("//toolchain:tc", provider.GetProgrammaticValue(
- variables::kCurrentToolchain)->string_value());
- EXPECT_EQ("//toolchain:default", provider.GetProgrammaticValue(
- variables::kDefaultToolchain)->string_value());
- EXPECT_EQ("//out/Debug/gen",provider.GetProgrammaticValue(
- variables::kRootGenDir)->string_value());
- EXPECT_EQ("//out/Debug",provider.GetProgrammaticValue(
- variables::kRootOutDir)->string_value());
- EXPECT_EQ("//out/Debug/gen/source",provider.GetProgrammaticValue(
- variables::kTargetGenDir)->string_value());
- EXPECT_EQ("//out/Debug/obj/source",provider.GetProgrammaticValue(
- variables::kTargetOutDir)->string_value());
+// Prevent horrible wrapping of calls below.
+#define GPV(val) provider.GetProgrammaticValue(val)->string_value()
+
+ // Test the default toolchain.
+ {
+ Toolchain toolchain(Label(SourceDir("//toolchain/"), "tc"));
+ Settings settings(&build_settings, &toolchain, std::string());
+
+ Scope scope(&settings);
+ scope.set_source_dir(SourceDir("//source/"));
+ ScopePerFileProvider provider(&scope);
+
+ EXPECT_EQ("//toolchain:tc", GPV(variables::kCurrentToolchain));
+ EXPECT_EQ("//toolchain:default", GPV(variables::kDefaultToolchain));
+ EXPECT_EQ("//out/Debug", GPV(variables::kRootBuildDir));
+ EXPECT_EQ("//out/Debug/gen", GPV(variables::kRootGenDir));
+ EXPECT_EQ("//out/Debug", GPV(variables::kRootOutDir));
+ EXPECT_EQ("//out/Debug/gen/source", GPV(variables::kTargetGenDir));
+ EXPECT_EQ("//out/Debug/obj/source", GPV(variables::kTargetOutDir));
+ }
+
+ // Test some with an alternate toolchain.
+ {
+ Toolchain toolchain(Label(SourceDir("//toolchain/"), "tc"));
+ Settings settings(&build_settings, &toolchain, "tc");
+
+ Scope scope(&settings);
+ scope.set_source_dir(SourceDir("//source/"));
+ ScopePerFileProvider provider(&scope);
+
+ EXPECT_EQ("//out/Debug", GPV(variables::kRootBuildDir));
+ EXPECT_EQ("//out/Debug/tc/gen", GPV(variables::kRootGenDir));
+ EXPECT_EQ("//out/Debug/tc", GPV(variables::kRootOutDir));
+ EXPECT_EQ("//out/Debug/tc/gen/source", GPV(variables::kTargetGenDir));
+ EXPECT_EQ("//out/Debug/tc/obj/source", GPV(variables::kTargetOutDir));
+ }
}
diff --git a/tools/gn/secondary/base/BUILD.gn b/tools/gn/secondary/base/BUILD.gn
index 6455ff2..ca26584 100644
--- a/tools/gn/secondary/base/BUILD.gn
+++ b/tools/gn/secondary/base/BUILD.gn
@@ -969,8 +969,8 @@ static_library("test_support_base") {
if (!is_posix) {
sources -= [
- "scoped_locale.cc",
- "scoped_locale.h",
+ "test/scoped_locale.cc",
+ "test/scoped_locale.h",
]
}
if (is_ios) {
diff --git a/tools/gn/secondary/chrome/BUILD.gn b/tools/gn/secondary/chrome/BUILD.gn
index 53d772c..4ba0c43 100644
--- a/tools/gn/secondary/chrome/BUILD.gn
+++ b/tools/gn/secondary/chrome/BUILD.gn
@@ -183,7 +183,8 @@ static_library("utility") {
# Credits ----------------------------------------------------------------------
about_credits_file = "$root_gen_dir/about_credits.html"
-build_relative_about_credits_file = to_build_path(about_credits_file)
+build_relative_about_credits_file =
+ rebase_path(about_credits_file, ".", root_build_dir)
custom("about_credits") {
script = "//tools/licenses.py"
@@ -194,7 +195,7 @@ custom("about_credits") {
# is added or removed, it will change the result, but there is no way to
# express this as a build dependency. We approximate this by depending on
# the last change file to force an update whenever the code is updated.
- source_deps = [ "//build/utils/LASTCHANGE" ]
+ source_prereqs = [ "//build/utils/LASTCHANGE" ]
hard_dep = true
diff --git a/tools/gn/secondary/crypto/ssl/BUILD.gn b/tools/gn/secondary/crypto/ssl/BUILD.gn
index 87f80f4..b48f111 100644
--- a/tools/gn/secondary/crypto/ssl/BUILD.gn
+++ b/tools/gn/secondary/crypto/ssl/BUILD.gn
@@ -9,8 +9,16 @@ config("ssl_preprocessor_flags") {
defines = [ "USE_OPENSSL" ]
} else if (use_nss) {
defines = [ "USE_NSS" ]
- } else {
- assert(false) # Either OpenSSL or NSS should be defined.
+ }
+}
+
+# Config for system SSL on Linux.
+if (is_linux && use_system_ssl) {
+ pkg_script = "//build/config/linux/pkg-config.py"
+ config("system_ssl_config") {
+ defines = [ "USE_SYSTEM_SSL" ]
+ cflags = exec_script(pkg_script, [ "--cflags", "nss" ], "list lines")
+ ldflags = exec_script(pkg_script, [ "--libs", "nss" ], "list lines")
}
}
@@ -18,10 +26,16 @@ config("ssl_preprocessor_flags") {
group("metassl") {
direct_dependent_configs = [ ":ssl_preprocessor_flags" ]
- deps = []
- if (is_linux) {
- # TODO(brettw) figure this out.
- deps += [ "//net/third_party/nss/ssl" ]
+ if (use_openssl) {
+ assert(is_linux)
+ deps = "//third_party/openssl"
+ use_openssl = false
+ } else if (use_system_ssl) {
+ assert(is_linux)
+ direct_dependent_configs = ":system_ssl_config"
+ } else {
+ deps = [ "//net/third_party/nss/ssl" ]
}
+
forward_dependent_configs_from = deps
}
diff --git a/tools/gn/secondary/crypto/ssl/flags.gni b/tools/gn/secondary/crypto/ssl/flags.gni
index 598ad71..aac6e96 100644
--- a/tools/gn/secondary/crypto/ssl/flags.gni
+++ b/tools/gn/secondary/crypto/ssl/flags.gni
@@ -2,9 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# This file declares build flags for
+# This file declares build flags for the SSL library configuration.
declare_args() {
+ # Use OpenSSL instead of NSS. This is used for Android and is experimental
+ # in other cases (see http://crbug.com/62803).
use_openssl = false
# Use the built-in system SSL library rather than our tree's libnss/OpenSSL.
diff --git a/tools/gn/secondary/skia/BUILD.gn b/tools/gn/secondary/skia/BUILD.gn
index a3fd838..7f16db3 100644
--- a/tools/gn/secondary/skia/BUILD.gn
+++ b/tools/gn/secondary/skia/BUILD.gn
@@ -635,6 +635,7 @@ static_library("skia_library") {
# ["exclude", "opts_check_SSE2\\.cpp$"],
# ],
+ includes = []
if (is_win) {
includes += [
"//third_party/skia/include/utils/win",
diff --git a/tools/gn/secondary/third_party/expat/BUILD.gn b/tools/gn/secondary/third_party/expat/BUILD.gn
index 4fcb84e..1ff7b14 100644
--- a/tools/gn/secondary/third_party/expat/BUILD.gn
+++ b/tools/gn/secondary/third_party/expat/BUILD.gn
@@ -10,4 +10,28 @@ if (is_linux) {
group("expat") {
direct_dependent_configs = [ ":expat_config" ]
}
+
+ # TODO(brettw) Android needs direct dependent includes of
+ # <android_src>/external/expat/lib
+} else {
+ config("expat_config") {
+ includes = [ "files/lib" ]
+ defines = [ "XML_STATIC" ]
+ }
+
+ static_library("expat") {
+ sources = [
+ "files/lib/expat.h",
+ "files/lib/xmlparse.c",
+ "files/lib/xmlrole.c",
+ "files/lib/xmltok.c",
+ ]
+
+ defines = [ "_LIB" ]
+ if (is_win) {
+ defines += "COMPILED_FROM_DSP"
+ } else {
+ defines += "HAVE_EXPAT_CONFIG_H"
+ }
+ }
}
diff --git a/tools/gn/secondary/third_party/icu/BUILD.gn b/tools/gn/secondary/third_party/icu/BUILD.gn
index 4c76ffe..1a55536 100644
--- a/tools/gn/secondary/third_party/icu/BUILD.gn
+++ b/tools/gn/secondary/third_party/icu/BUILD.gn
@@ -404,7 +404,7 @@ if (is_win) {
copy("icudata") {
external = true
sources = [ "windows/icudt.dll" ]
- outputs = [ "$root_output_dir/icudt.dll" ]
+ outputs = [ "$root_out_dir/icudt.dll" ]
}
} else {
static_library("icudata") {
diff --git a/tools/gn/secondary/third_party/libusb/BUILD.gn b/tools/gn/secondary/third_party/libusb/BUILD.gn
index 9bdd38e..2517df8 100644
--- a/tools/gn/secondary/third_party/libusb/BUILD.gn
+++ b/tools/gn/secondary/third_party/libusb/BUILD.gn
@@ -50,7 +50,6 @@ static_library("libusb") {
configs -= "//build/config/compiler:chromium_code"
configs += "//build/config/compiler:no_chromium_code"
- configs += "//build/config/linux:udev"
direct_dependent_configs = [ ":libusb_config" ]
@@ -64,13 +63,6 @@ static_library("libusb") {
"POLL_NFDS_TYPE=nfds_t",
"THREADS_POSIX=1",
]
- } else {
- sources -= [
- "src/libusb/os/poll_posix.c",
- "src/libusb/os/poll_posix.h",
- "src/libusb/os/threads_posix.c",
- "src/libusb/os/threads_posix.h",
- ]
}
if (is_mac) {
@@ -89,6 +81,7 @@ static_library("libusb") {
"USE_UDEV=1",
"_GNU_SOURCE=1",
]
+ configs += "//build/config/linux:udev"
} else {
sources -= [
"src/libusb/os/linux_udev.c",
diff --git a/tools/gn/secondary/tools/grit/grit_rule.gni b/tools/gn/secondary/tools/grit/grit_rule.gni
index 3db2c33..32e5409 100644
--- a/tools/gn/secondary/tools/grit/grit_rule.gni
+++ b/tools/gn/secondary/tools/grit/grit_rule.gni
@@ -19,25 +19,32 @@ template("grit") {
"Neither \"sources\" nor \"outputs\" can be defined for the grit " +
"template $target_name")
- resource_ids = to_build_path("//tools/gritsettings/resource_ids")
- output_dir = to_build_path(target_gen_dir)
- grit_info_script = to_build_path("//tools/grit/grit_info.py")
- source_path = to_build_path(source)
+ grit_info_script = "//tools/grit/grit_info.py"
+
+ # These are all passed as arguments to the script so have to be relative to
+ # the build directory.
+ resource_ids =
+ rebase_path("//tools/gritsettings/resource_ids", ".", root_build_dir)
+ output_dir = rebase_path(target_gen_dir, ".", root_build_dir)
+ source_path = rebase_path(source, ".", root_build_dir)
if (!defined(grit_flags)) {
grit_flags = [] # These are optional so default to empty list.
}
- # TODO(brettw) these are wrong because grit outputs the file names relative
- # to its current directory (the build output) and we want them relative
- # to the current input directory. We need a way to rebase the paths we get
- # back.
- grit_inputs = exec_script(grit_info_script,
+ grit_inputs_build_rel = exec_script(grit_info_script,
[ "--inputs", source_path, "-f", resource_ids] + grit_flags, "list lines")
- grit_outputs = exec_script(grit_info_script,
+ # The inputs are relative to the current (build) directory, rebase to
+ # the current one.
+ grit_inputs = rebase_path(grit_inputs_build_rel, root_build_dir, ".")
+
+ grit_outputs_build_rel = exec_script(grit_info_script,
[ "--outputs", "$output_dir", source_path, "-f", resource_ids ] +
grit_flags,
"list lines")
+ # The inputs are relative to the current (build) directory, rebase to
+ # the current one.
+ grit_outputs = rebase_path(grit_outputs_build_rel, root_build_dir, ".")
# The current grit setup makes an file in $target_gen_dir/grit/foo.h that
# the source code expects to include via "grit/foo.h". It would be nice to
@@ -70,7 +77,6 @@ template("grit") {
# Since we generate a file, we need to be run before the targets that
# depend on us.
hard_dep = true
-
sources = grit_outputs
# Deps set on the template invocation will go on the grit script running
diff --git a/tools/gn/settings.cc b/tools/gn/settings.cc
index 63b8afb..bfab85d 100644
--- a/tools/gn/settings.cc
+++ b/tools/gn/settings.cc
@@ -32,7 +32,6 @@ Settings::Settings(const BuildSettings* build_settings,
if (!toolchain_output_dir_.is_null())
toolchain_gen_dir_ = SourceDir(toolchain_output_dir_.value() + "gen/");
-
#if defined(OS_WIN)
target_os_ = WIN;
#elif defined(OS_MACOSX)
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc
index 3ab34f2..28f8ec6 100644
--- a/tools/gn/setup.cc
+++ b/tools/gn/setup.cc
@@ -28,7 +28,8 @@ extern const char kDotfile_Help[] =
" same as a buildfile, but with very limited build setup-specific\n"
" meaning.\n"
"\n"
- "Variables:\n"
+ "Variables\n"
+ "\n"
" buildconfig [required]\n"
" Label of the build config file. This file will be used to setup\n"
" the build file execution environment for each toolchain.\n"
@@ -45,7 +46,7 @@ extern const char kDotfile_Help[] =
"\n"
" The secondary source root must be inside the main source tree.\n"
"\n"
- "Example .gn file contents:\n"
+ "Example .gn file contents\n"
"\n"
" buildconfig = \"//build/config/BUILDCONFIG.gn\"\n"
"\n"
@@ -110,8 +111,8 @@ bool Setup::DoSetup() {
// FIXME(brettw) get python path!
#if defined(OS_WIN)
- build_settings_.set_python_path(
- base::FilePath(FILE_PATH_LITERAL("cmd.exe /c python")));
+ build_settings_.set_python_path(base::FilePath(
+ FILE_PATH_LITERAL("python.exe")));
#else
build_settings_.set_python_path(base::FilePath(FILE_PATH_LITERAL("python")));
#endif
diff --git a/tools/gn/variables.cc b/tools/gn/variables.cc
index 499ba6b..baacb3c 100644
--- a/tools/gn/variables.cc
+++ b/tools/gn/variables.cc
@@ -97,6 +97,18 @@ const char kPythonPath_Help[] =
" requires Python. You will normally not need this when invoking scripts\n"
" since GN automatically finds it for you.\n";
+const char kRootBuildDir[] = "root_build_dir";
+const char kRootBuildDir_HelpShort[] =
+ "root_build_dir: [string] Directory where build commands are run.";
+const char kRootBuildDir_Help[] =
+ "root_build_dir: [string] Directory where build commands are run.\n"
+ "\n"
+ " This is the root build output directory which will be the current\n"
+ " directory when executing all compilers and scripts.\n"
+ "\n"
+ " Most often this is used with rebase_path (see \"gn help rebase_path\")\n"
+ " to convert arguments to be relative to a script's current directory.\n";
+
const char kRootGenDir[] = "root_gen_dir";
const char kRootGenDir_HelpShort[] =
"root_gen_dir: [string] Directory for the toolchain's generated files.";
@@ -647,6 +659,7 @@ const VariableInfoMap& GetBuiltinVariables() {
INSERT_VARIABLE(IsPosix)
INSERT_VARIABLE(IsWin)
INSERT_VARIABLE(PythonPath)
+ INSERT_VARIABLE(RootBuildDir)
INSERT_VARIABLE(RootGenDir)
INSERT_VARIABLE(RootOutDir)
INSERT_VARIABLE(TargetGenDir)
diff --git a/tools/gn/variables.h b/tools/gn/variables.h
index ab27eafa..703ebde 100644
--- a/tools/gn/variables.h
+++ b/tools/gn/variables.h
@@ -45,6 +45,10 @@ extern const char kPythonPath[];
extern const char kPythonPath_HelpShort[];
extern const char kPythonPath_Help[];
+extern const char kRootBuildDir[];
+extern const char kRootBuildDir_HelpShort[];
+extern const char kRootBuildDir_Help[];
+
extern const char kRootGenDir[];
extern const char kRootGenDir_HelpShort[];
extern const char kRootGenDir_Help[];