| Index: tools/gn/function_toolchain.cc
|
| diff --git a/tools/gn/function_toolchain.cc b/tools/gn/function_toolchain.cc
|
| index 210cc2c84b45c092f1c57732d9df70d6b2b66689..3501ec128a064a7ed86e822970e4a4a5af859cac 100644
|
| --- a/tools/gn/function_toolchain.cc
|
| +++ b/tools/gn/function_toolchain.cc
|
| @@ -47,7 +47,7 @@ bool ReadBool(Scope* scope,
|
| bool ReadString(Scope* scope,
|
| const char* var,
|
| Tool* tool,
|
| - void (Tool::*set)(const std::string&),
|
| + void (Tool::*set)(std::string),
|
| Err* err) {
|
| const Value* v = scope->GetValue(var, true);
|
| if (!v)
|
| @@ -64,9 +64,8 @@ bool ReadString(Scope* scope,
|
| bool ReadLabel(Scope* scope,
|
| const char* var,
|
| Tool* tool,
|
| - const ParseNode* origin,
|
| const Label& current_toolchain,
|
| - void (Tool::*set)(const LabelPtrPair<Pool>&),
|
| + void (Tool::*set)(LabelPtrPair<Pool>),
|
| Err* err) {
|
| const Value* v = scope->GetValue(var, true);
|
| if (!v)
|
| @@ -78,9 +77,9 @@ bool ReadLabel(Scope* scope,
|
| return false;
|
|
|
| LabelPtrPair<Pool> pair(label);
|
| - pair.origin = origin;
|
| + pair.origin = tool->defined_from();
|
|
|
| - (tool->*set)(pair);
|
| + (tool->*set)(std::move(pair));
|
| return true;
|
| }
|
|
|
| @@ -105,7 +104,7 @@ bool ReadPattern(Scope* scope,
|
| const char* name,
|
| bool (*validate)(SubstitutionType),
|
| Tool* tool,
|
| - void (Tool::*set)(const SubstitutionPattern&),
|
| + void (Tool::*set)(SubstitutionPattern),
|
| Err* err) {
|
| const Value* value = scope->GetValue(name, true);
|
| if (!value)
|
| @@ -119,7 +118,31 @@ bool ReadPattern(Scope* scope,
|
| if (!ValidateSubstitutionList(pattern.required_types(), validate, value, err))
|
| return false;
|
|
|
| - (tool->*set)(pattern);
|
| + (tool->*set)(std::move(pattern));
|
| + return true;
|
| +}
|
| +
|
| +bool ReadPatternList(Scope* scope,
|
| + const char* name,
|
| + bool (*validate)(SubstitutionType),
|
| + Tool* tool,
|
| + void (Tool::*set)(SubstitutionList),
|
| + Err* err) {
|
| + const Value* value = scope->GetValue(name, true);
|
| + if (!value)
|
| + return true; // Not present is fine.
|
| + if (!value->VerifyTypeIs(Value::LIST, err))
|
| + return false;
|
| +
|
| + SubstitutionList list;
|
| + if (!list.Parse(*value, err))
|
| + return false;
|
| +
|
| + // Validate the right kinds of patterns are used.
|
| + if (!ValidateSubstitutionList(list.required_types(), validate, value, err))
|
| + return false;
|
| +
|
| + (tool->*set)(std::move(list));
|
| return true;
|
| }
|
|
|
| @@ -182,35 +205,6 @@ bool ReadDepsFormat(Scope* scope, Tool* tool, Err* err) {
|
| return true;
|
| }
|
|
|
| -bool ReadOutputs(Scope* scope,
|
| - const FunctionCallNode* tool_function,
|
| - bool (*validate)(SubstitutionType),
|
| - Tool* tool,
|
| - Err* err) {
|
| - const Value* value = scope->GetValue("outputs", true);
|
| - if (!value) {
|
| - *err = Err(tool_function, "\"outputs\" must be specified for this tool.");
|
| - return false;
|
| - }
|
| -
|
| - SubstitutionList list;
|
| - if (!list.Parse(*value, err))
|
| - return false;
|
| -
|
| - // Validate the right kinds of patterns are used.
|
| - if (!ValidateSubstitutionList(list.required_types(), validate, value, err))
|
| - return false;
|
| -
|
| - // There should always be at least one output.
|
| - if (list.list().empty()) {
|
| - *err = Err(*value, "Outputs list is empty.", "I need some outputs.");
|
| - return false;
|
| - }
|
| -
|
| - tool->set_outputs(list);
|
| - return true;
|
| -}
|
| -
|
| bool IsCompilerTool(Toolchain::ToolType type) {
|
| return type == Toolchain::TYPE_CC ||
|
| type == Toolchain::TYPE_CXX ||
|
| @@ -238,6 +232,68 @@ bool IsPatternInOutputList(const SubstitutionList& output_list,
|
| return false;
|
| }
|
|
|
| +
|
| +bool ValidateOutputs(const Tool* tool, Err* err) {
|
| + if (tool->outputs().list().empty()) {
|
| + *err = Err(tool->defined_from(),
|
| + "\"outputs\" must be specified for this tool.");
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +// Validates either link_output or depend_output. To generalize to either, pass
|
| +// the associated pattern, and the variable name that should appear in error
|
| +// messages.
|
| +bool ValidateLinkAndDependOutput(const Tool* tool,
|
| + Toolchain::ToolType tool_type,
|
| + const SubstitutionPattern& pattern,
|
| + const char* variable_name,
|
| + Err* err) {
|
| + if (pattern.empty())
|
| + return true; // Empty is always OK.
|
| +
|
| + // It should only be specified for certain tool types.
|
| + if (tool_type != Toolchain::TYPE_SOLINK &&
|
| + tool_type != Toolchain::TYPE_SOLINK_MODULE) {
|
| + *err = Err(tool->defined_from(),
|
| + "This tool specifies a " + std::string(variable_name) + ".",
|
| + "This is only valid for solink and solink_module tools.");
|
| + return false;
|
| + }
|
| +
|
| + if (!IsPatternInOutputList(tool->outputs(), pattern)) {
|
| + *err = Err(tool->defined_from(), "This tool's link_output is bad.",
|
| + "It must match one of the outputs.");
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool ValidateRuntimeOutputs(const Tool* tool,
|
| + Toolchain::ToolType tool_type,
|
| + Err* err) {
|
| + if (tool->runtime_outputs().list().empty())
|
| + return true; // Empty is always OK.
|
| +
|
| + if (!IsLinkerTool(tool_type)) {
|
| + *err = Err(tool->defined_from(), "This tool specifies runtime_outputs.",
|
| + "This is only valid for linker tools (alink doesn't count).");
|
| + return false;
|
| + }
|
| +
|
| + for (const SubstitutionPattern& pattern : tool->runtime_outputs().list()) {
|
| + if (!IsPatternInOutputList(tool->outputs(), pattern)) {
|
| + *err = Err(tool->defined_from(), "This tool's runtime_outputs is bad.",
|
| + "It must be a subset of the outputs. The bad one is:\n " +
|
| + pattern.AsString());
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| } // namespace
|
|
|
| // toolchain -------------------------------------------------------------------
|
| @@ -527,9 +583,7 @@ const char kTool_Help[] =
|
| "\n"
|
| " If you specify more than one output for shared library links,\n"
|
| " you should consider setting link_output, depend_output, and\n"
|
| - " runtime_link_output. Otherwise, the first entry in the\n"
|
| - " outputs list should always be the main output which will be\n"
|
| - " linked to.\n"
|
| + " runtime_outputs.\n"
|
| "\n"
|
| " Example for a compiler tool that produces .obj files:\n"
|
| " outputs = [\n"
|
| @@ -555,16 +609,14 @@ const char kTool_Help[] =
|
| "\n"
|
| " link_output [string with substitutions]\n"
|
| " depend_output [string with substitutions]\n"
|
| - " runtime_link_output [string with substitutions]\n"
|
| " Valid for: \"solink\" only (optional)\n"
|
| "\n"
|
| - " These three files specify which of the outputs from the solink\n"
|
| + " These two files specify which of the outputs from the solink\n"
|
| " tool should be used for linking and dependency tracking. These\n"
|
| " should match entries in the \"outputs\". If unspecified, the\n"
|
| " first item in the \"outputs\" array will be used for all. See\n"
|
| " \"Separate linking and dependencies for shared libraries\"\n"
|
| - " below for more. If link_output is set but runtime_link_output\n"
|
| - " is not set, runtime_link_output defaults to link_output.\n"
|
| + " below for more.\n"
|
| "\n"
|
| " On Windows, where the tools produce a .dll shared library and\n"
|
| " a .lib import library, you will want the first two to be the\n"
|
| @@ -642,6 +694,14 @@ const char kTool_Help[] =
|
| " rspfile_content = \"{{inputs}} {{solibs}} {{libs}}\"\n"
|
| " }\n"
|
| "\n"
|
| + " runtime_outputs [string list with substitutions]\n"
|
| + " Valid for: linker tools\n"
|
| + "\n"
|
| + " If specified, this list is the subset of the outputs that should\n"
|
| + " be added to runtime deps (see \"gn help runtime_deps\"). By\n"
|
| + " default (if runtime_outputs is empty or unspecified), it will be\n"
|
| + " the link_output.\n"
|
| + "\n"
|
| "Expansions for tool variables\n"
|
| "\n"
|
| " All paths are relative to the root build directory, which is the\n"
|
| @@ -915,6 +975,7 @@ Value RunTool(Scope* scope,
|
| }
|
|
|
| std::unique_ptr<Tool> tool(new Tool);
|
| + tool->set_defined_from(function);
|
|
|
| if (!ReadPattern(&block_scope, "command", subst_validator, tool.get(),
|
| &Tool::set_command, err) ||
|
| @@ -932,8 +993,8 @@ Value RunTool(Scope* scope,
|
| &Tool::set_link_output, err) ||
|
| !ReadPattern(&block_scope, "depend_output", subst_validator, tool.get(),
|
| &Tool::set_depend_output, err) ||
|
| - !ReadPattern(&block_scope, "runtime_link_output", subst_validator,
|
| - tool.get(), &Tool::set_runtime_link_output, err) ||
|
| + !ReadPatternList(&block_scope, "runtime_outputs", subst_validator,
|
| + tool.get(), &Tool::set_runtime_outputs, err) ||
|
| !ReadString(&block_scope, "output_prefix", tool.get(),
|
| &Tool::set_output_prefix, err) ||
|
| !ReadPattern(&block_scope, "default_output_dir", subst_validator,
|
| @@ -944,7 +1005,7 @@ Value RunTool(Scope* scope,
|
| &Tool::set_rspfile, err) ||
|
| !ReadPattern(&block_scope, "rspfile_content", subst_validator, tool.get(),
|
| &Tool::set_rspfile_content, err) ||
|
| - !ReadLabel(&block_scope, "pool", tool.get(), function, toolchain->label(),
|
| + !ReadLabel(&block_scope, "pool", tool.get(), toolchain->label(),
|
| &Tool::set_pool, err)) {
|
| return Value();
|
| }
|
| @@ -955,59 +1016,27 @@ Value RunTool(Scope* scope,
|
| tool_type != Toolchain::TYPE_COMPILE_XCASSETS) {
|
| // All tools should have outputs, except the copy, stamp, copy_bundle_data
|
| // and compile_xcassets tools that generate their outputs internally.
|
| - if (!ReadOutputs(&block_scope, function, subst_output_validator,
|
| - tool.get(), err))
|
| + if (!ReadPatternList(&block_scope, "outputs", subst_output_validator,
|
| + tool.get(), &Tool::set_outputs, err) ||
|
| + !ValidateOutputs(tool.get(), err))
|
| return Value();
|
| }
|
| + if (!ValidateRuntimeOutputs(tool.get(), tool_type, err))
|
| + return Value();
|
|
|
| - // Validate that the link_output, depend_output, and runtime_link_output
|
| - // refer to items in the outputs and aren't defined for irrelevant tool
|
| - // types.
|
| - if (!tool->link_output().empty()) {
|
| - if (tool_type != Toolchain::TYPE_SOLINK &&
|
| - tool_type != Toolchain::TYPE_SOLINK_MODULE) {
|
| - *err = Err(function, "This tool specifies a link_output.",
|
| - "This is only valid for solink and solink_module tools.");
|
| - return Value();
|
| - }
|
| - if (!IsPatternInOutputList(tool->outputs(), tool->link_output())) {
|
| - *err = Err(function, "This tool's link_output is bad.",
|
| - "It must match one of the outputs.");
|
| - return Value();
|
| - }
|
| - }
|
| - if (!tool->depend_output().empty()) {
|
| - if (tool_type != Toolchain::TYPE_SOLINK &&
|
| - tool_type != Toolchain::TYPE_SOLINK_MODULE) {
|
| - *err = Err(function, "This tool specifies a depend_output.",
|
| - "This is only valid for solink and solink_module tools.");
|
| - return Value();
|
| - }
|
| - if (!IsPatternInOutputList(tool->outputs(), tool->depend_output())) {
|
| - *err = Err(function, "This tool's depend_output is bad.",
|
| - "It must match one of the outputs.");
|
| - return Value();
|
| - }
|
| - }
|
| + // Validate link_output and depend_output.
|
| + if (!ValidateLinkAndDependOutput(tool.get(), tool_type, tool->link_output(),
|
| + "link_output", err))
|
| + return Value();
|
| + if (!ValidateLinkAndDependOutput(tool.get(), tool_type, tool->depend_output(),
|
| + "depend_output", err))
|
| + return Value();
|
| if ((!tool->link_output().empty() && tool->depend_output().empty()) ||
|
| (tool->link_output().empty() && !tool->depend_output().empty())) {
|
| *err = Err(function, "Both link_output and depend_output should either "
|
| "be specified or they should both be empty.");
|
| return Value();
|
| }
|
| - if (!tool->runtime_link_output().empty()) {
|
| - if (tool_type != Toolchain::TYPE_SOLINK &&
|
| - tool_type != Toolchain::TYPE_SOLINK_MODULE) {
|
| - *err = Err(function, "This tool specifies a runtime_link_output.",
|
| - "This is only valid for solink and solink_module tools.");
|
| - return Value();
|
| - }
|
| - if (!IsPatternInOutputList(tool->outputs(), tool->runtime_link_output())) {
|
| - *err = Err(function, "This tool's runtime_link_output is bad.",
|
| - "It must match one of the outputs.");
|
| - return Value();
|
| - }
|
| - }
|
|
|
| // Make sure there weren't any vars set in this tool that were unused.
|
| if (!block_scope.CheckForUnusedVars(err))
|
|
|