diff options
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); |