1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "tools/gn/build_settings.h" 6 #include "tools/gn/file_template.h" 7 #include "tools/gn/functions.h" 8 #include "tools/gn/ninja_helper.h" 9 #include "tools/gn/parse_tree.h" 10 #include "tools/gn/settings.h" 11 #include "tools/gn/target.h" 12 #include "tools/gn/value.h" 13 14 namespace functions { 15 16 namespace { 17 18 void GetOutputsForTarget(const Settings* settings, 19 const Target* target, 20 std::vector<std::string>* ret) { 21 switch (target->output_type()) { 22 case Target::ACTION: 23 case Target::COPY_FILES: { 24 // Actions and copy targets: return the outputs specified. 25 const std::vector<SourceFile>& outs = target->action_values().outputs(); 26 ret->reserve(outs.size()); 27 for (size_t i = 0; i < outs.size(); i++) 28 ret->push_back(outs[i].value()); 29 break; 30 } 31 32 case Target::ACTION_FOREACH: { 33 // Action_foreach: return the result of the template in the outputs. 34 FileTemplate file_template(settings, target->action_values().outputs()); 35 const std::vector<SourceFile>& sources = target->sources(); 36 for (size_t i = 0; i < sources.size(); i++) 37 file_template.Apply(sources[i], ret); 38 break; 39 } 40 41 case Target::EXECUTABLE: 42 case Target::SHARED_LIBRARY: 43 case Target::STATIC_LIBRARY: 44 // Return the resulting binary file. Currently, fall through to the 45 // Ninja helper below which will compute the main output name. 46 // 47 // TODO(brettw) some targets have secondary files which should go into 48 // the list after the main (like shared libraries on Windows have an 49 // import library). 50 case Target::GROUP: 51 case Target::SOURCE_SET: { 52 // These return the stamp file, which is computed by the NinjaHelper. 53 NinjaHelper helper(settings->build_settings()); 54 OutputFile output_file = helper.GetTargetOutputFile(target); 55 56 // The output file is relative to the build dir. 57 std::string absolute_output_file = 58 settings->build_settings()->build_dir().value(); 59 absolute_output_file.append(output_file.value()); 60 61 ret->push_back(absolute_output_file); 62 break; 63 } 64 65 default: 66 NOTREACHED(); 67 } 68 } 69 70 } // namespace 71 72 const char kGetTargetOutputs[] = "get_target_outputs"; 73 const char kGetTargetOutputs_HelpShort[] = 74 "get_target_outputs: [file list] Get the list of outputs from a target."; 75 const char kGetTargetOutputs_Help[] = 76 "get_target_outputs: [file list] Get the list of outputs from a target.\n" 77 "\n" 78 " get_target_outputs(target_label)\n" 79 "\n" 80 " Returns a list of output files for the named target. The named target\n" 81 " must have been previously defined in the current file before this\n" 82 " function is called (it can't reference targets in other files because\n" 83 " there isn't a defined execution order, and it obviously can't\n" 84 " reference targets that are defined after the function call).\n" 85 "\n" 86 "Return value\n" 87 "\n" 88 " The names in the resulting list will be absolute file paths (normally\n" 89 " like \"//out/Debug/bar.exe\", depending on the build directory).\n" 90 "\n" 91 " action targets: this will just return the files specified in the\n" 92 " \"outputs\" variable of the target.\n" 93 "\n" 94 " action_foreach targets: this will return the result of applying\n" 95 " the output template to the sources (see \"gn help source_expansion\").\n" 96 " This will be the same result (though with guaranteed absolute file\n" 97 " paths), as process_file_template will return for those inputs\n" 98 " (see \"gn help process_file_template\").\n" 99 "\n" 100 " binary targets (executables, libraries): this will return a list\n" 101 " of the resulting binary file(s). The \"main output\" (the actual\n" 102 " binary or library) will always be the 0th element in the result.\n" 103 " Depending on the platform and output type, there may be other output\n" 104 " files as well (like import libraries) which will follow.\n" 105 "\n" 106 " source sets and groups: this will return a list containing the path of\n" 107 " the \"stamp\" file that Ninja will produce once all outputs are\n" 108 " generated. This probably isn't very useful.\n" 109 "\n" 110 "Example\n" 111 "\n" 112 " # Say this action generates a bunch of C source files.\n" 113 " action_foreach(\"my_action\") {\n" 114 " sources = [ ... ]\n" 115 " outputs = [ ... ]\n" 116 " }\n" 117 "\n" 118 " # Compile the resulting source files into a source set.\n" 119 " source_set(\"my_lib\") {\n" 120 " sources = get_target_outputs(\":my_action\")\n" 121 " }\n"; 122 123 Value RunGetTargetOutputs(Scope* scope, 124 const FunctionCallNode* function, 125 const std::vector<Value>& args, 126 Err* err) { 127 if (args.size() != 1) { 128 *err = Err(function, "Expected one argument."); 129 return Value(); 130 } 131 132 // Resolve the requested label. 133 Label label = Label::Resolve(scope->GetSourceDir(), 134 ToolchainLabelForScope(scope), args[0], err); 135 if (label.is_null()) 136 return Value(); 137 138 // Find the referenced target. The targets previously encountered in this 139 // scope will have been stashed in the item collector (they'll be dispatched 140 // when this file is done running) so we can look through them. 141 const Target* target = NULL; 142 Scope::ItemVector* collector = scope->GetItemCollector(); 143 if (!collector) { 144 *err = Err(function, "No targets defined in this context."); 145 return Value(); 146 } 147 for (size_t i = 0; i < collector->size(); i++) { 148 const Item* item = (*collector)[i]->get(); 149 if (item->label() != label) 150 continue; 151 152 const Target* as_target = item->AsTarget(); 153 if (!as_target) { 154 *err = Err(function, "Label does not refer to a target.", 155 label.GetUserVisibleName(false) + 156 "\nrefers to a " + item->GetItemTypeName()); 157 return Value(); 158 } 159 target = as_target; 160 break; 161 } 162 163 if (!target) { 164 *err = Err(function, "Target not found in this context.", 165 label.GetUserVisibleName(false) + 166 "\nwas not found. get_target_outputs() can only be used for targets\n" 167 "previously defined in the current file."); 168 return Value(); 169 } 170 171 std::vector<std::string> files; 172 GetOutputsForTarget(scope->settings(), target, &files); 173 174 Value ret(function, Value::LIST); 175 ret.list_value().reserve(files.size()); 176 for (size_t i = 0; i < files.size(); i++) 177 ret.list_value().push_back(Value(function, files[i])); 178 179 return ret; 180 } 181 182 } // namespace functions 183