8840f16c427a18fb0edf68a25cb785d5443d13b0
[platform/framework/web/crosswalk.git] / src / tools / gn / action_target_generator.cc
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "tools/gn/action_target_generator.h"
6
7 #include "tools/gn/build_settings.h"
8 #include "tools/gn/err.h"
9 #include "tools/gn/filesystem_utils.h"
10 #include "tools/gn/parse_tree.h"
11 #include "tools/gn/scope.h"
12 #include "tools/gn/value.h"
13 #include "tools/gn/value_extractors.h"
14 #include "tools/gn/variables.h"
15
16 namespace {
17
18 // Returns true if the list of files looks like it might have a {{ }} pattern
19 // in it. Used for error checking.
20 bool FileListHasPattern(const Target::FileList& files) {
21   for (size_t i = 0; i < files.size(); i++) {
22     if (files[i].value().find("{{") != std::string::npos &&
23         files[i].value().find("}}") != std::string::npos)
24       return true;
25   }
26   return false;
27 }
28
29 }  // namespace
30
31 ActionTargetGenerator::ActionTargetGenerator(
32     Target* target,
33     Scope* scope,
34     const FunctionCallNode* function_call,
35     Target::OutputType type,
36     Err* err)
37     : TargetGenerator(target, scope, function_call, err),
38       output_type_(type) {
39 }
40
41 ActionTargetGenerator::~ActionTargetGenerator() {
42 }
43
44 void ActionTargetGenerator::DoRun() {
45   target_->set_output_type(output_type_);
46
47   FillSources();
48   if (err_->has_error())
49     return;
50   if (output_type_ == Target::ACTION_FOREACH && target_->sources().empty()) {
51     // Foreach rules must always have some sources to have an effect.
52     *err_ = Err(function_call_, "action_foreach target has no sources.",
53         "If you don't specify any sources, there is nothing to run your\n"
54         "script over.");
55     return;
56   }
57
58   FillInputs();
59   if (err_->has_error())
60     return;
61
62   FillScript();
63   if (err_->has_error())
64     return;
65
66   FillScriptArgs();
67   if (err_->has_error())
68     return;
69
70   FillOutputs();
71   if (err_->has_error())
72     return;
73
74   FillDepfile();
75   if (err_->has_error())
76     return;
77
78   CheckOutputs();
79   if (err_->has_error())
80     return;
81
82   // Action outputs don't depend on the current toolchain so we can skip adding
83   // that dependency.
84 }
85
86 void ActionTargetGenerator::FillScript() {
87   // If this gets called, the target type requires a script, so error out
88   // if it doesn't have one.
89   const Value* value = scope_->GetValue(variables::kScript, true);
90   if (!value) {
91     *err_ = Err(function_call_, "This target type requires a \"script\".");
92     return;
93   }
94   if (!value->VerifyTypeIs(Value::STRING, err_))
95     return;
96
97   SourceFile script_file =
98       scope_->GetSourceDir().ResolveRelativeFile(value->string_value());
99   if (script_file.value().empty()) {
100     *err_ = Err(*value, "script name is empty");
101     return;
102   }
103   target_->action_values().set_script(script_file);
104 }
105
106 void ActionTargetGenerator::FillScriptArgs() {
107   const Value* value = scope_->GetValue(variables::kArgs, true);
108   if (!value)
109     return;
110
111   std::vector<std::string> args;
112   if (!ExtractListOfStringValues(*value, &args, err_))
113     return;
114   target_->action_values().swap_in_args(&args);
115 }
116
117 void ActionTargetGenerator::FillDepfile() {
118   const Value* value = scope_->GetValue(variables::kDepfile, true);
119   if (!value)
120     return;
121   target_->action_values().set_depfile(
122       scope_->settings()->build_settings()->build_dir().ResolveRelativeFile(
123           value->string_value()));
124 }
125
126 void ActionTargetGenerator::CheckOutputs() {
127   const Target::FileList& outputs = target_->action_values().outputs();
128   if (outputs.empty()) {
129     *err_ = Err(function_call_, "Action has no outputs.",
130         "If you have no outputs, the build system can not tell when your\n"
131         "script needs to be run.");
132     return;
133   }
134
135   if (output_type_ == Target::ACTION) {
136     // Make sure the outputs for an action have no patterns in them.
137     if (FileListHasPattern(outputs)) {
138       *err_ = Err(function_call_, "Action has patterns in the output.",
139           "An action target should have the outputs completely specified. If\n"
140           "you want to provide a mapping from source to output, use an\n"
141           "\"action_foreach\" target.");
142       return;
143     }
144   } else if (output_type_ == Target::ACTION_FOREACH) {
145     // A foreach target should always have a pattern in the outputs.
146     if (!FileListHasPattern(outputs)) {
147       *err_ = Err(function_call_,
148           "action_foreach should have a pattern in the output.",
149           "An action_foreach target should have a source expansion pattern in\n"
150           "it to map source file to unique output file name. Otherwise, the\n"
151           "build system can't determine when your script needs to be run.");
152       return;
153     }
154   }
155 }