summaryrefslogtreecommitdiffstats
path: root/tools/gn/file_template.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gn/file_template.cc')
-rw-r--r--tools/gn/file_template.cc189
1 files changed, 127 insertions, 62 deletions
diff --git a/tools/gn/file_template.cc b/tools/gn/file_template.cc
index b00eb39..2809920 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
}
}