summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/gn/binary_target_generator.cc3
-rw-r--r--tools/gn/build_settings.cc5
-rw-r--r--tools/gn/build_settings.h4
-rw-r--r--tools/gn/command_desc.cc21
-rw-r--r--tools/gn/config_values_generator.cc4
-rw-r--r--tools/gn/filesystem_utils.cc56
-rw-r--r--tools/gn/filesystem_utils.h16
-rw-r--r--tools/gn/filesystem_utils_unittest.cc37
-rw-r--r--tools/gn/function_exec_script.cc2
-rw-r--r--tools/gn/function_read_file.cc2
-rw-r--r--tools/gn/function_set_default_toolchain.cc2
-rw-r--r--tools/gn/function_toolchain.cc2
-rw-r--r--tools/gn/function_write_file.cc2
-rw-r--r--tools/gn/functions.cc131
-rw-r--r--tools/gn/functions.h24
-rw-r--r--tools/gn/import_manager.cc1
-rw-r--r--tools/gn/ninja_script_target_writer.cc75
-rw-r--r--tools/gn/parse_tree.cc6
-rw-r--r--tools/gn/parse_tree.h4
-rw-r--r--tools/gn/scheduler.cc18
-rw-r--r--tools/gn/scope.cc8
-rw-r--r--tools/gn/scope.h9
-rw-r--r--tools/gn/scope_per_file_provider.cc17
-rw-r--r--tools/gn/script_target_generator.cc5
-rw-r--r--tools/gn/secondary/net/BUILD.gn42
-rw-r--r--tools/gn/secondary/tools/grit/grit_rule.gni19
-rw-r--r--tools/gn/setup.cc2
-rw-r--r--tools/gn/source_dir.cc35
-rw-r--r--tools/gn/source_dir.h12
-rw-r--r--tools/gn/target.cc22
-rw-r--r--tools/gn/target.h3
-rw-r--r--tools/gn/target_generator.cc20
-rw-r--r--tools/gn/target_generator.h4
-rw-r--r--tools/gn/toolchain_manager.cc2
-rw-r--r--tools/gn/value_extractors.cc33
-rw-r--r--tools/gn/value_extractors.h7
36 files changed, 493 insertions, 162 deletions
diff --git a/tools/gn/binary_target_generator.cc b/tools/gn/binary_target_generator.cc
index d7e488a..4638be4 100644
--- a/tools/gn/binary_target_generator.cc
+++ b/tools/gn/binary_target_generator.cc
@@ -6,6 +6,7 @@
#include "tools/gn/config_values_generator.h"
#include "tools/gn/err.h"
+#include "tools/gn/scope.h"
BinaryTargetGenerator::BinaryTargetGenerator(Target* target,
Scope* scope,
@@ -27,7 +28,7 @@ void BinaryTargetGenerator::DoRun() {
// Config values (compiler flags, etc.) set directly on this target.
ConfigValuesGenerator gen(&target_->config_values(), scope_,
- function_token_, input_directory_, err_);
+ function_token_, scope_->GetSourceDir(), err_);
gen.Run();
if (err_->has_error())
return;
diff --git a/tools/gn/build_settings.cc b/tools/gn/build_settings.cc
index 09b4c99..ebe0323 100644
--- a/tools/gn/build_settings.cc
+++ b/tools/gn/build_settings.cc
@@ -15,6 +15,11 @@ BuildSettings::BuildSettings()
BuildSettings::~BuildSettings() {
}
+void BuildSettings::SetRootPath(const base::FilePath& r) {
+ root_path_ = r;
+ root_path_utf8_ = FilePathToUTF8(root_path_);
+}
+
void BuildSettings::SetSecondarySourcePath(const SourceDir& d) {
secondary_source_path_ = GetFullPath(d);
}
diff --git a/tools/gn/build_settings.h b/tools/gn/build_settings.h
index 376c8b4..454eca4 100644
--- a/tools/gn/build_settings.h
+++ b/tools/gn/build_settings.h
@@ -28,7 +28,8 @@ class BuildSettings {
// Absolute path of the source root on the local system. Everything is
// relative to this.
const base::FilePath& root_path() const { return root_path_; }
- void set_root_path(const base::FilePath& r) { root_path_ = r; }
+ const std::string& root_path_utf8() const { return root_path_utf8_; }
+ void SetRootPath(const base::FilePath& r);
// When nonempty, specifies a parallel directory higherarchy in which to
// search for buildfiles if they're not found in the root higherarchy. This
@@ -95,6 +96,7 @@ class BuildSettings {
private:
base::FilePath root_path_;
+ std::string root_path_utf8_;
base::FilePath secondary_source_path_;
base::FilePath python_path_;
diff --git a/tools/gn/command_desc.cc b/tools/gn/command_desc.cc
index b004042..9139d43 100644
--- a/tools/gn/command_desc.cc
+++ b/tools/gn/command_desc.cc
@@ -27,11 +27,17 @@ struct CompareTargetLabel {
}
};
+void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result);
+
void RecursiveCollectDeps(const Target* target, std::set<Label>* result) {
if (result->find(target->label()) != result->end())
return; // Already did this target.
result->insert(target->label());
+ RecursiveCollectChildDeps(target, result);
+}
+
+void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result) {
const std::vector<const Target*>& deps = target->deps();
for (size_t i = 0; i < deps.size(); i++)
RecursiveCollectDeps(deps[i], result);
@@ -78,7 +84,7 @@ void PrintDeps(const Target* target, bool display_header) {
OutputString("\nAll recursive dependencies:\n");
std::set<Label> all_deps;
- RecursiveCollectDeps(target, &all_deps);
+ RecursiveCollectChildDeps(target, &all_deps);
for (std::set<Label>::iterator i = all_deps.begin();
i != all_deps.end(); ++i)
deps.push_back(*i);
@@ -326,14 +332,13 @@ int RunDesc(const std::vector<std::string>& args) {
Label target_toolchain = target->label().GetToolchainLabel();
// Header.
- std::string title_target =
- "Target: " + target->label().GetUserVisibleName(false);
- std::string title_toolchain =
- "Toolchain: " + target_toolchain.GetUserVisibleName(false);
- OutputString(title_target + "\n", DECORATION_YELLOW);
- OutputString(title_toolchain + "\n", DECORATION_YELLOW);
+ OutputString("Target: ", DECORATION_YELLOW);
+ OutputString(target->label().GetUserVisibleName(false) + "\n");
+ OutputString("Type: ", DECORATION_YELLOW);
OutputString(std::string(
- std::max(title_target.size(), title_toolchain.size()), '=') + "\n");
+ Target::GetStringForOutputType(target->output_type())) + "\n");
+ OutputString("Toolchain: ", DECORATION_YELLOW);
+ OutputString(target_toolchain.GetUserVisibleName(false) + "\n");
PrintSources(target, true);
PrintConfigs(target, true);
diff --git a/tools/gn/config_values_generator.cc b/tools/gn/config_values_generator.cc
index 46c9e88..c6b68ca 100644
--- a/tools/gn/config_values_generator.cc
+++ b/tools/gn/config_values_generator.cc
@@ -6,6 +6,7 @@
#include "tools/gn/config_values.h"
#include "tools/gn/scope.h"
+#include "tools/gn/settings.h"
#include "tools/gn/value.h"
#include "tools/gn/value_extractors.h"
@@ -67,7 +68,8 @@ void ConfigValuesGenerator::FillIncludes() {
return; // No value, empty input and succeed.
std::vector<SourceDir> includes;
- if (!ExtractListOfRelativeDirs(*value, input_dir_, &includes, err_))
+ if (!ExtractListOfRelativeDirs(scope_->settings()->build_settings(),
+ *value, input_dir_, &includes, err_))
return;
config_values_->swap_in_includes(&includes);
}
diff --git a/tools/gn/filesystem_utils.cc b/tools/gn/filesystem_utils.cc
index d3d60c4..dfaa303 100644
--- a/tools/gn/filesystem_utils.cc
+++ b/tools/gn/filesystem_utils.cc
@@ -251,6 +251,62 @@ bool EnsureStringIsInOutputDir(const SourceDir& dir,
return true;
}
+bool IsPathAbsolute(const base::StringPiece& path) {
+ if (path.empty())
+ return false;
+
+ if (path[0] != '/') {
+#if defined(OS_WIN)
+ // Check for Windows system paths like "C:\foo".
+ if (path.size() > 2 &&
+ path[1] == ':' && (path[2] == '/' || path[2] == '\\'))
+ return true;
+#endif
+ return false; // Doesn't begin with a slash, is relative.
+ }
+
+ if (path.size() > 1 && path[1] == '/')
+ return false; // Double slash at the beginning means source-relative.
+
+ return true;
+}
+
+bool MakeAbsolutePathRelativeIfPossible(const base::StringPiece& source_root,
+ const base::StringPiece& path,
+ std::string* dest) {
+ DCHECK(IsPathAbsolute(source_root));
+ DCHECK(IsPathAbsolute(path));
+
+ dest->clear();
+
+ if (source_root.size() > path.size())
+ return false; // The source root is longer: the path can never be inside.
+
+#if defined(OS_WIN)
+ // Source root should be canonical on Windows.
+ DCHECK(source_root.size() > 2 && source_root[0] != '/' &&
+ source_root[1] == ':' && source_root[2] =='\\');
+#error
+#else
+ // On non-Windows this is easy. Since we know both are absolute, just do a
+ // prefix check.
+ if (path.substr(0, source_root.size()) == source_root) {
+ dest->assign("//"); // Result is source root relative.
+
+ // The base may or may not have a trailing slash, so skip all slashes from
+ // the path after our prefix match.
+ size_t first_after_slash = source_root.size();
+ while (first_after_slash < path.size() && path[first_after_slash] == '/')
+ first_after_slash++;
+
+ dest->append(&path.data()[first_after_slash],
+ path.size() - first_after_slash);
+ return true;
+ }
+#endif
+ return false;
+}
+
std::string InvertDir(const SourceDir& path) {
const std::string value = path.value();
if (value.empty())
diff --git a/tools/gn/filesystem_utils.h b/tools/gn/filesystem_utils.h
index 38d64be..4ab4ec5 100644
--- a/tools/gn/filesystem_utils.h
+++ b/tools/gn/filesystem_utils.h
@@ -99,6 +99,22 @@ bool EnsureStringIsInOutputDir(const SourceDir& dir,
// ----------------------------------------------------------------------------
+// Returns true if the input string is absolute. Double-slashes at the
+// beginning are treated as source-relative paths. On Windows, this handles
+// paths of both the native format: "C:/foo" and ours "/C:/foo"
+bool IsPathAbsolute(const base::StringPiece& path);
+
+// Given an absolute path, checks to see if is it is inside the source root.
+// If it is, fills a source-absolute path into the given output and returns
+// true. If it isn't, clears the dest and returns false.
+//
+// The source_root should be a base::FilePath converted to UTF-8. On Windows,
+// it should begin with a "C:/" rather than being our SourceFile's style
+// ("/C:/"). The source root can end with a slash or not.
+bool MakeAbsolutePathRelativeIfPossible(const base::StringPiece& source_root,
+ const base::StringPiece& path,
+ std::string* dest);
+
// Converts a directory to its inverse (e.g. "/foo/bar/" -> "../../").
// This will be the empty string for the root directories ("/" and "//"), and
// in all other cases, this is guaranteed to end in a slash.
diff --git a/tools/gn/filesystem_utils_unittest.cc b/tools/gn/filesystem_utils_unittest.cc
index 75bf7cd..27e65e2 100644
--- a/tools/gn/filesystem_utils_unittest.cc
+++ b/tools/gn/filesystem_utils_unittest.cc
@@ -73,6 +73,43 @@ TEST(FilesystemUtils, FindDir) {
EXPECT_EQ("foo/bar/", FindDir(&input));
}
+TEST(FilesystemUtils, IsPathAbsolute) {
+ EXPECT_TRUE(IsPathAbsolute("/foo/bar"));
+ EXPECT_TRUE(IsPathAbsolute("/"));
+ EXPECT_FALSE(IsPathAbsolute(""));
+ EXPECT_FALSE(IsPathAbsolute("//"));
+ EXPECT_FALSE(IsPathAbsolute("//foo/bar"));
+
+#if defined(OS_WIN)
+ EXPECT_TRUE(IsPathAbsolute("C:/foo"));
+ EXPECT_TRUE(IsPathAbsolute("C:/"));
+ EXPECT_TRUE(IsPathAbsolute("C:\\foo"));
+ EXPECT_TRUE(IsPathAbsolute("C:\\"));
+ EXPECT_TRUE(IsPathAbsolute("/C:/foo"));
+ EXPECT_TRUE(IsPathAbsolute("/C:\\foo"));
+#endif
+}
+
+TEST(FilesystemUtils, MakeAbsolutePathRelativeIfPossible) {
+ std::string dest;
+
+ EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("/base", "/base/foo/", &dest));
+ EXPECT_EQ("//foo/", dest);
+ EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("/base", "/base/foo", &dest));
+ EXPECT_EQ("//foo", dest);
+ EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("/base/", "/base/foo/",
+ &dest));
+ EXPECT_EQ("//foo/", dest);
+
+ EXPECT_FALSE(MakeAbsolutePathRelativeIfPossible("/base", "/ba", &dest));
+ EXPECT_FALSE(MakeAbsolutePathRelativeIfPossible("/base", "/notbase/foo",
+ &dest));
+
+#if defined(OS_WIN)
+ //EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("
+#endif
+}
+
TEST(FilesystemUtils, InvertDir) {
EXPECT_TRUE(InvertDir(SourceDir()) == "");
EXPECT_TRUE(InvertDir(SourceDir("/")) == "");
diff --git a/tools/gn/function_exec_script.cc b/tools/gn/function_exec_script.cc
index adfa2ae..34c5e96 100644
--- a/tools/gn/function_exec_script.cc
+++ b/tools/gn/function_exec_script.cc
@@ -279,7 +279,7 @@ Value RunExecScript(Scope* scope,
const Settings* settings = scope->settings();
const BuildSettings* build_settings = settings->build_settings();
- const SourceDir& cur_dir = SourceDirForFunctionCall(function);
+ const SourceDir& cur_dir = scope->GetSourceDir();
// Find the python script to run.
if (!args[0].VerifyTypeIs(Value::STRING, err))
diff --git a/tools/gn/function_read_file.cc b/tools/gn/function_read_file.cc
index 01de7c8..af8bdb1 100644
--- a/tools/gn/function_read_file.cc
+++ b/tools/gn/function_read_file.cc
@@ -50,7 +50,7 @@ Value RunReadFile(Scope* scope,
return Value();
// Compute the file name.
- const SourceDir& cur_dir = SourceDirForFunctionCall(function);
+ const SourceDir& cur_dir = scope->GetSourceDir();
SourceFile source_file = cur_dir.ResolveRelativeFile(args[0].string_value());
base::FilePath file_path =
scope->settings()->build_settings()->GetFullPath(source_file);
diff --git a/tools/gn/function_set_default_toolchain.cc b/tools/gn/function_set_default_toolchain.cc
index f6ece07..c2b20a5 100644
--- a/tools/gn/function_set_default_toolchain.cc
+++ b/tools/gn/function_set_default_toolchain.cc
@@ -56,7 +56,7 @@ Value RunSetDefaultToolchain(Scope* scope,
if (!scope->IsProcessingDefaultBuildConfig())
return Value();
- const SourceDir& current_dir = SourceDirForFunctionCall(function);
+ const SourceDir& current_dir = scope->GetSourceDir();
const Label& default_toolchain = ToolchainLabelForScope(scope);
if (!EnsureSingleStringArg(function, args, err))
diff --git a/tools/gn/function_toolchain.cc b/tools/gn/function_toolchain.cc
index 63aa3c2..7b4458e 100644
--- a/tools/gn/function_toolchain.cc
+++ b/tools/gn/function_toolchain.cc
@@ -51,7 +51,7 @@ Value RunToolchain(Scope* scope,
// Note that we don't want to use MakeLabelForScope since that will include
// the toolchain name in the label, and toolchain labels don't themselves
// have toolchain names.
- const SourceDir& input_dir = SourceDirForFunctionCall(function);
+ const SourceDir& input_dir = scope->GetSourceDir();
Label label(input_dir, args[0].string_value(), SourceDir(), std::string());
if (g_scheduler->verbose_logging())
g_scheduler->Log("Generating toolchain", label.GetUserVisibleName(false));
diff --git a/tools/gn/function_write_file.cc b/tools/gn/function_write_file.cc
index f84f146..ea42100 100644
--- a/tools/gn/function_write_file.cc
+++ b/tools/gn/function_write_file.cc
@@ -50,7 +50,7 @@ Value RunWriteFile(Scope* scope,
// Compute the file name and make sure it's in the output dir.
if (!args[0].VerifyTypeIs(Value::STRING, err))
return Value();
- const SourceDir& cur_dir = SourceDirForFunctionCall(function);
+ const SourceDir& cur_dir = scope->GetSourceDir();
SourceFile source_file = cur_dir.ResolveRelativeFile(args[0].string_value());
if (!EnsureStringIsInOutputDir(
scope->settings()->build_settings()->build_dir(),
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc
index 11608ef..894c934 100644
--- a/tools/gn/functions.cc
+++ b/tools/gn/functions.cc
@@ -134,10 +134,6 @@ bool EnsureSingleStringArg(const FunctionCallNode* function,
return args[0].VerifyTypeIs(Value::STRING, err);
}
-const SourceDir& SourceDirForFunctionCall(const FunctionCallNode* function) {
- return function->function().location().file()->dir();
-}
-
const Label& ToolchainLabelForScope(const Scope* scope) {
return scope->settings()->toolchain()->label();
}
@@ -145,9 +141,9 @@ const Label& ToolchainLabelForScope(const Scope* scope) {
Label MakeLabelForScope(const Scope* scope,
const FunctionCallNode* function,
const std::string& name) {
- const SourceDir& input_dir = SourceDirForFunctionCall(function);
const Label& toolchain_label = ToolchainLabelForScope(scope);
- return Label(input_dir, name, toolchain_label.dir(), toolchain_label.name());
+ return Label(scope->GetSourceDir(), name, toolchain_label.dir(),
+ toolchain_label.name());
}
namespace functions {
@@ -156,20 +152,42 @@ namespace functions {
const char kAssert[] = "assert";
const char kAssert_Help[] =
- "TODO(brettw) WRITE ME";
+ "assert: Assert an expression is true at generation time.\n"
+ "\n"
+ " assert(<condition> [, <error string>])\n"
+ "\n"
+ " If the condition is false, the build will fail with an error. If the\n"
+ " optional second argument is provided, that string will be printed\n"
+ " with the error message.\n"
+ "\n"
+ "Examples:\n"
+ " assert(is_win)\n"
+ " assert(defined(sources), \"Sources must be defined\")\n";
Value RunAssert(Scope* scope,
const FunctionCallNode* function,
const std::vector<Value>& args,
Err* err) {
- if (args.size() != 1) {
+ if (args.size() != 1 && args.size() != 2) {
*err = Err(function->function(), "Wrong number of arguments.",
- "assert() takes one argument, "
+ "assert() takes one or two argument, "
"were you expecting somethig else?");
} else if (args[0].type() != Value::BOOLEAN) {
*err = Err(function->function(), "Assertion value not a bool.");
} else if (!args[0].boolean_value()) {
- *err = Err(function->function(), "Assertion failed.");
+ if (args.size() == 2) {
+ // Optional string message.
+ if (args[1].type() != Value::STRING) {
+ *err = Err(function->function(), "Assertion failed.",
+ "<<<ERROR MESSAGE IS NOT A STRING>>>");
+ } else {
+ *err = Err(function->function(), "Assertion failed.",
+ args[1].string_value());
+ }
+ } else {
+ *err = Err(function->function(), "Assertion failed.");
+ }
+
if (args[0].origin()) {
// If you do "assert(foo)" we'd ideally like to show you where foo was
// set, and in this case the origin of the args will tell us that.
@@ -219,7 +237,7 @@ Value RunConfig(const FunctionCallNode* function,
return Value();
// Fill it.
- const SourceDir input_dir = SourceDirForFunctionCall(function);
+ const SourceDir& input_dir = scope->GetSourceDir();
ConfigValuesGenerator gen(&config->config_values(), scope,
function->function(), input_dir, err);
gen.Run();
@@ -279,6 +297,46 @@ Value RunDeclareArgs(Scope* scope,
return Value();
}
+// defined ---------------------------------------------------------------------
+
+const char kDefined[] = "defined";
+const char kDefined_Help[] =
+ "defined: Returns whether an identifier is defined.\n"
+ "\n"
+ " Returns true if the given argument is defined. This is most useful in\n"
+ " templates to assert that the caller set things up properly.\n"
+ "\n"
+ "Example:\n"
+ "\n"
+ " template(\"mytemplate\") {\n"
+ " # To help users call this template properly...\n"
+ " assert(defined(sources), \"Sources must be defined\")\n"
+ "\n"
+ " # If we want to accept an optional \"values\" argument, we don't\n"
+ " # want to dereference something that may not be defined.\n"
+ " if (!defined(outputs)) {\n"
+ " outputs = []\n"
+ " }\n"
+ " }\n";
+
+Value RunDefined(Scope* scope,
+ const FunctionCallNode* function,
+ const ListNode* args_list,
+ Err* err) {
+ const std::vector<const ParseNode*>& args_vector = args_list->contents();
+ const IdentifierNode* identifier = NULL;
+ if (args_vector.size() != 1 ||
+ !(identifier = args_vector[0]->AsIdentifier())) {
+ *err = Err(function, "Bad argument to defined().",
+ "defined() takes one argument which should be an identifier.");
+ return Value();
+ }
+
+ if (scope->GetValue(identifier->value().value()))
+ return Value(function, true);
+ return Value(function, false);
+}
+
// import ----------------------------------------------------------------------
const char kImport[] = "import";
@@ -320,7 +378,7 @@ Value RunImport(Scope* scope,
!EnsureNotProcessingImport(function, scope, err))
return Value();
- const SourceDir input_dir = SourceDirForFunctionCall(function);
+ const SourceDir& input_dir = scope->GetSourceDir();
SourceFile import_file =
input_dir.ResolveRelativeFile(args[0].string_value());
scope->settings()->import_manager().DoImport(import_file, function,
@@ -384,28 +442,40 @@ Value RunPrint(Scope* scope,
// -----------------------------------------------------------------------------
FunctionInfo::FunctionInfo()
- : generic_block_runner(NULL),
+ : self_evaluating_args_runner(NULL),
+ generic_block_runner(NULL),
executed_block_runner(NULL),
no_block_runner(NULL),
help(NULL) {
}
+FunctionInfo::FunctionInfo(SelfEvaluatingArgsFunction seaf, const char* in_help)
+ : self_evaluating_args_runner(seaf),
+ generic_block_runner(NULL),
+ executed_block_runner(NULL),
+ no_block_runner(NULL),
+ help(in_help) {
+}
+
FunctionInfo::FunctionInfo(GenericBlockFunction gbf, const char* in_help)
- : generic_block_runner(gbf),
+ : self_evaluating_args_runner(NULL),
+ generic_block_runner(gbf),
executed_block_runner(NULL),
no_block_runner(NULL),
help(in_help) {
}
FunctionInfo::FunctionInfo(ExecutedBlockFunction ebf, const char* in_help)
- : generic_block_runner(NULL),
+ : self_evaluating_args_runner(NULL),
+ generic_block_runner(NULL),
executed_block_runner(ebf),
no_block_runner(NULL),
help(in_help) {
}
FunctionInfo::FunctionInfo(NoBlockFunction nbf, const char* in_help)
- : generic_block_runner(NULL),
+ : self_evaluating_args_runner(NULL),
+ generic_block_runner(NULL),
executed_block_runner(NULL),
no_block_runner(nbf),
help(in_help) {
@@ -429,6 +499,7 @@ struct FunctionInfoInitializer {
INSERT_FUNCTION(Copy)
INSERT_FUNCTION(Custom)
INSERT_FUNCTION(DeclareArgs)
+ INSERT_FUNCTION(Defined)
INSERT_FUNCTION(ExecScript)
INSERT_FUNCTION(Executable)
INSERT_FUNCTION(Group)
@@ -459,7 +530,7 @@ const FunctionInfoMap& GetFunctions() {
Value RunFunction(Scope* scope,
const FunctionCallNode* function,
- const std::vector<Value>& args,
+ const ListNode* args_list,
BlockNode* block,
Err* err) {
const Token& name = function->function();
@@ -471,20 +542,35 @@ Value RunFunction(Scope* scope,
// No build-in function matching this, check for a template.
const FunctionCallNode* rule =
scope->GetTemplate(function->function().value().as_string());
- if (rule)
- return RunTemplateInvocation(scope, function, args, block, rule, err);
+ if (rule) {
+ Value args = args_list->Execute(scope, err);
+ if (err->has_error())
+ return Value();
+ return RunTemplateInvocation(scope, function, args.list_value(), block,
+ rule, err);
+ }
*err = Err(name, "Unknown function.");
return Value();
}
+ if (found_function->second.self_evaluating_args_runner) {
+ return found_function->second.self_evaluating_args_runner(
+ scope, function, args_list, err);
+ }
+
+ // All other function types take a pre-executed set of args.
+ Value args = args_list->Execute(scope, err);
+ if (err->has_error())
+ return Value();
+
if (found_function->second.generic_block_runner) {
if (!block) {
FillNeedsBlockError(function, err);
return Value();
}
return found_function->second.generic_block_runner(
- scope, function, args, block, err);
+ scope, function, args.list_value(), block, err);
}
if (found_function->second.executed_block_runner) {
@@ -498,11 +584,12 @@ Value RunFunction(Scope* scope,
if (err->has_error())
return Value();
return found_function->second.executed_block_runner(
- function, args, &block_scope, err);
+ function, args.list_value(), &block_scope, err);
}
// Otherwise it's a no-block function.
- return found_function->second.no_block_runner(scope, function, args, err);
+ return found_function->second.no_block_runner(scope, function,
+ args.list_value(), err);
}
} // namespace functions
diff --git a/tools/gn/functions.h b/tools/gn/functions.h
index b55ff3a..351861b 100644
--- a/tools/gn/functions.h
+++ b/tools/gn/functions.h
@@ -18,7 +18,6 @@ class Label;
class ListNode;
class ParseNode;
class Scope;
-class SourceDir;
class Token;
class Value;
@@ -26,6 +25,14 @@ class Value;
namespace functions {
+// This type of function invocation has no block and evaluates its arguments
+// itself rather than taking a pre-executed list. This allows us to implement
+// certain built-in functions.
+typedef Value (*SelfEvaluatingArgsFunction)(Scope* scope,
+ const FunctionCallNode* function,
+ const ListNode* args_list,
+ Err* err);
+
// This type of function invocation takes a block node that it will execute.
typedef Value (*GenericBlockFunction)(Scope* scope,
const FunctionCallNode* function,
@@ -92,6 +99,13 @@ Value RunDeclareArgs(Scope* scope,
BlockNode* block,
Err* err);
+extern const char kDefined[];
+extern const char kDefined_Help[];
+Value RunDefined(Scope* scope,
+ const FunctionCallNode* function,
+ const ListNode* args_list,
+ Err* err);
+
extern const char kExecScript[];
extern const char kExecScript_Help[];
Value RunExecScript(Scope* scope,
@@ -234,10 +248,12 @@ Value RunWriteFile(Scope* scope,
// which indicates the type of function it is.
struct FunctionInfo {
FunctionInfo();
+ FunctionInfo(SelfEvaluatingArgsFunction seaf, const char* in_help);
FunctionInfo(GenericBlockFunction gbf, const char* in_help);
FunctionInfo(ExecutedBlockFunction ebf, const char* in_help);
FunctionInfo(NoBlockFunction nbf, const char* in_help);
+ SelfEvaluatingArgsFunction self_evaluating_args_runner;
GenericBlockFunction generic_block_runner;
ExecutedBlockFunction executed_block_runner;
NoBlockFunction no_block_runner;
@@ -253,7 +269,7 @@ const FunctionInfoMap& GetFunctions();
// Runs the given function.
Value RunFunction(Scope* scope,
const FunctionCallNode* function,
- const std::vector<Value>& args,
+ const ListNode* args_list,
BlockNode* block, // Optional.
Err* err);
@@ -300,10 +316,6 @@ bool EnsureSingleStringArg(const FunctionCallNode* function,
const std::vector<Value>& args,
Err* err);
-// Returns the source directory for the file comtaining the given function
-// invocation.
-const SourceDir& SourceDirForFunctionCall(const FunctionCallNode* function);
-
// Returns the name of the toolchain for the given scope.
const Label& ToolchainLabelForScope(const Scope* scope);
diff --git a/tools/gn/import_manager.cc b/tools/gn/import_manager.cc
index 774f866..e9e9425 100644
--- a/tools/gn/import_manager.cc
+++ b/tools/gn/import_manager.cc
@@ -24,6 +24,7 @@ Scope* UncachedImport(const Settings* settings,
CHECK(block);
scoped_ptr<Scope> scope(new Scope(settings->base_config()));
+ scope->set_source_dir(file.GetDir());
scope->SetProcessingImport();
block->ExecuteBlockInScope(scope.get(), err);
if (err->has_error())
diff --git a/tools/gn/ninja_script_target_writer.cc b/tools/gn/ninja_script_target_writer.cc
index 44e13c6..e259fff 100644
--- a/tools/gn/ninja_script_target_writer.cc
+++ b/tools/gn/ninja_script_target_writer.cc
@@ -28,12 +28,17 @@ void NinjaScriptTargetWriter::Run() {
if (script_cd_to_root.empty()) {
script_cd_to_root = ".";
} else {
- // Remove trailing slash
+ // Remove trailing slash.
DCHECK(script_cd_to_root[script_cd_to_root.size() - 1] == '/');
script_cd_to_root.resize(script_cd_to_root.size() - 1);
}
- std::string script_relative_to_cd =
- script_cd_to_root + target_->script_values().script().value();
+
+ // Compute the relative script file name. The script string should start with
+ // 2 slashes, and we trim 1.
+ DCHECK(target_->script_values().script().is_source_absolute());
+ std::string script_relative_to_cd = script_cd_to_root;
+ const std::string& script_string = target_->script_values().script().value();
+ script_relative_to_cd.append(&script_string[1], script_string.size() - 1);
std::string custom_rule_name = WriteRuleDefinition(script_relative_to_cd);
@@ -61,7 +66,7 @@ void NinjaScriptTargetWriter::Run() {
// Collects all output files for writing below.
std::vector<OutputFile> output_files;
- if (!has_sources()) {
+ if (has_sources()) {
// Write separate rules for each input source file.
WriteSourceRules(custom_rule_name, common_deps, script_cd,
script_cd_to_root, &output_files);
@@ -96,28 +101,48 @@ std::string NinjaScriptTargetWriter::WriteRuleDefinition(
// Use a unique name for the response file when there are multiple build
// steps so that they don't stomp on each other. When there are no sources,
// there will be only one invocation so we can use a simple name.
- std::string rspfile = custom_rule_name;
- if (has_sources())
- rspfile += ".$unique_name";
- rspfile += ".rsp";
-
- out_ << "rule " << custom_rule_name << std::endl;
- out_ << " command = $pythonpath gyp-win-tool action-wrapper $arch "
- << rspfile << " ";
- path_output_.WriteDir(out_, target_->label().dir(),
- PathOutput::DIR_NO_LAST_SLASH);
- out_ << std::endl;
- out_ << " description = CUSTOM " << target_label << std::endl;
- out_ << " restat = 1" << std::endl;
- out_ << " rspfile = " << rspfile << std::endl;
-
- // The build command goes in the rsp file.
- out_ << " rspfile_content = $pythonpath " << script_relative_to_cd;
- for (size_t i = 0; i < target_->script_values().args().size(); i++) {
- const std::string& arg = target_->script_values().args()[i];
- out_ << " ";
- WriteArg(arg);
+
+ if (settings_->IsWin()) {
+ // Send through gyp-win-tool and use a response file.
+ std::string rspfile = custom_rule_name;
+ if (has_sources())
+ rspfile += ".$unique_name";
+ rspfile += ".rsp";
+
+ out_ << "rule " << custom_rule_name << std::endl;
+ out_ << " command = $pythonpath gyp-win-tool action-wrapper $arch "
+ << rspfile << " ";
+ path_output_.WriteDir(out_, target_->label().dir(),
+ PathOutput::DIR_NO_LAST_SLASH);
+ out_ << std::endl;
+ out_ << " description = CUSTOM " << target_label << std::endl;
+ out_ << " restat = 1" << std::endl;
+ out_ << " rspfile = " << rspfile << std::endl;
+
+ // The build command goes in the rsp file.
+ out_ << " rspfile_content = $pythonpath " << script_relative_to_cd;
+ for (size_t i = 0; i < target_->script_values().args().size(); i++) {
+ const std::string& arg = target_->script_values().args()[i];
+ out_ << " ";
+ WriteArg(arg);
+ }
+ } else {
+ // Posix can execute Python directly.
+ out_ << "rule " << custom_rule_name << std::endl;
+ out_ << " command = cd ";
+ path_output_.WriteDir(out_, target_->label().dir(),
+ PathOutput::DIR_NO_LAST_SLASH);
+ out_ << "; $pythonpath " << script_relative_to_cd;
+ for (size_t i = 0; i < target_->script_values().args().size(); i++) {
+ const std::string& arg = target_->script_values().args()[i];
+ out_ << " ";
+ WriteArg(arg);
+ }
+ out_ << std::endl;
+ out_ << " description = CUSTOM " << target_label << std::endl;
+ out_ << " restat = 1" << std::endl;
}
+
out_ << std::endl;
return custom_rule_name;
}
diff --git a/tools/gn/parse_tree.cc b/tools/gn/parse_tree.cc
index 24c477d..4ac30a2 100644
--- a/tools/gn/parse_tree.cc
+++ b/tools/gn/parse_tree.cc
@@ -277,11 +277,7 @@ const FunctionCallNode* FunctionCallNode::AsFunctionCall() const {
}
Value FunctionCallNode::Execute(Scope* scope, Err* err) const {
- Value args = args_->Execute(scope, err);
- if (err->has_error())
- return Value();
- return functions::RunFunction(scope, this, args.list_value(), block_.get(),
- err);
+ return functions::RunFunction(scope, this, args_.get(), block_.get(), err);
}
LocationRange FunctionCallNode::GetRange() const {
diff --git a/tools/gn/parse_tree.h b/tools/gn/parse_tree.h
index 69f05e1..cc3550f 100644
--- a/tools/gn/parse_tree.h
+++ b/tools/gn/parse_tree.h
@@ -295,7 +295,7 @@ class ListNode : public ParseNode {
void append_item(scoped_ptr<ParseNode> s) {
contents_.push_back(s.release());
}
- const std::vector<ParseNode*>& contents() const { return contents_; }
+ const std::vector<const ParseNode*>& contents() const { return contents_; }
private:
// Tokens corresponding to the [ and ].
@@ -303,7 +303,7 @@ class ListNode : public ParseNode {
Token end_token_;
// Owning pointers, use unique_ptr when we can use C++11.
- std::vector<ParseNode*> contents_;
+ std::vector<const ParseNode*> contents_;
DISALLOW_COPY_AND_ASSIGN(ListNode);
};
diff --git a/tools/gn/scheduler.cc b/tools/gn/scheduler.cc
index 05dd76f..72c310b 100644
--- a/tools/gn/scheduler.cc
+++ b/tools/gn/scheduler.cc
@@ -5,13 +5,29 @@
#include "tools/gn/scheduler.h"
#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
#include "tools/gn/ninja_target_writer.h"
#include "tools/gn/standard_out.h"
Scheduler* g_scheduler = NULL;
+namespace {
+
+int GetThreadCount() {
+ std::string thread_count =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII("threads");
+
+ int result;
+ if (thread_count.empty() || !base::StringToInt(thread_count, &result))
+ return 32;
+ return result;
+}
+
+} // namespace
+
Scheduler::Scheduler()
- : pool_(new base::SequencedWorkerPool(32, "worker_")),
+ : pool_(new base::SequencedWorkerPool(GetThreadCount(), "worker_")),
input_file_manager_(new InputFileManager),
verbose_logging_(false),
work_count_(0),
diff --git a/tools/gn/scope.cc b/tools/gn/scope.cc
index df645b8..42277f7 100644
--- a/tools/gn/scope.cc
+++ b/tools/gn/scope.cc
@@ -339,6 +339,14 @@ bool Scope::IsProcessingImport() const {
return false;
}
+const SourceDir& Scope::GetSourceDir() const {
+ if (!source_dir_.is_null())
+ return source_dir_;
+ if (containing())
+ return containing()->GetSourceDir();
+ return source_dir_;
+}
+
void Scope::SetProperty(const void* key, void* value) {
if (!value) {
DCHECK(properties_.find(key) != properties_.end());
diff --git a/tools/gn/scope.h b/tools/gn/scope.h
index 3016729..0d1c156 100644
--- a/tools/gn/scope.h
+++ b/tools/gn/scope.h
@@ -13,6 +13,7 @@
#include "base/memory/scoped_ptr.h"
#include "tools/gn/err.h"
#include "tools/gn/pattern.h"
+#include "tools/gn/source_dir.h"
#include "tools/gn/value.h"
class FunctionCallNode;
@@ -188,6 +189,12 @@ class Scope {
void ClearProcessingImport();
bool IsProcessingImport() const;
+ // The source directory associated with this scope. This will check embedded
+ // scopes until it finds a nonempty source directory. This will default to
+ // an empty dir if no containing scope has a source dir set.
+ const SourceDir& GetSourceDir() const;
+ void set_source_dir(const SourceDir& d) { source_dir_ = d; }
+
// Properties are opaque pointers that code can use to set state on a Scope
// that it can retrieve later.
//
@@ -255,6 +262,8 @@ class Scope {
typedef std::set<ProgrammaticProvider*> ProviderSet;
ProviderSet programmatic_providers_;
+ SourceDir source_dir_;
+
DISALLOW_COPY_AND_ASSIGN(Scope);
};
diff --git a/tools/gn/scope_per_file_provider.cc b/tools/gn/scope_per_file_provider.cc
index bf6aa89..6e61dad 100644
--- a/tools/gn/scope_per_file_provider.cc
+++ b/tools/gn/scope_per_file_provider.cc
@@ -132,8 +132,11 @@ std::string ScopePerFileProvider::GetRootOutputDirWithNoLastSlash(
const Settings* settings) {
const std::string& output_dir =
settings->build_settings()->build_dir().value();
- CHECK(!output_dir.empty());
- return output_dir.substr(1, output_dir.size() - 1);
+
+ // Trim off a leading and trailing slash. So "//foo/bar/" -> /foo/bar".
+ DCHECK(output_dir.size() > 2 && output_dir[0] == '/' &&
+ output_dir[output_dir.size() - 1] == '/');
+ return output_dir.substr(1, output_dir.size() - 2);
}
// static
@@ -143,12 +146,16 @@ std::string ScopePerFileProvider::GetRootGenDirWithNoLastSlash(
}
std::string ScopePerFileProvider::GetFileDirWithNoLastSlash() const {
- std::string dir_value = source_file_.GetDir().value();
- return dir_value.substr(0, dir_value.size() - 1);
+ const std::string& dir_value = scope_->GetSourceDir().value();
+
+ // Trim off a leading and trailing slash. So "//foo/bar/" -> /foo/bar".
+ DCHECK(dir_value.size() > 2 && dir_value[0] == '/' &&
+ dir_value[dir_value.size() - 1] == '/');
+ return dir_value.substr(1, dir_value.size() - 2);
}
std::string ScopePerFileProvider::GetRelativeRootWithNoLastSlash() const {
- return InvertDirWithNoLastSlash(source_file_.GetDir());
+ return InvertDirWithNoLastSlash(scope_->GetSourceDir());
}
// static
diff --git a/tools/gn/script_target_generator.cc b/tools/gn/script_target_generator.cc
index 58243d5..8df05b6 100644
--- a/tools/gn/script_target_generator.cc
+++ b/tools/gn/script_target_generator.cc
@@ -45,7 +45,7 @@ void ScriptTargetGenerator::FillScript() {
return;
target_->script_values().set_script(
- input_directory_.ResolveRelativeFile(value->string_value()));
+ scope_->GetSourceDir().ResolveRelativeFile(value->string_value()));
}
void ScriptTargetGenerator::FillScriptArgs() {
@@ -66,7 +66,8 @@ void ScriptTargetGenerator::FillOutputs() {
return;
Target::FileList outputs;
- if (!ExtractListOfRelativeFiles(*value, input_directory_, &outputs, err_))
+ if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
+ scope_->GetSourceDir(), &outputs, err_))
return;
// Validate that outputs are in the output dir.
diff --git a/tools/gn/secondary/net/BUILD.gn b/tools/gn/secondary/net/BUILD.gn
index a65b580..cf70629 100644
--- a/tools/gn/secondary/net/BUILD.gn
+++ b/tools/gn/secondary/net/BUILD.gn
@@ -2,11 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-#import("//tools/grit/grit_rule.gni")
+import("//tools/grit/grit_rule.gni")
component("net") {
deps = [
- #":net_resources",
+ ":net_resources",
"//base",
"//base:base_i18n",
"//base/third_party/dynamic_annotations",
@@ -20,38 +20,6 @@ component("net") {
}
-#template("grit") {
-# resource_ids = "$relative_source_root_dir/tools/gritsettings/resource_ids"
-# output_dir = "$relative_target_gen_dir/grit"
-# grit_info_script = "//tools/grit/grit_info.py"
-#
-# grit_inputs = exec_script(grit_info_script,
-# [ "--inputs", source, "-f", resource_ids], "list lines")
-# grit_outputs = exec_script(grit_info_script,
-# [ "--outputs", "\"$output_dir\"", source, "-f", resource_ids ],
-# "list lines")
-#
-# custom(target_name + "_grit") {
-# script = "grit.py"
-# #inputs = grit_inputs
-# outputs = grit_outputs
-#
-# # TODO(brettw) grit_defines.
-# args = [
-# "-i", source, "build",
-# "-f", resource_ids,
-# "-o", relative_target_gen_dir,
-# ]
-# }
-#
-# # This is the thing that people actually link with, it must be named the
-# # same as the argument the template was invoked with.
-# static_library(target_name) {
-# sources = grit_outputs
-# deps = [ ":${target_name}_grit" ]
-# }
-#}
-#
-#grit("net_resources") {
-# source = "base/net_resources.grd"
-#}
+grit("net_resources") {
+ source = "base/net_resources.grd"
+}
diff --git a/tools/gn/secondary/tools/grit/grit_rule.gni b/tools/gn/secondary/tools/grit/grit_rule.gni
index aca9f2f..7b3ba48 100644
--- a/tools/gn/secondary/tools/grit/grit_rule.gni
+++ b/tools/gn/secondary/tools/grit/grit_rule.gni
@@ -3,19 +3,28 @@
# found in the LICENSE file.
template("grit") {
+ assert(defined(source),
+ "\"source\" must be defined for the grit template $target_name")
+ assert(!defined(sources) && !defined(outputs),
+ "Neither \"sources\" nor \"outputs\" can be defined for the grit " +
+ "template $target_name")
+
resource_ids = "$relative_source_root_dir/tools/gritsettings/resource_ids"
- output_dir = "$relative_target_gen_dir/grit"
- grit_info_script = "grit_info.py"
+ output_dir = "$relative_target_gen_dir"
+
+ # Note that this needs to be source-absolute since the current directory will
+ # be that of the file invoking the template, not this file.
+ grit_info_script = "$relative_source_root_dir/tools/grit/grit_info.py"
grit_inputs = exec_script(grit_info_script,
[ "--inputs", source, "-f", resource_ids], "list lines")
grit_outputs = exec_script(grit_info_script,
- [ "--outputs", "\"$output_dir\"", source, "-f", resource_ids ],
+ [ "--outputs", "$output_dir", source, "-f", resource_ids ],
"list lines")
custom(target_name + "_grit") {
- script = "grit.py"
- inputs = grit_inputs
+ script = "$relative_source_root_dir/tools/grit/grit.py"
+ data = grit_inputs # TODO(brettw) this should be inputs or something
outputs = grit_outputs
# TODO(brettw) grit_defines.
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc
index 919d90d..8fba875 100644
--- a/tools/gn/setup.cc
+++ b/tools/gn/setup.cc
@@ -202,7 +202,7 @@ bool Setup::FillSourceDir(const CommandLine& cmdline) {
if (scheduler_.verbose_logging())
scheduler_.Log("Using source root", FilePathToUTF8(root_path));
- build_settings_.set_root_path(root_path);
+ build_settings_.SetRootPath(root_path);
return true;
}
diff --git a/tools/gn/source_dir.cc b/tools/gn/source_dir.cc
index 5739b52..7cdd693 100644
--- a/tools/gn/source_dir.cc
+++ b/tools/gn/source_dir.cc
@@ -31,7 +31,9 @@ SourceDir::SourceDir(const base::StringPiece& p)
SourceDir::~SourceDir() {
}
-SourceFile SourceDir::ResolveRelativeFile(const base::StringPiece& p) const {
+SourceFile SourceDir::ResolveRelativeFile(
+ const base::StringPiece& p,
+ const base::StringPiece& source_root) const {
SourceFile ret;
// It's an error to resolve an empty string or one that is a directory
@@ -39,9 +41,16 @@ SourceFile SourceDir::ResolveRelativeFile(const base::StringPiece& p) const {
// to return a file.
if (p.empty() || (p.size() > 0 && p[p.size() - 1] == '/'))
return SourceFile();
- if (p[0] == '/') {
- // Absolute path.
+ if (p.size() >= 2 && p[0] == '/' && p[1] == '/') {
+ // Source-relative.
ret.value_.assign(p.data(), p.size());
+ NormalizePath(&ret.value_);
+ return ret;
+ } else if (IsPathAbsolute(p)) {
+ if (source_root.empty() ||
+ !MakeAbsolutePathRelativeIfPossible(source_root, p, &ret.value_))
+ ret.value_.assign(p.data(), p.size());
+ NormalizePath(&ret.value_);
return ret;
}
@@ -53,13 +62,27 @@ SourceFile SourceDir::ResolveRelativeFile(const base::StringPiece& p) const {
return ret;
}
-SourceDir SourceDir::ResolveRelativeDir(const base::StringPiece& p) const {
+SourceDir SourceDir::ResolveRelativeDir(
+ const base::StringPiece& p,
+ const base::StringPiece& source_root) const {
SourceDir ret;
if (p.empty())
return ret;
- if (p[0] == '/') {
- // Absolute path.
+ if (p.size() >= 2 && p[0] == '/' && p[1] == '/') {
+ // Source-relative.
+ ret.value_.assign(p.data(), p.size());
+ if (!EndsWithSlash(ret.value_))
+ ret.value_.push_back('/');
+ NormalizePath(&ret.value_);
+ return ret;
+ } else if (IsPathAbsolute(p)) {
+ if (source_root.empty() ||
+ !MakeAbsolutePathRelativeIfPossible(source_root, p, &ret.value_))
+ ret.value_.assign(p.data(), p.size());
+ NormalizePath(&ret.value_);
+ if (!EndsWithSlash(ret.value_))
+ ret.value_.push_back('/');
return SourceDir(p);
}
diff --git a/tools/gn/source_dir.h b/tools/gn/source_dir.h
index 3b6caee..4aa344a 100644
--- a/tools/gn/source_dir.h
+++ b/tools/gn/source_dir.h
@@ -31,8 +31,16 @@ class SourceDir {
// an empty SourceDir/File on error. Empty input is always an error (it's
// possible we should say ResolveRelativeDir vs. an empty string should be
// the source dir, but we require "." instead).
- SourceFile ResolveRelativeFile(const base::StringPiece& p) const;
- SourceDir ResolveRelativeDir(const base::StringPiece& p) const;
+ //
+ // If source_root is supplied, these functions will additionally handle the
+ // case where the input is a system-absolute but still inside the source
+ // tree. This is the case for some external tools.
+ SourceFile ResolveRelativeFile(
+ const base::StringPiece& p,
+ const base::StringPiece& source_root = base::StringPiece()) const;
+ SourceDir ResolveRelativeDir(
+ const base::StringPiece& p,
+ const base::StringPiece& source_root = base::StringPiece()) const;
// Resolves this source file relative to some given source root. Returns
// an empty file path on error.
diff --git a/tools/gn/target.cc b/tools/gn/target.cc
index a59ca6a..0d7a492 100644
--- a/tools/gn/target.cc
+++ b/tools/gn/target.cc
@@ -70,6 +70,28 @@ Target::Target(const Settings* settings, const Label& label)
Target::~Target() {
}
+// static
+const char* Target::GetStringForOutputType(OutputType type) {
+ switch (type) {
+ case UNKNOWN:
+ return "Unknown";
+ case GROUP:
+ return "Group";
+ case EXECUTABLE:
+ return "Executable";
+ case SHARED_LIBRARY:
+ return "Shared library";
+ case STATIC_LIBRARY:
+ return "Static library";
+ case COPY_FILES:
+ return "Copy";
+ case CUSTOM:
+ return "Custom";
+ default:
+ return "";
+ }
+}
+
Target* Target::AsTarget() {
return this;
}
diff --git a/tools/gn/target.h b/tools/gn/target.h
index 99edb11..2e55805 100644
--- a/tools/gn/target.h
+++ b/tools/gn/target.h
@@ -40,6 +40,9 @@ class Target : public Item {
Target(const Settings* settings, const Label& label);
virtual ~Target();
+ // Returns a string naming the output type.
+ static const char* GetStringForOutputType(OutputType type);
+
// Item overrides.
virtual Target* AsTarget() OVERRIDE;
virtual const Target* AsTarget() const OVERRIDE;
diff --git a/tools/gn/target_generator.cc b/tools/gn/target_generator.cc
index 50d9580..5421d93 100644
--- a/tools/gn/target_generator.cc
+++ b/tools/gn/target_generator.cc
@@ -29,8 +29,7 @@ TargetGenerator::TargetGenerator(Target* target,
: target_(target),
scope_(scope),
function_token_(function_token),
- err_(err),
- input_directory_(function_token.location().file()->dir()) {
+ err_(err) {
}
TargetGenerator::~TargetGenerator() {
@@ -70,8 +69,7 @@ void TargetGenerator::GenerateTarget(Scope* scope,
// The location of the target is the directory name with no slash at the end.
// FIXME(brettw) validate name.
const Label& toolchain_label = ToolchainLabelForScope(scope);
- Label label(function_token.location().file()->dir(),
- args[0].string_value(),
+ Label label(scope->GetSourceDir(), args[0].string_value(),
toolchain_label.dir(), toolchain_label.name());
if (g_scheduler->verbose_logging())
@@ -121,8 +119,8 @@ void TargetGenerator::FillSources() {
return;
Target::FileList dest_sources;
- if (!ExtractListOfRelativeFiles(*value, input_directory_, &dest_sources,
- err_))
+ if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
+ scope_->GetSourceDir(), &dest_sources, err_))
return;
target_->swap_in_sources(&dest_sources);
}
@@ -146,8 +144,8 @@ void TargetGenerator::FillData() {
return;
Target::FileList dest_data;
- if (!ExtractListOfRelativeFiles(*value, input_directory_, &dest_data,
- err_))
+ if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
+ scope_->GetSourceDir(), &dest_data, err_))
return;
target_->swap_in_data(&dest_data);
}
@@ -180,7 +178,7 @@ void TargetGenerator::FillGenericConfigs(
return;
std::vector<Label> labels;
- if (!ExtractListOfLabels(*value, input_directory_,
+ if (!ExtractListOfLabels(*value, scope_->GetSourceDir(),
ToolchainLabelForScope(scope_), &labels, err_))
return;
@@ -205,7 +203,7 @@ void TargetGenerator::FillGenericDeps(
return;
std::vector<Label> labels;
- if (!ExtractListOfLabels(*value, input_directory_,
+ if (!ExtractListOfLabels(*value, scope_->GetSourceDir(),
ToolchainLabelForScope(scope_), &labels, err_))
return;
@@ -228,7 +226,7 @@ void TargetGenerator::FillForwardDependentConfigs() {
return;
std::vector<Label> labels;
- if (!ExtractListOfLabels(*value, input_directory_,
+ if (!ExtractListOfLabels(*value, scope_->GetSourceDir(),
ToolchainLabelForScope(scope_), &labels, err_))
return;
diff --git a/tools/gn/target_generator.h b/tools/gn/target_generator.h
index cd65c61..2b16ee0 100644
--- a/tools/gn/target_generator.h
+++ b/tools/gn/target_generator.h
@@ -60,10 +60,6 @@ class TargetGenerator {
const Token& function_token_;
Err* err_;
- // Sources are relative to this. This comes from the input file which doesn't
- // get freed so we don't acautlly have to make a copy.
- const SourceDir& input_directory_;
-
private:
void FillDependentConfigs(); // Includes all types of dependent configs.
void FillData();
diff --git a/tools/gn/toolchain_manager.cc b/tools/gn/toolchain_manager.cc
index c28e543..3e84530 100644
--- a/tools/gn/toolchain_manager.cc
+++ b/tools/gn/toolchain_manager.cc
@@ -483,6 +483,7 @@ void ToolchainManager::BackgroundLoadBuildConfig(Info* info,
// Nobody should be accessing settings at this point other than us since we
// haven't marked it loaded, so we can do it outside the lock.
Scope* base_config = info->settings.base_config();
+ base_config->set_source_dir(SourceDir("//"));
info->settings.build_settings()->build_args().SetupRootScope(base_config,
info->settings.toolchain()->args());
@@ -537,6 +538,7 @@ void ToolchainManager::BackgroundInvoke(const Info* info,
Scope our_scope(info->settings.base_config());
ScopePerFileProvider per_file_provider(&our_scope, file_name);
+ our_scope.set_source_dir(file_name.GetDir());
Err err;
root->Execute(&our_scope, &err);
diff --git a/tools/gn/value_extractors.cc b/tools/gn/value_extractors.cc
index 56a2be2..c2ca285 100644
--- a/tools/gn/value_extractors.cc
+++ b/tools/gn/value_extractors.cc
@@ -4,6 +4,7 @@
#include "tools/gn/value_extractors.h"
+#include "tools/gn/build_settings.h"
#include "tools/gn/err.h"
#include "tools/gn/label.h"
#include "tools/gn/source_dir.h"
@@ -14,12 +15,16 @@ namespace {
// This extractor rejects files with system-absolute file paths. If we need
// that in the future, we'll have to add some flag to control this.
struct RelativeFileConverter {
- RelativeFileConverter(const SourceDir& current_dir_in)
- : current_dir(current_dir_in) {}
+ RelativeFileConverter(const BuildSettings* build_settings_in,
+ const SourceDir& current_dir_in)
+ : build_settings(build_settings_in),
+ current_dir(current_dir_in) {
+ }
bool operator()(const Value& v, SourceFile* out, Err* err) const {
if (!v.VerifyTypeIs(Value::STRING, err))
return false;
- *out = current_dir.ResolveRelativeFile(v.string_value());
+ *out = current_dir.ResolveRelativeFile(v.string_value(),
+ build_settings->root_path_utf8());
if (out->is_system_absolute()) {
*err = Err(v, "System-absolute file path.",
"You can't list a system-absolute file path here. Please include "
@@ -29,18 +34,24 @@ struct RelativeFileConverter {
}
return true;
}
+ const BuildSettings* build_settings;
const SourceDir& current_dir;
};
struct RelativeDirConverter {
- RelativeDirConverter(const SourceDir& current_dir_in)
- : current_dir(current_dir_in) {}
+ RelativeDirConverter(const BuildSettings* build_settings_in,
+ const SourceDir& current_dir_in)
+ : build_settings(build_settings_in),
+ current_dir(current_dir_in) {
+ }
bool operator()(const Value& v, SourceDir* out, Err* err) const {
if (!v.VerifyTypeIs(Value::STRING, err))
return false;
- *out = current_dir.ResolveRelativeDir(v.string_value());
+ *out = current_dir.ResolveRelativeDir(v.string_value(),
+ build_settings->root_path_utf8());
return true;
}
+ const BuildSettings* build_settings;
const SourceDir& current_dir;
};
@@ -76,20 +87,22 @@ bool ExtractListOfStringValues(const Value& value,
return true;
}
-bool ExtractListOfRelativeFiles(const Value& value,
+bool ExtractListOfRelativeFiles(const BuildSettings* build_settings,
+ const Value& value,
const SourceDir& current_dir,
std::vector<SourceFile>* files,
Err* err) {
return ListValueExtractor(value, files, err,
- RelativeFileConverter(current_dir));
+ RelativeFileConverter(build_settings, current_dir));
}
-bool ExtractListOfRelativeDirs(const Value& value,
+bool ExtractListOfRelativeDirs(const BuildSettings* build_settings,
+ const Value& value,
const SourceDir& current_dir,
std::vector<SourceDir>* dest,
Err* err) {
return ListValueExtractor(value, dest, err,
- RelativeDirConverter(current_dir));
+ RelativeDirConverter(build_settings, current_dir));
}
bool ExtractListOfLabels(const Value& value,
diff --git a/tools/gn/value_extractors.h b/tools/gn/value_extractors.h
index 556f44f..12fff00 100644
--- a/tools/gn/value_extractors.h
+++ b/tools/gn/value_extractors.h
@@ -10,6 +10,7 @@
#include "tools/gn/value.h"
+class BuildSettings;
class Err;
class Label;
class SourceDir;
@@ -37,13 +38,15 @@ bool ExtractListOfStringValues(const Value& value,
Err* err);
// Looks for a list of source files relative to a given current dir.
-bool ExtractListOfRelativeFiles(const Value& value,
+bool ExtractListOfRelativeFiles(const BuildSettings* build_settings,
+ const Value& value,
const SourceDir& current_dir,
std::vector<SourceFile>* files,
Err* err);
// Looks for a list of source directories relative to a given current dir.
-bool ExtractListOfRelativeDirs(const Value& value,
+bool ExtractListOfRelativeDirs(const BuildSettings* build_settings,
+ const Value& value,
const SourceDir& current_dir,
std::vector<SourceDir>* dest,
Err* err);