Commit e9bf4fcb authored by brettw@chromium.org's avatar brettw@chromium.org

Add directory extraction to GN path handling.

Some of the mojo templates want to put generated files in the directory
corresponding to the source file, rather than the directory containing the
BUILD file. Previously, this required putting the BUILD files in the same
directory.

This patch adds the ability to specify the generated file directory
corresponding to the input file in the action_foreach file templates so this
can be expressed naturally.

For parity, it also adds qquerying for this information via get_path_info.

BUG=
R=cjhopman@chromium.org

Review URL: https://codereview.chromium.org/334333005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278402 0039d316-1c4b-4281-b951-d872f2087c98
parent 252e6603
...@@ -276,7 +276,7 @@ void PrintOutputs(const Target* target, bool display_header) { ...@@ -276,7 +276,7 @@ void PrintOutputs(const Target* target, bool display_header) {
std::vector<std::string> output_strings; std::vector<std::string> output_strings;
FileTemplate file_template = FileTemplate::GetForTargetOutputs(target); FileTemplate file_template = FileTemplate::GetForTargetOutputs(target);
for (size_t i = 0; i < target->sources().size(); i++) 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()); std::sort(output_strings.begin(), output_strings.end());
for (size_t i = 0; i < output_strings.size(); i++) { for (size_t i = 0; i < output_strings.size(); i++) {
......
This diff is collapsed.
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
struct EscapeOptions; struct EscapeOptions;
class ParseNode; class ParseNode;
class Settings;
class SourceFile; class SourceFile;
class Target; class Target;
...@@ -30,20 +31,17 @@ extern const char kSourceExpansion_Help[]; ...@@ -30,20 +31,17 @@ extern const char kSourceExpansion_Help[];
class FileTemplate { class FileTemplate {
public: public:
struct Subrange { struct Subrange {
// See the help in the .cc file for what these mean.
enum Type { enum Type {
LITERAL = 0, LITERAL = 0,
// {{source}} -> expands to be the source file name relative to the build SOURCE, // {{source}}
// root dir. NAME_PART, // {{source_name_part}}
SOURCE, FILE_PART, // {{source_file_part}}
SOURCE_DIR, // {{source_dir}}
// {{source_name_part}} -> file name without extension or directory. ROOT_RELATIVE_DIR, // {{root_relative_dir}}
// Maps "foo/bar.txt" to "bar". SOURCE_GEN_DIR, // {{source_gen_dir}}
NAME_PART, SOURCE_OUT_DIR, // {{source_out_dir}}
// {{source_file_part}} -> file name including extension but no directory.
// Maps "foo/bar.txt" to "bar.txt".
FILE_PART,
NUM_TYPES // Must be last NUM_TYPES // Must be last
}; };
...@@ -60,9 +58,9 @@ class FileTemplate { ...@@ -60,9 +58,9 @@ class FileTemplate {
// Constructs a template from the given value. On error, the err will be // Constructs a template from the given value. On error, the err will be
// set. In this case you should not use this object. // set. In this case you should not use this object.
FileTemplate(const Value& t, Err* err); FileTemplate(const Settings* settings, const Value& t, Err* err);
FileTemplate(const std::vector<std::string>& t); FileTemplate(const Settings* settings, const std::vector<std::string>& t);
FileTemplate(const std::vector<SourceFile>& t); FileTemplate(const Settings* settings, const std::vector<SourceFile>& t);
~FileTemplate(); ~FileTemplate();
...@@ -76,17 +74,9 @@ class FileTemplate { ...@@ -76,17 +74,9 @@ class FileTemplate {
// Returns true if there are any substitutions. // Returns true if there are any substitutions.
bool has_substitutions() const { return has_substitutions_; } bool has_substitutions() const { return has_substitutions_; }
// Applies this template to the given list of sources, appending all // Applies the template to one source file. The results will be *appended* to
// results to the given dest list. The sources must be a list for the // the output.
// one that takes a value as an input, otherwise the given error will be set. void Apply(const SourceFile& source,
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; std::vector<std::string>* output) const;
// Writes a string representing the template with Ninja variables for the // Writes a string representing the template with Ninja variables for the
...@@ -115,7 +105,8 @@ class FileTemplate { ...@@ -115,7 +105,8 @@ class FileTemplate {
// (see GetWithNinjaExpansions). // (see GetWithNinjaExpansions).
void WriteNinjaVariablesForSubstitution( void WriteNinjaVariablesForSubstitution(
std::ostream& out, std::ostream& out,
const std::string& source, const Settings* settings,
const SourceFile& source,
const EscapeOptions& escape_options) const; const EscapeOptions& escape_options) const;
// Returns the Ninja variable name used by the above Ninja functions to // Returns the Ninja variable name used by the above Ninja functions to
...@@ -124,13 +115,18 @@ class FileTemplate { ...@@ -124,13 +115,18 @@ class FileTemplate {
// Extracts the given type of substitution from the given source. The source // Extracts the given type of substitution from the given source. The source
// should be the file name relative to the output directory. // 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); Subrange::Type type);
// Known template types, these include the "{{ }}" // Known template types, these include the "{{ }}"
static const char kSource[]; static const char kSource[];
static const char kSourceNamePart[]; static const char kSourceNamePart[];
static const char kSourceFilePart[]; static const char kSourceFilePart[];
static const char kSourceDir[];
static const char kRootRelDir[];
static const char kSourceGenDir[];
static const char kSourceOutDir[];
private: private:
typedef base::StackVector<Subrange, 8> Template; typedef base::StackVector<Subrange, 8> Template;
...@@ -141,6 +137,8 @@ class FileTemplate { ...@@ -141,6 +137,8 @@ class FileTemplate {
// Parses a template string and adds it to the templates_ list. // Parses a template string and adds it to the templates_ list.
void ParseOneTemplateString(const std::string& str); void ParseOneTemplateString(const std::string& str);
const Settings* settings_;
TemplateVector templates_; TemplateVector templates_;
// The corresponding value is set to true if the given subrange type is // The corresponding value is set to true if the given subrange type is
......
...@@ -7,58 +7,62 @@ ...@@ -7,58 +7,62 @@
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "tools/gn/escape.h" #include "tools/gn/escape.h"
#include "tools/gn/file_template.h" #include "tools/gn/file_template.h"
#include "tools/gn/test_with_scope.h"
TEST(FileTemplate, Static) { TEST(FileTemplate, Static) {
TestWithScope setup;
std::vector<std::string> templates; std::vector<std::string> templates;
templates.push_back("something_static"); templates.push_back("something_static");
FileTemplate t(templates); FileTemplate t(setup.settings(), templates);
EXPECT_FALSE(t.has_substitutions()); EXPECT_FALSE(t.has_substitutions());
std::vector<std::string> result; std::vector<std::string> result;
t.ApplyString("", &result); t.Apply(SourceFile("//foo/bar"), &result);
ASSERT_EQ(1u, result.size());
EXPECT_EQ("something_static", result[0]);
result.clear();
t.ApplyString("lalala", &result);
ASSERT_EQ(1u, result.size()); ASSERT_EQ(1u, result.size());
EXPECT_EQ("something_static", result[0]); EXPECT_EQ("something_static", result[0]);
} }
TEST(FileTemplate, Typical) { TEST(FileTemplate, Typical) {
TestWithScope setup;
std::vector<std::string> templates; std::vector<std::string> templates;
templates.push_back("foo/{{source_name_part}}.cc"); templates.push_back("foo/{{source_name_part}}.cc");
templates.push_back("foo/{{source_name_part}}.h"); templates.push_back("foo/{{source_name_part}}.h");
FileTemplate t(templates); FileTemplate t(setup.settings(), templates);
EXPECT_TRUE(t.has_substitutions()); EXPECT_TRUE(t.has_substitutions());
std::vector<std::string> result; std::vector<std::string> result;
t.ApplyString("sources/ha.idl", &result); t.Apply(SourceFile("//sources/ha.idl"), &result);
ASSERT_EQ(2u, result.size()); ASSERT_EQ(2u, result.size());
EXPECT_EQ("foo/ha.cc", result[0]); EXPECT_EQ("foo/ha.cc", result[0]);
EXPECT_EQ("foo/ha.h", result[1]); EXPECT_EQ("foo/ha.h", result[1]);
} }
TEST(FileTemplate, Weird) { TEST(FileTemplate, Weird) {
TestWithScope setup;
std::vector<std::string> templates; std::vector<std::string> templates;
templates.push_back("{{{source}}{{source}}{{"); templates.push_back("{{{source}}{{source}}{{");
FileTemplate t(templates); FileTemplate t(setup.settings(), templates);
EXPECT_TRUE(t.has_substitutions()); EXPECT_TRUE(t.has_substitutions());
std::vector<std::string> result; std::vector<std::string> result;
t.ApplyString("foo/lalala.c", &result); t.Apply(SourceFile("//foo/lalala.c"), &result);
ASSERT_EQ(1u, result.size()); 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) { TEST(FileTemplate, NinjaExpansions) {
TestWithScope setup;
std::vector<std::string> templates; std::vector<std::string> templates;
templates.push_back("-i"); templates.push_back("-i");
templates.push_back("{{source}}"); templates.push_back("{{source}}");
templates.push_back("--out=foo bar\"{{source_name_part}}\".o"); templates.push_back("--out=foo bar\"{{source_name_part}}\".o");
templates.push_back(""); // Test empty string. templates.push_back(""); // Test empty string.
FileTemplate t(templates); FileTemplate t(setup.settings(), templates);
std::ostringstream out; std::ostringstream out;
t.WriteWithNinjaExpansions(out); t.WriteWithNinjaExpansions(out);
...@@ -79,21 +83,64 @@ TEST(FileTemplate, NinjaExpansions) { ...@@ -79,21 +83,64 @@ TEST(FileTemplate, NinjaExpansions) {
} }
TEST(FileTemplate, NinjaVariables) { TEST(FileTemplate, NinjaVariables) {
TestWithScope setup;
std::vector<std::string> templates; std::vector<std::string> templates;
templates.push_back("-i"); templates.push_back("-i");
templates.push_back("{{source}}"); templates.push_back("{{source}}");
templates.push_back("--out=foo bar\"{{source_name_part}}\".o"); 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; std::ostringstream out;
EscapeOptions options; EscapeOptions options;
options.mode = ESCAPE_NINJA_COMMAND; 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. // Just the variables used above should be written.
EXPECT_EQ( EXPECT_EQ(
" source = ../../foo/bar.txt\n" " 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()); 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
}
...@@ -720,10 +720,12 @@ SourceDir GetOutputDirForSourceDir(const Settings* settings, ...@@ -720,10 +720,12 @@ SourceDir GetOutputDirForSourceDir(const Settings* settings,
toolchain.SwapValue(&ret); toolchain.SwapValue(&ret);
ret.append("obj/"); ret.append("obj/");
// The source dir should be source-absolute, so we trim off the two leading 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. // 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); 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); return SourceDir(SourceDir::SWAP_IN, &ret);
} }
...@@ -735,10 +737,13 @@ SourceDir GetGenDirForSourceDir(const Settings* settings, ...@@ -735,10 +737,13 @@ SourceDir GetGenDirForSourceDir(const Settings* settings,
std::string ret; std::string ret;
toolchain.SwapValue(&ret); toolchain.SwapValue(&ret);
if (source_dir.is_source_absolute()) {
// The source dir should be source-absolute, so we trim off the two leading // The source dir should be source-absolute, so we trim off the two leading
// slashes to append to the toolchain object directory. // slashes to append to the toolchain object directory.
DCHECK(source_dir.is_source_absolute()); DCHECK(source_dir.is_source_absolute());
ret.append(&source_dir.value()[2], source_dir.value().size() - 2); 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); return SourceDir(SourceDir::SWAP_IN, &ret);
} }
......
...@@ -20,9 +20,25 @@ enum What { ...@@ -20,9 +20,25 @@ enum What {
WHAT_EXTENSION, WHAT_EXTENSION,
WHAT_DIR, WHAT_DIR,
WHAT_ABSPATH, 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, What what,
const Value& input, const Value& input,
Err* err) { Err* err) {
...@@ -62,6 +78,16 @@ std::string GetOnePathInfo(const SourceDir& current_dir, ...@@ -62,6 +78,16 @@ std::string GetOnePathInfo(const SourceDir& current_dir,
return std::string("//."); return std::string("//.");
return dir_incl_slash.substr(0, dir_incl_slash.size() - 1).as_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: { case WHAT_ABSPATH: {
if (!input_string.empty() && input_string[input_string.size() - 1] == '/') if (!input_string.empty() && input_string[input_string.size() - 1] == '/')
return current_dir.ResolveRelativeDir(input_string).value(); return current_dir.ResolveRelativeDir(input_string).value();
...@@ -123,6 +149,16 @@ const char kGetPathInfo_Help[] = ...@@ -123,6 +149,16 @@ const char kGetPathInfo_Help[] =
" will be appended such that it is always legal to append a slash\n" " will be appended such that it is always legal to append a slash\n"
" and a filename and get a valid path.\n" " and a filename and get a valid path.\n"
"\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" " \"abspath\"\n"
" The full absolute path name to the file or directory. It will be\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" " resolved relative to the currebt directory, and then the source-\n"
...@@ -168,6 +204,10 @@ Value RunGetPathInfo(Scope* scope, ...@@ -168,6 +204,10 @@ Value RunGetPathInfo(Scope* scope,
what = WHAT_EXTENSION; what = WHAT_EXTENSION;
} else if (args[1].string_value() == "dir") { } else if (args[1].string_value() == "dir") {
what = WHAT_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") { } else if (args[1].string_value() == "abspath") {
what = WHAT_ABSPATH; what = WHAT_ABSPATH;
} else { } else {
...@@ -177,13 +217,15 @@ Value RunGetPathInfo(Scope* scope, ...@@ -177,13 +217,15 @@ Value RunGetPathInfo(Scope* scope,
const SourceDir& current_dir = scope->GetSourceDir(); const SourceDir& current_dir = scope->GetSourceDir();
if (args[0].type() == Value::STRING) { 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) { } else if (args[0].type() == Value::LIST) {
const std::vector<Value>& input_list = args[0].list_value(); const std::vector<Value>& input_list = args[0].list_value();
Value result(function, Value::LIST); Value result(function, Value::LIST);
for (size_t i = 0; i < input_list.size(); i++) { for (size_t i = 0; i < input_list.size(); i++) {
result.list_value().push_back(Value(function, 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()) if (err->has_error())
return Value(); return Value();
} }
......
...@@ -87,3 +87,25 @@ TEST_F(GetPathInfoTest, AbsPath) { ...@@ -87,3 +87,25 @@ TEST_F(GetPathInfoTest, AbsPath) {
EXPECT_EQ("/foo/", Call("/foo/", "abspath")); EXPECT_EQ("/foo/", Call("/foo/", "abspath"));
EXPECT_EQ("/", Call("/", "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"));
}
...@@ -15,7 +15,7 @@ namespace functions { ...@@ -15,7 +15,7 @@ namespace functions {
namespace { namespace {
void GetOutputsForTarget(const BuildSettings* build_settings, void GetOutputsForTarget(const Settings* settings,
const Target* target, const Target* target,
std::vector<std::string>* ret) { std::vector<std::string>* ret) {
switch (target->output_type()) { switch (target->output_type()) {
...@@ -31,10 +31,10 @@ void GetOutputsForTarget(const BuildSettings* build_settings, ...@@ -31,10 +31,10 @@ void GetOutputsForTarget(const BuildSettings* build_settings,
case Target::ACTION_FOREACH: { case Target::ACTION_FOREACH: {
// Action_foreach: return the result of the template in the outputs. // 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(); const std::vector<SourceFile>& sources = target->sources();
for (size_t i = 0; i < sources.size(); i++) for (size_t i = 0; i < sources.size(); i++)
file_template.ApplyString(sources[i].value(), ret); file_template.Apply(sources[i], ret);
break; break;
} }
...@@ -50,11 +50,12 @@ void GetOutputsForTarget(const BuildSettings* build_settings, ...@@ -50,11 +50,12 @@ void GetOutputsForTarget(const BuildSettings* build_settings,
case Target::GROUP: case Target::GROUP:
case Target::SOURCE_SET: { case Target::SOURCE_SET: {
// These return the stamp file, which is computed by the NinjaHelper. // 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); OutputFile output_file = helper.GetTargetOutputFile(target);
// The output file is relative to the build dir. // 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()); absolute_output_file.append(output_file.value());
ret->push_back(absolute_output_file); ret->push_back(absolute_output_file);
...@@ -168,7 +169,7 @@ Value RunGetTargetOutputs(Scope* scope, ...@@ -168,7 +169,7 @@ Value RunGetTargetOutputs(Scope* scope,
} }
std::vector<std::string> files; std::vector<std::string> files;
GetOutputsForTarget(scope->settings()->build_settings(), target, &files); GetOutputsForTarget(scope->settings(), target, &files);
Value ret(function, Value::LIST); Value ret(function, Value::LIST);
ret.list_value().reserve(files.size()); ret.list_value().reserve(files.size());
......
...@@ -5,6 +5,10 @@ ...@@ -5,6 +5,10 @@
#include "tools/gn/file_template.h" #include "tools/gn/file_template.h"
#include "tools/gn/functions.h" #include "tools/gn/functions.h"
#include "tools/gn/parse_tree.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 { namespace functions {
...@@ -67,12 +71,26 @@ Value RunProcessFileTemplate(Scope* scope, ...@@ -67,12 +71,26 @@ Value RunProcessFileTemplate(Scope* scope,
return Value(); return Value();
} }
FileTemplate file_template(args[1], err); FileTemplate file_template(scope->settings(), args[1], err);
if (err->has_error()) if (err->has_error())
return Value(); 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); 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; return ret;
} }
......
...@@ -23,7 +23,8 @@ NinjaActionTargetWriter::~NinjaActionTargetWriter() { ...@@ -23,7 +23,8 @@ NinjaActionTargetWriter::~NinjaActionTargetWriter() {
} }
void NinjaActionTargetWriter::Run() { 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); std::string custom_rule_name = WriteRuleDefinition(args_template);
// Collect our deps to pass as "extra hard dependencies" for input deps. This // Collect our deps to pass as "extra hard dependencies" for input deps. This
...@@ -136,14 +137,11 @@ std::string NinjaActionTargetWriter::WriteRuleDefinition( ...@@ -136,14 +137,11 @@ std::string NinjaActionTargetWriter::WriteRuleDefinition(
void NinjaActionTargetWriter::WriteArgsSubstitutions( void NinjaActionTargetWriter::WriteArgsSubstitutions(
const SourceFile& source, const SourceFile& source,
const FileTemplate& args_template) { const FileTemplate& args_template) {
std::ostringstream source_file_stream;
path_output_no_escaping_.WriteFile(source_file_stream, source);
EscapeOptions template_escape_options; EscapeOptions template_escape_options;
template_escape_options.mode = ESCAPE_NINJA_COMMAND; template_escape_options.mode = ESCAPE_NINJA_COMMAND;
args_template.WriteNinjaVariablesForSubstitution( args_template.WriteNinjaVariablesForSubstitution(
out_, source_file_stream.str(), template_escape_options); out_, target_->settings(), source, template_escape_options);
} }
void NinjaActionTargetWriter::WriteSourceRules( void NinjaActionTargetWriter::WriteSourceRules(
...@@ -208,7 +206,7 @@ void NinjaActionTargetWriter::WriteOutputFilesForBuildLine( ...@@ -208,7 +206,7 @@ void NinjaActionTargetWriter::WriteOutputFilesForBuildLine(
const SourceFile& source, const SourceFile& source,
std::vector<OutputFile>* output_files) { std::vector<OutputFile>* output_files) {
std::vector<std::string> output_template_result; 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++) { for (size_t out_i = 0; out_i < output_template_result.size(); out_i++) {
OutputFile output_path(output_template_result[out_i]); OutputFile output_path(output_template_result[out_i]);
output_files->push_back(output_path); output_files->push_back(output_path);
...@@ -219,7 +217,7 @@ void NinjaActionTargetWriter::WriteOutputFilesForBuildLine( ...@@ -219,7 +217,7 @@ void NinjaActionTargetWriter::WriteOutputFilesForBuildLine(
void NinjaActionTargetWriter::WriteDepfile(const SourceFile& source) { void NinjaActionTargetWriter::WriteDepfile(const SourceFile& source) {
std::vector<std::string> result; std::vector<std::string> result;
GetDepfileTemplate().ApplyString(source.value(), &result); GetDepfileTemplate().Apply(source, &result);
path_output_.WriteFile(out_, OutputFile(result[0])); path_output_.WriteFile(out_, OutputFile(result[0]));
} }
...@@ -229,5 +227,5 @@ FileTemplate NinjaActionTargetWriter::GetDepfileTemplate() const { ...@@ -229,5 +227,5 @@ FileTemplate NinjaActionTargetWriter::GetDepfileTemplate() const {
RemovePrefix(target_->action_values().depfile().value(), RemovePrefix(target_->action_values().depfile().value(),
settings_->build_settings()->build_dir().value()); settings_->build_settings()->build_dir().value());
template_args.push_back(depfile_relative_to_build_dir); template_args.push_back(depfile_relative_to_build_dir);
return FileTemplate(template_args); return FileTemplate(settings_, template_args);
} }
...@@ -44,7 +44,7 @@ TEST(NinjaActionTargetWriter, WriteArgsSubstitutions) { ...@@ -44,7 +44,7 @@ TEST(NinjaActionTargetWriter, WriteArgsSubstitutions) {
args.push_back("-i"); args.push_back("-i");
args.push_back("{{source}}"); args.push_back("{{source}}");
args.push_back("--out=foo bar{{source_name_part}}.o"); 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); writer.WriteArgsSubstitutions(SourceFile("//foo/b ar.in"), args_template);
#if defined(OS_WIN) #if defined(OS_WIN)
......
...@@ -30,7 +30,7 @@ void NinjaCopyTargetWriter::Run() { ...@@ -30,7 +30,7 @@ void NinjaCopyTargetWriter::Run() {
// Make the output file from the template. // Make the output file from the template.
std::vector<std::string> template_result; 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); CHECK(template_result.size() == 1);
OutputFile output_file(template_result[0]); OutputFile output_file(template_result[0]);
......
...@@ -165,5 +165,5 @@ FileTemplate NinjaTargetWriter::GetOutputTemplate() const { ...@@ -165,5 +165,5 @@ FileTemplate NinjaTargetWriter::GetOutputTemplate() const {
RemovePrefix(outputs[i].value(), RemovePrefix(outputs[i].value(),
settings_->build_settings()->build_dir().value())); settings_->build_settings()->build_dir().value()));
} }
return FileTemplate(output_template_args); return FileTemplate(target_->settings(), output_template_args);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment