diff options
Diffstat (limited to 'tools/gn')
-rw-r--r-- | tools/gn/command_desc.cc | 2 | ||||
-rw-r--r-- | tools/gn/file_template.cc | 189 | ||||
-rw-r--r-- | tools/gn/file_template.h | 54 | ||||
-rw-r--r-- | tools/gn/file_template_unittest.cc | 79 | ||||
-rw-r--r-- | tools/gn/filesystem_utils.cc | 21 | ||||
-rw-r--r-- | tools/gn/function_get_path_info.cc | 48 | ||||
-rw-r--r-- | tools/gn/function_get_path_info_unittest.cc | 22 | ||||
-rw-r--r-- | tools/gn/function_get_target_outputs.cc | 13 | ||||
-rw-r--r-- | tools/gn/function_process_file_template.cc | 22 | ||||
-rw-r--r-- | tools/gn/ninja_action_target_writer.cc | 14 | ||||
-rw-r--r-- | tools/gn/ninja_action_target_writer_unittest.cc | 2 | ||||
-rw-r--r-- | tools/gn/ninja_copy_target_writer.cc | 2 | ||||
-rw-r--r-- | tools/gn/ninja_target_writer.cc | 2 |
13 files changed, 333 insertions, 137 deletions
diff --git a/tools/gn/command_desc.cc b/tools/gn/command_desc.cc index d178233..4491920 100644 --- a/tools/gn/command_desc.cc +++ b/tools/gn/command_desc.cc @@ -276,7 +276,7 @@ void PrintOutputs(const Target* target, bool display_header) { std::vector<std::string> output_strings; FileTemplate file_template = FileTemplate::GetForTargetOutputs(target); for (size_t i = 0; i < target->sources().size(); i++) - file_template.ApplyString(target->sources()[i].value(), &output_strings); + file_template.Apply(target->sources()[i], &output_strings); std::sort(output_strings.begin(), output_strings.end()); for (size_t i = 0; i < output_strings.size(); i++) { 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 } } diff --git a/tools/gn/file_template.h b/tools/gn/file_template.h index 30b40da..b04a6c7 100644 --- a/tools/gn/file_template.h +++ b/tools/gn/file_template.h @@ -14,6 +14,7 @@ struct EscapeOptions; class ParseNode; +class Settings; class SourceFile; class Target; @@ -30,20 +31,17 @@ extern const char kSourceExpansion_Help[]; class FileTemplate { public: struct Subrange { + // See the help in the .cc file for what these mean. enum Type { LITERAL = 0, - // {{source}} -> expands to be the source file name relative to the build - // root dir. - SOURCE, - - // {{source_name_part}} -> file name without extension or directory. - // Maps "foo/bar.txt" to "bar". - NAME_PART, - - // {{source_file_part}} -> file name including extension but no directory. - // Maps "foo/bar.txt" to "bar.txt". - FILE_PART, + SOURCE, // {{source}} + NAME_PART, // {{source_name_part}} + FILE_PART, // {{source_file_part}} + SOURCE_DIR, // {{source_dir}} + ROOT_RELATIVE_DIR, // {{root_relative_dir}} + SOURCE_GEN_DIR, // {{source_gen_dir}} + SOURCE_OUT_DIR, // {{source_out_dir}} NUM_TYPES // Must be last }; @@ -60,9 +58,9 @@ class FileTemplate { // Constructs a template from the given value. On error, the err will be // set. In this case you should not use this object. - FileTemplate(const Value& t, Err* err); - FileTemplate(const std::vector<std::string>& t); - FileTemplate(const std::vector<SourceFile>& t); + FileTemplate(const Settings* settings, const Value& t, Err* err); + FileTemplate(const Settings* settings, const std::vector<std::string>& t); + FileTemplate(const Settings* settings, const std::vector<SourceFile>& t); ~FileTemplate(); @@ -76,18 +74,10 @@ class FileTemplate { // Returns true if there are any substitutions. bool has_substitutions() const { return has_substitutions_; } - // Applies this template to the given list of sources, appending all - // results to the given dest list. The sources must be a list for the - // one that takes a value as an input, otherwise the given error will be set. - void Apply(const Value& sources, - const ParseNode* origin, - std::vector<Value>* dest, - Err* err) const; - - // Low-level version of Apply that handles one source file. The results - // will be *appended* to the output. - void ApplyString(const std::string& input, - std::vector<std::string>* output) const; + // Applies the template to one source file. The results will be *appended* to + // the output. + void Apply(const SourceFile& source, + std::vector<std::string>* output) const; // Writes a string representing the template with Ninja variables for the // substitutions, and the literals escaped for Ninja consumption. @@ -115,7 +105,8 @@ class FileTemplate { // (see GetWithNinjaExpansions). void WriteNinjaVariablesForSubstitution( std::ostream& out, - const std::string& source, + const Settings* settings, + const SourceFile& source, const EscapeOptions& escape_options) const; // Returns the Ninja variable name used by the above Ninja functions to @@ -124,13 +115,18 @@ class FileTemplate { // Extracts the given type of substitution from the given source. The source // should be the file name relative to the output directory. - static std::string GetSubstitution(const std::string& source, + static std::string GetSubstitution(const Settings* settings, + const SourceFile& source, Subrange::Type type); // Known template types, these include the "{{ }}" static const char kSource[]; static const char kSourceNamePart[]; static const char kSourceFilePart[]; + static const char kSourceDir[]; + static const char kRootRelDir[]; + static const char kSourceGenDir[]; + static const char kSourceOutDir[]; private: typedef base::StackVector<Subrange, 8> Template; @@ -141,6 +137,8 @@ class FileTemplate { // Parses a template string and adds it to the templates_ list. void ParseOneTemplateString(const std::string& str); + const Settings* settings_; + TemplateVector templates_; // The corresponding value is set to true if the given subrange type is diff --git a/tools/gn/file_template_unittest.cc b/tools/gn/file_template_unittest.cc index 8e3bf40..d10791e 100644 --- a/tools/gn/file_template_unittest.cc +++ b/tools/gn/file_template_unittest.cc @@ -7,58 +7,62 @@ #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/escape.h" #include "tools/gn/file_template.h" +#include "tools/gn/test_with_scope.h" TEST(FileTemplate, Static) { + TestWithScope setup; + std::vector<std::string> templates; templates.push_back("something_static"); - FileTemplate t(templates); + FileTemplate t(setup.settings(), templates); EXPECT_FALSE(t.has_substitutions()); std::vector<std::string> result; - t.ApplyString("", &result); - ASSERT_EQ(1u, result.size()); - EXPECT_EQ("something_static", result[0]); - - result.clear(); - t.ApplyString("lalala", &result); + t.Apply(SourceFile("//foo/bar"), &result); ASSERT_EQ(1u, result.size()); EXPECT_EQ("something_static", result[0]); } TEST(FileTemplate, Typical) { + TestWithScope setup; + std::vector<std::string> templates; templates.push_back("foo/{{source_name_part}}.cc"); templates.push_back("foo/{{source_name_part}}.h"); - FileTemplate t(templates); + FileTemplate t(setup.settings(), templates); EXPECT_TRUE(t.has_substitutions()); std::vector<std::string> result; - t.ApplyString("sources/ha.idl", &result); + t.Apply(SourceFile("//sources/ha.idl"), &result); ASSERT_EQ(2u, result.size()); EXPECT_EQ("foo/ha.cc", result[0]); EXPECT_EQ("foo/ha.h", result[1]); } TEST(FileTemplate, Weird) { + TestWithScope setup; + std::vector<std::string> templates; templates.push_back("{{{source}}{{source}}{{"); - FileTemplate t(templates); + FileTemplate t(setup.settings(), templates); EXPECT_TRUE(t.has_substitutions()); std::vector<std::string> result; - t.ApplyString("foo/lalala.c", &result); + t.Apply(SourceFile("//foo/lalala.c"), &result); ASSERT_EQ(1u, result.size()); - EXPECT_EQ("{foo/lalala.cfoo/lalala.c{{", result[0]); + EXPECT_EQ("{../../foo/lalala.c../../foo/lalala.c{{", result[0]); } TEST(FileTemplate, NinjaExpansions) { + TestWithScope setup; + std::vector<std::string> templates; templates.push_back("-i"); templates.push_back("{{source}}"); templates.push_back("--out=foo bar\"{{source_name_part}}\".o"); templates.push_back(""); // Test empty string. - FileTemplate t(templates); + FileTemplate t(setup.settings(), templates); std::ostringstream out; t.WriteWithNinjaExpansions(out); @@ -79,21 +83,64 @@ TEST(FileTemplate, NinjaExpansions) { } TEST(FileTemplate, NinjaVariables) { + TestWithScope setup; + std::vector<std::string> templates; templates.push_back("-i"); templates.push_back("{{source}}"); templates.push_back("--out=foo bar\"{{source_name_part}}\".o"); + templates.push_back("{{source_file_part}}"); + templates.push_back("{{source_dir}}"); + templates.push_back("{{source_root_relative_dir}}"); + templates.push_back("{{source_gen_dir}}"); + templates.push_back("{{source_out_dir}}"); - FileTemplate t(templates); + FileTemplate t(setup.settings(), templates); std::ostringstream out; EscapeOptions options; options.mode = ESCAPE_NINJA_COMMAND; - t.WriteNinjaVariablesForSubstitution(out, "../../foo/bar.txt", options); + t.WriteNinjaVariablesForSubstitution(out, setup.settings(), + SourceFile("//foo/bar.txt"), options); // Just the variables used above should be written. EXPECT_EQ( " source = ../../foo/bar.txt\n" - " source_name_part = bar\n", + " source_name_part = bar\n" + " source_file_part = bar.txt\n" + " source_dir = ../../foo\n" + " source_root_rel_dir = foo\n" + " source_gen_dir = gen/foo\n" + " source_out_dir = obj/foo\n", out.str()); } + +// Tests in isolation different types of substitutions and that the right +// things are generated. +TEST(FileTemplate, Substitutions) { + TestWithScope setup; + + #define GetSubst(str, what) \ + FileTemplate::GetSubstitution(setup.settings(), \ + SourceFile(str), \ + FileTemplate::Subrange::what) + + // Try all possible templates with a normal looking string. + EXPECT_EQ("../../foo/bar/baz.txt", GetSubst("//foo/bar/baz.txt", SOURCE)); + EXPECT_EQ("baz", GetSubst("//foo/bar/baz.txt", NAME_PART)); + EXPECT_EQ("baz.txt", GetSubst("//foo/bar/baz.txt", FILE_PART)); + EXPECT_EQ("../../foo/bar", GetSubst("//foo/bar/baz.txt", SOURCE_DIR)); + EXPECT_EQ("foo/bar", GetSubst("//foo/bar/baz.txt", ROOT_RELATIVE_DIR)); + EXPECT_EQ("gen/foo/bar", GetSubst("//foo/bar/baz.txt", SOURCE_GEN_DIR)); + EXPECT_EQ("obj/foo/bar", GetSubst("//foo/bar/baz.txt", SOURCE_OUT_DIR)); + + // Operations on an absolute path. + EXPECT_EQ("/baz.txt", GetSubst("/baz.txt", SOURCE)); + EXPECT_EQ("/.", GetSubst("/baz.txt", SOURCE_DIR)); + EXPECT_EQ("gen", GetSubst("/baz.txt", SOURCE_GEN_DIR)); + EXPECT_EQ("obj", GetSubst("/baz.txt", SOURCE_OUT_DIR)); + + EXPECT_EQ(".", GetSubst("//baz.txt", ROOT_RELATIVE_DIR)); + + #undef GetSubst +} diff --git a/tools/gn/filesystem_utils.cc b/tools/gn/filesystem_utils.cc index 4cfefa9..ca45625 100644 --- a/tools/gn/filesystem_utils.cc +++ b/tools/gn/filesystem_utils.cc @@ -720,10 +720,12 @@ SourceDir GetOutputDirForSourceDir(const Settings* settings, toolchain.SwapValue(&ret); ret.append("obj/"); - // The source dir should be source-absolute, so we trim off the two leading - // slashes to append to the toolchain object directory. - DCHECK(source_dir.is_source_absolute()); - ret.append(&source_dir.value()[2], source_dir.value().size() - 2); + if (source_dir.is_source_absolute()) { + // The source dir is source-absolute, so we trim off the two leading + // slashes to append to the toolchain object directory. + ret.append(&source_dir.value()[2], source_dir.value().size() - 2); + } + // (Put system-absolute stuff in the root obj directory.) return SourceDir(SourceDir::SWAP_IN, &ret); } @@ -735,10 +737,13 @@ SourceDir GetGenDirForSourceDir(const Settings* settings, std::string ret; toolchain.SwapValue(&ret); - // The source dir should be source-absolute, so we trim off the two leading - // slashes to append to the toolchain object directory. - DCHECK(source_dir.is_source_absolute()); - ret.append(&source_dir.value()[2], source_dir.value().size() - 2); + if (source_dir.is_source_absolute()) { + // The source dir should be source-absolute, so we trim off the two leading + // slashes to append to the toolchain object directory. + DCHECK(source_dir.is_source_absolute()); + ret.append(&source_dir.value()[2], source_dir.value().size() - 2); + } + // (Put system-absolute stuff in the root gen directory.) return SourceDir(SourceDir::SWAP_IN, &ret); } diff --git a/tools/gn/function_get_path_info.cc b/tools/gn/function_get_path_info.cc index 23f690c..ea6651c 100644 --- a/tools/gn/function_get_path_info.cc +++ b/tools/gn/function_get_path_info.cc @@ -20,9 +20,25 @@ enum What { WHAT_EXTENSION, WHAT_DIR, WHAT_ABSPATH, + WHAT_GEN_DIR, + WHAT_OUT_DIR, }; -std::string GetOnePathInfo(const SourceDir& current_dir, +// Returns the directory containing the input (resolving it against the +// |current_dir|), regardless of whether the input is a directory or a file. +SourceDir DirForInput(const SourceDir& current_dir, + const std::string& input_string) { + if (!input_string.empty() && input_string[input_string.size() - 1] == '/') { + // Input is a directory. + return current_dir.ResolveRelativeDir(input_string); + } + + // Input is a directory. + return current_dir.ResolveRelativeFile(input_string).GetDir(); +} + +std::string GetOnePathInfo(const Settings* settings, + const SourceDir& current_dir, What what, const Value& input, Err* err) { @@ -62,6 +78,16 @@ std::string GetOnePathInfo(const SourceDir& current_dir, return std::string("//."); return dir_incl_slash.substr(0, dir_incl_slash.size() - 1).as_string(); } + case WHAT_GEN_DIR: { + return DirectoryWithNoLastSlash( + GetGenDirForSourceDir(settings, + DirForInput(current_dir, input_string))); + } + case WHAT_OUT_DIR: { + return DirectoryWithNoLastSlash( + GetOutputDirForSourceDir(settings, + DirForInput(current_dir, input_string))); + } case WHAT_ABSPATH: { if (!input_string.empty() && input_string[input_string.size() - 1] == '/') return current_dir.ResolveRelativeDir(input_string).value(); @@ -123,6 +149,16 @@ const char kGetPathInfo_Help[] = " will be appended such that it is always legal to append a slash\n" " and a filename and get a valid path.\n" "\n" + " \"out_dir\"\n" + " The output file directory corresponding to the path of the\n" + " given file, not including a trailing slash.\n" + " \"//foo/bar/baz.txt\" => \"//out/Default/obj/foo/bar\"\n" + + " \"gen_dir\"\n" + " The generated file directory corresponding to the path of the\n" + " given file, not including a trailing slash.\n" + " \"//foo/bar/baz.txt\" => \"//out/Default/gen/foo/bar\"\n" + "\n" " \"abspath\"\n" " The full absolute path name to the file or directory. It will be\n" " resolved relative to the currebt directory, and then the source-\n" @@ -168,6 +204,10 @@ Value RunGetPathInfo(Scope* scope, what = WHAT_EXTENSION; } else if (args[1].string_value() == "dir") { what = WHAT_DIR; + } else if (args[1].string_value() == "out_dir") { + what = WHAT_OUT_DIR; + } else if (args[1].string_value() == "gen_dir") { + what = WHAT_GEN_DIR; } else if (args[1].string_value() == "abspath") { what = WHAT_ABSPATH; } else { @@ -177,13 +217,15 @@ Value RunGetPathInfo(Scope* scope, const SourceDir& current_dir = scope->GetSourceDir(); if (args[0].type() == Value::STRING) { - return Value(function, GetOnePathInfo(current_dir, what, args[0], err)); + return Value(function, GetOnePathInfo(scope->settings(), current_dir, what, + args[0], err)); } else if (args[0].type() == Value::LIST) { const std::vector<Value>& input_list = args[0].list_value(); Value result(function, Value::LIST); for (size_t i = 0; i < input_list.size(); i++) { result.list_value().push_back(Value(function, - GetOnePathInfo(current_dir, what, input_list[i], err))); + GetOnePathInfo(scope->settings(), current_dir, what, + input_list[i], err))); if (err->has_error()) return Value(); } diff --git a/tools/gn/function_get_path_info_unittest.cc b/tools/gn/function_get_path_info_unittest.cc index 12bdc2a..1756c0c 100644 --- a/tools/gn/function_get_path_info_unittest.cc +++ b/tools/gn/function_get_path_info_unittest.cc @@ -87,3 +87,25 @@ TEST_F(GetPathInfoTest, AbsPath) { EXPECT_EQ("/foo/", Call("/foo/", "abspath")); EXPECT_EQ("/", Call("/", "abspath")); } + +// Note build dir is "//out/Debug/". +TEST_F(GetPathInfoTest, OutDir) { + EXPECT_EQ("//out/Debug/obj/src/foo/foo", Call("foo/bar.txt", "out_dir")); + EXPECT_EQ("//out/Debug/obj/src/foo/bar", Call("bar/", "out_dir")); + EXPECT_EQ("//out/Debug/obj/src/foo", Call(".", "out_dir")); + EXPECT_EQ("//out/Debug/obj/src/foo", Call("bar", "out_dir")); + EXPECT_EQ("//out/Debug/obj/foo", Call("//foo/bar.txt", "out_dir")); + // System paths go into the root obj directory. + EXPECT_EQ("//out/Debug/obj", Call("/foo/bar.txt", "out_dir")); +} + +// Note build dir is "//out/Debug/". +TEST_F(GetPathInfoTest, GenDir) { + EXPECT_EQ("//out/Debug/gen/src/foo/foo", Call("foo/bar.txt", "gen_dir")); + EXPECT_EQ("//out/Debug/gen/src/foo/bar", Call("bar/", "gen_dir")); + EXPECT_EQ("//out/Debug/gen/src/foo", Call(".", "gen_dir")); + EXPECT_EQ("//out/Debug/gen/src/foo", Call("bar", "gen_dir")); + EXPECT_EQ("//out/Debug/gen/foo", Call("//foo/bar.txt", "gen_dir")); + // System paths go into the root obj directory. + EXPECT_EQ("//out/Debug/gen", Call("/foo/bar.txt", "gen_dir")); +} diff --git a/tools/gn/function_get_target_outputs.cc b/tools/gn/function_get_target_outputs.cc index 370fee9..be014f2 100644 --- a/tools/gn/function_get_target_outputs.cc +++ b/tools/gn/function_get_target_outputs.cc @@ -15,7 +15,7 @@ namespace functions { namespace { -void GetOutputsForTarget(const BuildSettings* build_settings, +void GetOutputsForTarget(const Settings* settings, const Target* target, std::vector<std::string>* ret) { switch (target->output_type()) { @@ -31,10 +31,10 @@ void GetOutputsForTarget(const BuildSettings* build_settings, case Target::ACTION_FOREACH: { // Action_foreach: return the result of the template in the outputs. - FileTemplate file_template(target->action_values().outputs()); + FileTemplate file_template(settings, 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); + file_template.Apply(sources[i], ret); break; } @@ -50,11 +50,12 @@ void GetOutputsForTarget(const BuildSettings* build_settings, case Target::GROUP: case Target::SOURCE_SET: { // These return the stamp file, which is computed by the NinjaHelper. - NinjaHelper helper(build_settings); + NinjaHelper helper(settings->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(); + std::string absolute_output_file = + settings->build_settings()->build_dir().value(); absolute_output_file.append(output_file.value()); ret->push_back(absolute_output_file); @@ -168,7 +169,7 @@ Value RunGetTargetOutputs(Scope* scope, } std::vector<std::string> files; - GetOutputsForTarget(scope->settings()->build_settings(), target, &files); + GetOutputsForTarget(scope->settings(), target, &files); Value ret(function, Value::LIST); ret.list_value().reserve(files.size()); diff --git a/tools/gn/function_process_file_template.cc b/tools/gn/function_process_file_template.cc index 5d4c9d7..061c901 100644 --- a/tools/gn/function_process_file_template.cc +++ b/tools/gn/function_process_file_template.cc @@ -5,6 +5,10 @@ #include "tools/gn/file_template.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/target.h" +#include "tools/gn/value_extractors.h" namespace functions { @@ -67,12 +71,26 @@ Value RunProcessFileTemplate(Scope* scope, return Value(); } - FileTemplate file_template(args[1], err); + FileTemplate file_template(scope->settings(), args[1], err); if (err->has_error()) return Value(); + Target::FileList input_files; + if (!ExtractListOfRelativeFiles(scope->settings()->build_settings(), args[0], + scope->GetSourceDir(), &input_files, err)) + return Value(); + Value ret(function, Value::LIST); - file_template.Apply(args[0], function, &ret.list_value(), err); + + // Temporary holding place, allocate outside to re-use buffer. + std::vector<std::string> string_output; + + for (size_t i = 0; i < input_files.size(); i++) { + string_output.clear(); + file_template.Apply(input_files[i], &string_output); + for (size_t out_i = 0; out_i < string_output.size(); out_i++) + ret.list_value().push_back(Value(function, string_output[out_i])); + } return ret; } diff --git a/tools/gn/ninja_action_target_writer.cc b/tools/gn/ninja_action_target_writer.cc index 7f14e74..6a632e7 100644 --- a/tools/gn/ninja_action_target_writer.cc +++ b/tools/gn/ninja_action_target_writer.cc @@ -23,7 +23,8 @@ NinjaActionTargetWriter::~NinjaActionTargetWriter() { } void NinjaActionTargetWriter::Run() { - FileTemplate args_template(target_->action_values().args()); + FileTemplate args_template(target_->settings(), + target_->action_values().args()); std::string custom_rule_name = WriteRuleDefinition(args_template); // Collect our deps to pass as "extra hard dependencies" for input deps. This @@ -136,14 +137,11 @@ std::string NinjaActionTargetWriter::WriteRuleDefinition( void NinjaActionTargetWriter::WriteArgsSubstitutions( const SourceFile& source, const FileTemplate& args_template) { - std::ostringstream source_file_stream; - path_output_no_escaping_.WriteFile(source_file_stream, source); - EscapeOptions template_escape_options; template_escape_options.mode = ESCAPE_NINJA_COMMAND; args_template.WriteNinjaVariablesForSubstitution( - out_, source_file_stream.str(), template_escape_options); + out_, target_->settings(), source, template_escape_options); } void NinjaActionTargetWriter::WriteSourceRules( @@ -208,7 +206,7 @@ void NinjaActionTargetWriter::WriteOutputFilesForBuildLine( const SourceFile& source, std::vector<OutputFile>* output_files) { std::vector<std::string> output_template_result; - output_template.ApplyString(source.value(), &output_template_result); + output_template.Apply(source, &output_template_result); for (size_t out_i = 0; out_i < output_template_result.size(); out_i++) { OutputFile output_path(output_template_result[out_i]); output_files->push_back(output_path); @@ -219,7 +217,7 @@ void NinjaActionTargetWriter::WriteOutputFilesForBuildLine( void NinjaActionTargetWriter::WriteDepfile(const SourceFile& source) { std::vector<std::string> result; - GetDepfileTemplate().ApplyString(source.value(), &result); + GetDepfileTemplate().Apply(source, &result); path_output_.WriteFile(out_, OutputFile(result[0])); } @@ -229,5 +227,5 @@ FileTemplate NinjaActionTargetWriter::GetDepfileTemplate() const { RemovePrefix(target_->action_values().depfile().value(), settings_->build_settings()->build_dir().value()); template_args.push_back(depfile_relative_to_build_dir); - return FileTemplate(template_args); + return FileTemplate(settings_, template_args); } diff --git a/tools/gn/ninja_action_target_writer_unittest.cc b/tools/gn/ninja_action_target_writer_unittest.cc index 9899e2c..c6aa5f8 100644 --- a/tools/gn/ninja_action_target_writer_unittest.cc +++ b/tools/gn/ninja_action_target_writer_unittest.cc @@ -44,7 +44,7 @@ TEST(NinjaActionTargetWriter, WriteArgsSubstitutions) { args.push_back("-i"); args.push_back("{{source}}"); args.push_back("--out=foo bar{{source_name_part}}.o"); - FileTemplate args_template(args); + FileTemplate args_template(setup.settings(), args); writer.WriteArgsSubstitutions(SourceFile("//foo/b ar.in"), args_template); #if defined(OS_WIN) diff --git a/tools/gn/ninja_copy_target_writer.cc b/tools/gn/ninja_copy_target_writer.cc index 9ab88e4..4f8534f 100644 --- a/tools/gn/ninja_copy_target_writer.cc +++ b/tools/gn/ninja_copy_target_writer.cc @@ -30,7 +30,7 @@ void NinjaCopyTargetWriter::Run() { // Make the output file from the template. std::vector<std::string> template_result; - output_template.ApplyString(input_file.value(), &template_result); + output_template.Apply(input_file, &template_result); CHECK(template_result.size() == 1); OutputFile output_file(template_result[0]); diff --git a/tools/gn/ninja_target_writer.cc b/tools/gn/ninja_target_writer.cc index b6412dc..2383251 100644 --- a/tools/gn/ninja_target_writer.cc +++ b/tools/gn/ninja_target_writer.cc @@ -165,5 +165,5 @@ FileTemplate NinjaTargetWriter::GetOutputTemplate() const { RemovePrefix(outputs[i].value(), settings_->build_settings()->build_dir().value())); } - return FileTemplate(output_template_args); + return FileTemplate(target_->settings(), output_template_args); } |