| Index: tools/gn/file_template.cc
|
| diff --git a/tools/gn/file_template.cc b/tools/gn/file_template.cc
|
| index b00eb391738b1fff05d0141e58623e4a676dabbf..2809920ea2be8076ac38a9b1d0c3b932f52a3986 100644
|
| --- a/tools/gn/file_template.cc
|
| +++ b/tools/gn/file_template.cc
|
| @@ -15,6 +15,10 @@
|
| const char FileTemplate::kSource[] = "{{source}}";
|
| const char FileTemplate::kSourceNamePart[] = "{{source_name_part}}";
|
| const char FileTemplate::kSourceFilePart[] = "{{source_file_part}}";
|
| +const char FileTemplate::kSourceDir[] = "{{source_dir}}";
|
| +const char FileTemplate::kRootRelDir[] = "{{source_root_relative_dir}}";
|
| +const char FileTemplate::kSourceGenDir[] = "{{source_gen_dir}}";
|
| +const char FileTemplate::kSourceOutDir[] = "{{source_out_dir}}";
|
|
|
| const char kSourceExpansion_Help[] =
|
| "How Source Expansion Works\n"
|
| @@ -44,17 +48,47 @@ const char kSourceExpansion_Help[] =
|
| " directory (which is the current directory when running compilers\n"
|
| " and scripts). This will generally be used for specifying inputs\n"
|
| " to a script in the \"args\" variable.\n"
|
| + " \"//foo/bar/baz.txt\" => \"../../foo/bar/baz.txt\"\n"
|
| "\n"
|
| " {{source_file_part}}\n"
|
| - " The file part of the source including the extension. For the\n"
|
| - " source \"foo/bar.txt\" the source file part will be \"bar.txt\".\n"
|
| + " The file part of the source including the extension.\n"
|
| + " \"//foo/bar/baz.txt\" => \"baz.txt\"\n"
|
| "\n"
|
| " {{source_name_part}}\n"
|
| " The filename part of the source file with no directory or\n"
|
| " extension. This will generally be used for specifying a\n"
|
| " transformation from a soruce file to a destination file with the\n"
|
| - " same name but different extension. For the source \"foo/bar.txt\"\n"
|
| - " the source name part will be \"bar\".\n"
|
| + " same name but different extension.\n"
|
| + " \"//foo/bar/baz.txt\" => \"baz\"\n"
|
| + "\n"
|
| + " {{source_dir}}\n"
|
| + " The directory containing the source file, relative to the build\n"
|
| + " directory, with no trailing slash.\n"
|
| + " \"//foo/bar/baz.txt\" => \"../../foo/bar\"\n"
|
| + "\n"
|
| + " {{source_root_relative_dir}}\n"
|
| + " The path to the source file's directory relative to the source\n"
|
| + " root, with no leading \"//\" or trailing slashes. If the path is\n"
|
| + " system-absolute, (beginning in a single slash) this will just\n"
|
| + " return the path with no trailing slash.\n"
|
| + " \"//foo/bar/baz.txt\" => \"foo/bar\"\n"
|
| + "\n"
|
| + " {{source_gen_dir}}\n"
|
| + " The generated file directory corresponding to the source file's\n"
|
| + " path, relative to the build directory. This will be different than\n"
|
| + " the target's generated file directory if the source file is in a\n"
|
| + " different directory than the build.gn file. If the input path is\n"
|
| + " system absolute, this will return the root generated file\n"
|
| + " directory."
|
| + " \"//foo/bar/baz.txt\" => \"gen/foo/bar\"\n"
|
| + "\n"
|
| + " {{source_out_dir}}\n"
|
| + " The object file directory corresponding to the source file's\n"
|
| + " path, relative to the build directory. this us be different than\n"
|
| + " the target's out directory if the source file is in a different\n"
|
| + " directory than the build.gn file. if the input path is system\n"
|
| + " absolute, this will return the root generated file directory.\n"
|
| + " \"//foo/bar/baz.txt\" => \"obj/foo/bar\"\n"
|
| "\n"
|
| "Examples\n"
|
| "\n"
|
| @@ -78,21 +112,26 @@ const char kSourceExpansion_Help[] =
|
| " //out/Debug/obj/mydirectory/input2.h\n"
|
| " //out/Debug/obj/mydirectory/input2.cc\n";
|
|
|
| -FileTemplate::FileTemplate(const Value& t, Err* err)
|
| - : has_substitutions_(false) {
|
| +FileTemplate::FileTemplate(const Settings* settings, const Value& t, Err* err)
|
| + : settings_(settings),
|
| + has_substitutions_(false) {
|
| std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false);
|
| ParseInput(t, err);
|
| }
|
|
|
| -FileTemplate::FileTemplate(const std::vector<std::string>& t)
|
| - : has_substitutions_(false) {
|
| +FileTemplate::FileTemplate(const Settings* settings,
|
| + const std::vector<std::string>& t)
|
| + : settings_(settings),
|
| + has_substitutions_(false) {
|
| std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false);
|
| for (size_t i = 0; i < t.size(); i++)
|
| ParseOneTemplateString(t[i]);
|
| }
|
|
|
| -FileTemplate::FileTemplate(const std::vector<SourceFile>& t)
|
| - : has_substitutions_(false) {
|
| +FileTemplate::FileTemplate(const Settings* settings,
|
| + const std::vector<SourceFile>& t)
|
| + : settings_(settings),
|
| + has_substitutions_(false) {
|
| std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false);
|
| for (size_t i = 0; i < t.size(); i++)
|
| ParseOneTemplateString(t[i].value());
|
| @@ -107,7 +146,7 @@ FileTemplate FileTemplate::GetForTargetOutputs(const Target* target) {
|
| std::vector<std::string> output_template_args;
|
| for (size_t i = 0; i < outputs.size(); i++)
|
| output_template_args.push_back(outputs[i].value());
|
| - return FileTemplate(output_template_args);
|
| + return FileTemplate(target->settings(), output_template_args);
|
| }
|
|
|
| bool FileTemplate::IsTypeUsed(Subrange::Type type) const {
|
| @@ -115,37 +154,16 @@ bool FileTemplate::IsTypeUsed(Subrange::Type type) const {
|
| return types_required_[type];
|
| }
|
|
|
| -void FileTemplate::Apply(const Value& sources,
|
| - const ParseNode* origin,
|
| - std::vector<Value>* dest,
|
| - Err* err) const {
|
| - if (!sources.VerifyTypeIs(Value::LIST, err))
|
| - return;
|
| - dest->reserve(sources.list_value().size() * templates_.container().size());
|
| -
|
| - // Temporary holding place, allocate outside to re-use- buffer.
|
| - std::vector<std::string> string_output;
|
| -
|
| - const std::vector<Value>& sources_list = sources.list_value();
|
| - for (size_t i = 0; i < sources_list.size(); i++) {
|
| - string_output.clear();
|
| - if (!sources_list[i].VerifyTypeIs(Value::STRING, err))
|
| - return;
|
| -
|
| - ApplyString(sources_list[i].string_value(), &string_output);
|
| - for (size_t out_i = 0; out_i < string_output.size(); out_i++)
|
| - dest->push_back(Value(origin, string_output[out_i]));
|
| - }
|
| -}
|
| -
|
| -void FileTemplate::ApplyString(const std::string& str,
|
| - std::vector<std::string>* output) const {
|
| +void FileTemplate::Apply(const SourceFile& source,
|
| + std::vector<std::string>* output) const {
|
| // Compute all substitutions needed so we can just do substitutions below.
|
| // We skip the LITERAL one since that varies each time.
|
| std::string subst[Subrange::NUM_TYPES];
|
| for (int i = 1; i < Subrange::NUM_TYPES; i++) {
|
| - if (types_required_[i])
|
| - subst[i] = GetSubstitution(str, static_cast<Subrange::Type>(i));
|
| + if (types_required_[i]) {
|
| + subst[i] =
|
| + GetSubstitution(settings_, source, static_cast<Subrange::Type>(i));
|
| + }
|
| }
|
|
|
| size_t first_output_index = output->size();
|
| @@ -209,13 +227,15 @@ void FileTemplate::WriteWithNinjaExpansions(std::ostream& out) const {
|
|
|
| void FileTemplate::WriteNinjaVariablesForSubstitution(
|
| std::ostream& out,
|
| - const std::string& source,
|
| + const Settings* settings,
|
| + const SourceFile& source,
|
| const EscapeOptions& escape_options) const {
|
| for (int i = 1; i < Subrange::NUM_TYPES; i++) {
|
| if (types_required_[i]) {
|
| Subrange::Type type = static_cast<Subrange::Type>(i);
|
| out << " " << GetNinjaVariableNameForType(type) << " = ";
|
| - EscapeStringToStream(out, GetSubstitution(source, type), escape_options);
|
| + EscapeStringToStream(out, GetSubstitution(settings, source, type),
|
| + escape_options);
|
| out << std::endl;
|
| }
|
| }
|
| @@ -230,6 +250,15 @@ const char* FileTemplate::GetNinjaVariableNameForType(Subrange::Type type) {
|
| return "source_name_part";
|
| case Subrange::FILE_PART:
|
| return "source_file_part";
|
| + case Subrange::SOURCE_DIR:
|
| + return "source_dir";
|
| + case Subrange::ROOT_RELATIVE_DIR:
|
| + return "source_root_rel_dir";
|
| + case Subrange::SOURCE_GEN_DIR:
|
| + return "source_gen_dir";
|
| + case Subrange::SOURCE_OUT_DIR:
|
| + return "source_out_dir";
|
| +
|
| default:
|
| NOTREACHED();
|
| }
|
| @@ -237,15 +266,47 @@ const char* FileTemplate::GetNinjaVariableNameForType(Subrange::Type type) {
|
| }
|
|
|
| // static
|
| -std::string FileTemplate::GetSubstitution(const std::string& source,
|
| +std::string FileTemplate::GetSubstitution(const Settings* settings,
|
| + const SourceFile& source,
|
| Subrange::Type type) {
|
| switch (type) {
|
| case Subrange::SOURCE:
|
| - return source;
|
| + if (source.is_system_absolute())
|
| + return source.value();
|
| + return RebaseSourceAbsolutePath(source.value(),
|
| + settings->build_settings()->build_dir());
|
| +
|
| case Subrange::NAME_PART:
|
| - return FindFilenameNoExtension(&source).as_string();
|
| + return FindFilenameNoExtension(&source.value()).as_string();
|
| +
|
| case Subrange::FILE_PART:
|
| - return FindFilename(&source).as_string();
|
| + return source.GetName();
|
| +
|
| + case Subrange::SOURCE_DIR:
|
| + if (source.is_system_absolute())
|
| + return DirectoryWithNoLastSlash(source.GetDir());
|
| + return RebaseSourceAbsolutePath(
|
| + DirectoryWithNoLastSlash(source.GetDir()),
|
| + settings->build_settings()->build_dir());
|
| +
|
| + case Subrange::ROOT_RELATIVE_DIR:
|
| + if (source.is_system_absolute())
|
| + return DirectoryWithNoLastSlash(source.GetDir());
|
| + return RebaseSourceAbsolutePath(
|
| + DirectoryWithNoLastSlash(source.GetDir()), SourceDir("//"));
|
| +
|
| + case Subrange::SOURCE_GEN_DIR:
|
| + return RebaseSourceAbsolutePath(
|
| + DirectoryWithNoLastSlash(
|
| + GetGenDirForSourceDir(settings, source.GetDir())),
|
| + settings->build_settings()->build_dir());
|
| +
|
| + case Subrange::SOURCE_OUT_DIR:
|
| + return RebaseSourceAbsolutePath(
|
| + DirectoryWithNoLastSlash(
|
| + GetOutputDirForSourceDir(settings, source.GetDir())),
|
| + settings->build_settings()->build_dir());
|
| +
|
| default:
|
| NOTREACHED();
|
| }
|
| @@ -288,30 +349,34 @@ void FileTemplate::ParseOneTemplateString(const std::string& str) {
|
| Subrange(Subrange::LITERAL, str.substr(cur, next - cur)));
|
| }
|
|
|
| + // Given the name of the string constant and enum for a template parameter,
|
| + // checks for it and stores it. Writing this as a function requires passing
|
| + // the entire state of this function as arguments, so this actually ends
|
| + // up being more clear.
|
| + #define IF_MATCH_THEN_STORE(const_name, enum_name) \
|
| + if (str.compare(next, arraysize(const_name) - 1, const_name) == 0) { \
|
| + t.container().push_back(Subrange(Subrange::enum_name)); \
|
| + types_required_[Subrange::enum_name] = true; \
|
| + has_substitutions_ = true; \
|
| + cur = next + arraysize(const_name) - 1; \
|
| + }
|
| +
|
| // Decode the template param.
|
| - if (str.compare(next, arraysize(kSource) - 1, kSource) == 0) {
|
| - t.container().push_back(Subrange(Subrange::SOURCE));
|
| - types_required_[Subrange::SOURCE] = true;
|
| - has_substitutions_ = true;
|
| - cur = next + arraysize(kSource) - 1;
|
| - } else if (str.compare(next, arraysize(kSourceNamePart) - 1,
|
| - kSourceNamePart) == 0) {
|
| - t.container().push_back(Subrange(Subrange::NAME_PART));
|
| - types_required_[Subrange::NAME_PART] = true;
|
| - has_substitutions_ = true;
|
| - cur = next + arraysize(kSourceNamePart) - 1;
|
| - } else if (str.compare(next, arraysize(kSourceFilePart) - 1,
|
| - kSourceFilePart) == 0) {
|
| - t.container().push_back(Subrange(Subrange::FILE_PART));
|
| - types_required_[Subrange::FILE_PART] = true;
|
| - has_substitutions_ = true;
|
| - cur = next + arraysize(kSourceFilePart) - 1;
|
| - } else {
|
| + IF_MATCH_THEN_STORE(kSource, SOURCE)
|
| + else IF_MATCH_THEN_STORE(kSourceNamePart, NAME_PART)
|
| + else IF_MATCH_THEN_STORE(kSourceFilePart, FILE_PART)
|
| + else IF_MATCH_THEN_STORE(kSourceDir, SOURCE_DIR)
|
| + else IF_MATCH_THEN_STORE(kRootRelDir, ROOT_RELATIVE_DIR)
|
| + else IF_MATCH_THEN_STORE(kSourceGenDir, SOURCE_GEN_DIR)
|
| + else IF_MATCH_THEN_STORE(kSourceOutDir, SOURCE_OUT_DIR)
|
| + else {
|
| // If it's not a match, treat it like a one-char literal (this will be
|
| // rare, so it's not worth the bother to add to the previous literal) so
|
| // we can keep going.
|
| t.container().push_back(Subrange(Subrange::LITERAL, "{"));
|
| cur = next + 1;
|
| }
|
| +
|
| + #undef IF_MATCH_THEN_STORE
|
| }
|
| }
|
|
|