Index: tools/gn/function_get_target_outputs.cc |
diff --git a/tools/gn/function_get_target_outputs.cc b/tools/gn/function_get_target_outputs.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..370fee9cb2275518bce4a0617341024e2db1dc2a |
--- /dev/null |
+++ b/tools/gn/function_get_target_outputs.cc |
@@ -0,0 +1,181 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "tools/gn/build_settings.h" |
+#include "tools/gn/file_template.h" |
+#include "tools/gn/functions.h" |
+#include "tools/gn/ninja_helper.h" |
+#include "tools/gn/parse_tree.h" |
+#include "tools/gn/settings.h" |
+#include "tools/gn/target.h" |
+#include "tools/gn/value.h" |
+ |
+namespace functions { |
+ |
+namespace { |
+ |
+void GetOutputsForTarget(const BuildSettings* build_settings, |
+ const Target* target, |
+ std::vector<std::string>* ret) { |
+ switch (target->output_type()) { |
+ case Target::ACTION: |
+ case Target::COPY_FILES: { |
+ // Actions and copy targets: return the outputs specified. |
+ const std::vector<SourceFile>& outs = target->action_values().outputs(); |
+ ret->reserve(outs.size()); |
+ for (size_t i = 0; i < outs.size(); i++) |
+ ret->push_back(outs[i].value()); |
+ break; |
+ } |
+ |
+ case Target::ACTION_FOREACH: { |
+ // Action_foreach: return the result of the template in the outputs. |
+ FileTemplate file_template(target->action_values().outputs()); |
+ const std::vector<SourceFile>& sources = target->sources(); |
+ for (size_t i = 0; i < sources.size(); i++) |
+ file_template.ApplyString(sources[i].value(), ret); |
+ break; |
+ } |
+ |
+ case Target::EXECUTABLE: |
+ case Target::SHARED_LIBRARY: |
+ case Target::STATIC_LIBRARY: |
+ // Return the resulting binary file. Currently, fall through to the |
+ // Ninja helper below which will compute the main output name. |
+ // |
+ // TODO(brettw) some targets have secondary files which should go into |
+ // the list after the main (like shared libraries on Windows have an |
+ // import library). |
+ case Target::GROUP: |
+ case Target::SOURCE_SET: { |
+ // These return the stamp file, which is computed by the NinjaHelper. |
+ NinjaHelper helper(build_settings); |
+ OutputFile output_file = helper.GetTargetOutputFile(target); |
+ |
+ // The output file is relative to the build dir. |
+ std::string absolute_output_file = build_settings->build_dir().value(); |
+ absolute_output_file.append(output_file.value()); |
+ |
+ ret->push_back(absolute_output_file); |
+ break; |
+ } |
+ |
+ default: |
+ NOTREACHED(); |
+ } |
+} |
+ |
+} // namespace |
+ |
+const char kGetTargetOutputs[] = "get_target_outputs"; |
+const char kGetTargetOutputs_HelpShort[] = |
+ "get_target_outputs: [file list] Get the list of outputs from a target."; |
+const char kGetTargetOutputs_Help[] = |
+ "get_target_outputs: [file list] Get the list of outputs from a target.\n" |
+ "\n" |
+ " get_target_outputs(target_label)\n" |
+ "\n" |
+ " Returns a list of output files for the named target. The named target\n" |
+ " must have been previously defined in the current file before this\n" |
+ " function is called (it can't reference targets in other files because\n" |
+ " there isn't a defined execution order, and it obviously can't\n" |
+ " reference targets that are defined after the function call).\n" |
+ "\n" |
+ "Return value\n" |
+ "\n" |
+ " The names in the resulting list will be absolute file paths (normally\n" |
+ " like \"//out/Debug/bar.exe\", depending on the build directory).\n" |
+ "\n" |
+ " action targets: this will just return the files specified in the\n" |
+ " \"outputs\" variable of the target.\n" |
+ "\n" |
+ " action_foreach targets: this will return the result of applying\n" |
+ " the output template to the sources (see \"gn help source_expansion\").\n" |
+ " This will be the same result (though with guaranteed absolute file\n" |
+ " paths), as process_file_template will return for those inputs\n" |
+ " (see \"gn help process_file_template\").\n" |
+ "\n" |
+ " binary targets (executables, libraries): this will return a list\n" |
+ " of the resulting binary file(s). The \"main output\" (the actual\n" |
+ " binary or library) will always be the 0th element in the result.\n" |
+ " Depending on the platform and output type, there may be other output\n" |
+ " files as well (like import libraries) which will follow.\n" |
+ "\n" |
+ " source sets and groups: this will return a list containing the path of\n" |
+ " the \"stamp\" file that Ninja will produce once all outputs are\n" |
+ " generated. This probably isn't very useful.\n" |
+ "\n" |
+ "Example\n" |
+ "\n" |
+ " # Say this action generates a bunch of C source files.\n" |
+ " action_foreach(\"my_action\") {\n" |
+ " sources = [ ... ]\n" |
+ " outputs = [ ... ]\n" |
+ " }\n" |
+ "\n" |
+ " # Compile the resulting source files into a source set.\n" |
+ " source_set(\"my_lib\") {\n" |
+ " sources = get_target_outputs(\":my_action\")\n" |
+ " }\n"; |
+ |
+Value RunGetTargetOutputs(Scope* scope, |
+ const FunctionCallNode* function, |
+ const std::vector<Value>& args, |
+ Err* err) { |
+ if (args.size() != 1) { |
+ *err = Err(function, "Expected one argument."); |
+ return Value(); |
+ } |
+ |
+ // Resolve the requested label. |
+ Label label = Label::Resolve(scope->GetSourceDir(), |
+ ToolchainLabelForScope(scope), args[0], err); |
+ if (label.is_null()) |
+ return Value(); |
+ |
+ // Find the referenced target. The targets previously encountered in this |
+ // scope will have been stashed in the item collector (they'll be dispatched |
+ // when this file is done running) so we can look through them. |
+ const Target* target = NULL; |
+ Scope::ItemVector* collector = scope->GetItemCollector(); |
+ if (!collector) { |
+ *err = Err(function, "No targets defined in this context."); |
+ return Value(); |
+ } |
+ for (size_t i = 0; i < collector->size(); i++) { |
+ const Item* item = (*collector)[i]->get(); |
+ if (item->label() != label) |
+ continue; |
+ |
+ const Target* as_target = item->AsTarget(); |
+ if (!as_target) { |
+ *err = Err(function, "Label does not refer to a target.", |
+ label.GetUserVisibleName(false) + |
+ "\nrefers to a " + item->GetItemTypeName()); |
+ return Value(); |
+ } |
+ target = as_target; |
+ break; |
+ } |
+ |
+ if (!target) { |
+ *err = Err(function, "Target not found in this context.", |
+ label.GetUserVisibleName(false) + |
+ "\nwas not found. get_target_outputs() can only be used for targets\n" |
+ "previously defined in the current file."); |
+ return Value(); |
+ } |
+ |
+ std::vector<std::string> files; |
+ GetOutputsForTarget(scope->settings()->build_settings(), target, &files); |
+ |
+ Value ret(function, Value::LIST); |
+ ret.list_value().reserve(files.size()); |
+ for (size_t i = 0; i < files.size(); i++) |
+ ret.list_value().push_back(Value(function, files[i])); |
+ |
+ return ret; |
+} |
+ |
+} // namespace functions |