// Copyright (c) 2013 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 "base/stl_util.h" #include "tools/gn/functions.h" #include "tools/gn/parse_tree.h" #include "tools/gn/scope.h" #include "tools/gn/settings.h" #include "tools/gn/substitution_list.h" #include "tools/gn/substitution_writer.h" #include "tools/gn/target.h" #include "tools/gn/value_extractors.h" namespace functions { const char kProcessFileTemplate[] = "process_file_template"; const char kProcessFileTemplate_HelpShort[] = "process_file_template: Do template expansion over a list of files."; const char kProcessFileTemplate_Help[] = R"(process_file_template: Do template expansion over a list of files. process_file_template(source_list, template) process_file_template applies a template list to a source file list, returning the result of applying each template to each source. This is typically used for computing output file names from input files. In most cases, get_target_outputs() will give the same result with shorter, more maintainable code. This function should only be used when that function can't be used (like there's no target or the target is defined in another build file). Arguments The source_list is a list of file names. The template can be a string or a list. If it is a list, multiple output strings are generated for each input. The template should contain source expansions to which each name in the source list is applied. See "gn help source_expansion". Example sources = [ "foo.idl", "bar.idl", ] myoutputs = process_file_template( sources, [ "$target_gen_dir/{{source_name_part}}.cc", "$target_gen_dir/{{source_name_part}}.h" ]) The result in this case will be: [ "//out/Debug/foo.cc" "//out/Debug/foo.h" "//out/Debug/bar.cc" "//out/Debug/bar.h" ] )"; Value RunProcessFileTemplate(Scope* scope, const FunctionCallNode* function, const std::vector& args, Err* err) { if (args.size() != 2) { *err = Err(function->function(), "Expected two arguments"); return Value(); } // Source list. Target::FileList input_files; if (!ExtractListOfRelativeFiles(scope->settings()->build_settings(), args[0], scope->GetSourceDir(), &input_files, err)) return Value(); std::vector result_files; SubstitutionList subst; // Template. const Value& template_arg = args[1]; if (template_arg.type() == Value::STRING) { // Convert the string to a SubstitutionList with one pattern in it to // simplify the code below. std::vector list; list.push_back(template_arg.string_value()); if (!subst.Parse(list, template_arg.origin(), err)) return Value(); } else if (template_arg.type() == Value::LIST) { if (!subst.Parse(template_arg, err)) return Value(); } else { *err = Err(template_arg, "Not a string or a list."); return Value(); } auto& types = subst.required_types(); if (base::ContainsValue(types, SUBSTITUTION_SOURCE_TARGET_RELATIVE)) { *err = Err(template_arg, "Not a valid substitution type for the function."); return Value(); } SubstitutionWriter::ApplyListToSourcesAsString( nullptr, scope->settings(), subst, input_files, &result_files); // Convert the list of strings to the return Value. Value ret(function, Value::LIST); ret.list_value().reserve(result_files.size()); for (const auto& file : result_files) ret.list_value().push_back(Value(function, file)); return ret; } } // namespace functions