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/target_generator.h"
6
7#include "tools/gn/binary_target_generator.h"
8#include "tools/gn/build_settings.h"
9#include "tools/gn/config.h"
10#include "tools/gn/copy_target_generator.h"
11#include "tools/gn/err.h"
12#include "tools/gn/filesystem_utils.h"
13#include "tools/gn/functions.h"
14#include "tools/gn/group_target_generator.h"
15#include "tools/gn/parse_tree.h"
16#include "tools/gn/scheduler.h"
17#include "tools/gn/scope.h"
18#include "tools/gn/script_target_generator.h"
19#include "tools/gn/token.h"
20#include "tools/gn/value.h"
21#include "tools/gn/value_extractors.h"
22#include "tools/gn/variables.h"
23
24TargetGenerator::TargetGenerator(Target* target,
25                                 Scope* scope,
26                                 const FunctionCallNode* function_call,
27                                 Err* err)
28    : target_(target),
29      scope_(scope),
30      function_call_(function_call),
31      err_(err) {
32}
33
34TargetGenerator::~TargetGenerator() {
35}
36
37void TargetGenerator::Run() {
38  // All target types use these.
39  FillDependentConfigs();
40  FillData();
41  FillDependencies();
42  FillGypFile();
43
44  // Do type-specific generation.
45  DoRun();
46}
47
48// static
49void TargetGenerator::GenerateTarget(Scope* scope,
50                                     const FunctionCallNode* function_call,
51                                     const std::vector<Value>& args,
52                                     const std::string& output_type,
53                                     Err* err) {
54  // Name is the argument to the function.
55  if (args.size() != 1u || args[0].type() != Value::STRING) {
56    *err = Err(function_call,
57        "Target generator requires one string argument.",
58        "Otherwise I'm not sure what to call this target.");
59    return;
60  }
61
62  // The location of the target is the directory name with no slash at the end.
63  // FIXME(brettw) validate name.
64  const Label& toolchain_label = ToolchainLabelForScope(scope);
65  Label label(scope->GetSourceDir(), args[0].string_value(),
66              toolchain_label.dir(), toolchain_label.name());
67
68  if (g_scheduler->verbose_logging())
69    g_scheduler->Log("Defining target", label.GetUserVisibleName(true));
70
71  scoped_ptr<Target> target(new Target(scope->settings(), label));
72  target->set_defined_from(function_call);
73
74  // Create and call out to the proper generator.
75  if (output_type == functions::kCopy) {
76    CopyTargetGenerator generator(target.get(), scope, function_call, err);
77    generator.Run();
78  } else if (output_type == functions::kCustom) {
79    ScriptTargetGenerator generator(target.get(), scope, function_call, err);
80    generator.Run();
81  } else if (output_type == functions::kExecutable) {
82    BinaryTargetGenerator generator(target.get(), scope, function_call,
83                                    Target::EXECUTABLE, err);
84    generator.Run();
85  } else if (output_type == functions::kGroup) {
86    GroupTargetGenerator generator(target.get(), scope, function_call, err);
87    generator.Run();
88  } else if (output_type == functions::kSharedLibrary) {
89    BinaryTargetGenerator generator(target.get(), scope, function_call,
90                                    Target::SHARED_LIBRARY, err);
91    generator.Run();
92  } else if (output_type == functions::kSourceSet) {
93    BinaryTargetGenerator generator(target.get(), scope, function_call,
94                                    Target::SOURCE_SET, err);
95    generator.Run();
96  } else if (output_type == functions::kStaticLibrary) {
97    BinaryTargetGenerator generator(target.get(), scope, function_call,
98                                    Target::STATIC_LIBRARY, err);
99    generator.Run();
100  } else {
101    *err = Err(function_call, "Not a known output type",
102               "I am very confused.");
103  }
104
105  if (!err->has_error())
106    scope->settings()->build_settings()->ItemDefined(target.PassAs<Item>());
107}
108
109const BuildSettings* TargetGenerator::GetBuildSettings() const {
110  return scope_->settings()->build_settings();
111}
112
113void TargetGenerator::FillSources() {
114  const Value* value = scope_->GetValue(variables::kSources, true);
115  if (!value)
116    return;
117
118  Target::FileList dest_sources;
119  if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
120                                  scope_->GetSourceDir(), &dest_sources, err_))
121    return;
122  target_->sources().swap(dest_sources);
123}
124
125void TargetGenerator::FillSourcePrereqs() {
126  const Value* value = scope_->GetValue(variables::kSourcePrereqs, true);
127  if (!value)
128    return;
129
130  Target::FileList dest_reqs;
131  if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
132                                  scope_->GetSourceDir(), &dest_reqs, err_))
133    return;
134  target_->source_prereqs().swap(dest_reqs);
135}
136
137void TargetGenerator::FillConfigs() {
138  FillGenericConfigs(variables::kConfigs, &target_->configs());
139}
140
141void TargetGenerator::FillDependentConfigs() {
142  FillGenericConfigs(variables::kAllDependentConfigs,
143                     &target_->all_dependent_configs());
144  FillGenericConfigs(variables::kDirectDependentConfigs,
145                     &target_->direct_dependent_configs());
146}
147
148void TargetGenerator::FillData() {
149  const Value* value = scope_->GetValue(variables::kData, true);
150  if (!value)
151    return;
152
153  Target::FileList dest_data;
154  if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
155                                  scope_->GetSourceDir(), &dest_data, err_))
156    return;
157  target_->data().swap(dest_data);
158}
159
160void TargetGenerator::FillDependencies() {
161  FillGenericDeps(variables::kDeps, &target_->deps());
162  FillGenericDeps(variables::kDatadeps, &target_->datadeps());
163
164  // This is a list of dependent targets to have their configs fowarded, so
165  // it goes here rather than in FillConfigs.
166  FillForwardDependentConfigs();
167
168  FillHardDep();
169}
170
171void TargetGenerator::FillGypFile() {
172  const Value* gyp_file_value = scope_->GetValue(variables::kGypFile, true);
173  if (!gyp_file_value)
174    return;
175  if (!gyp_file_value->VerifyTypeIs(Value::STRING, err_))
176    return;
177
178  target_->set_gyp_file(scope_->GetSourceDir().ResolveRelativeFile(
179      gyp_file_value->string_value()));
180}
181
182void TargetGenerator::FillHardDep() {
183  const Value* hard_dep_value = scope_->GetValue(variables::kHardDep, true);
184  if (!hard_dep_value)
185    return;
186  if (!hard_dep_value->VerifyTypeIs(Value::BOOLEAN, err_))
187    return;
188  target_->set_hard_dep(hard_dep_value->boolean_value());
189}
190
191void TargetGenerator::FillExternal() {
192  const Value* value = scope_->GetValue(variables::kExternal, true);
193  if (!value)
194    return;
195  if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
196    return;
197  target_->set_external(value->boolean_value());
198}
199
200void TargetGenerator::FillOutputs() {
201  const Value* value = scope_->GetValue(variables::kOutputs, true);
202  if (!value)
203    return;
204
205  Target::FileList outputs;
206  if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
207                                  scope_->GetSourceDir(), &outputs, err_))
208    return;
209
210  // Validate that outputs are in the output dir.
211  CHECK(outputs.size() == value->list_value().size());
212  for (size_t i = 0; i < outputs.size(); i++) {
213    if (!EnsureStringIsInOutputDir(
214            GetBuildSettings()->build_dir(),
215            outputs[i].value(), value->list_value()[i], err_))
216      return;
217  }
218  target_->script_values().outputs().swap(outputs);
219}
220
221void TargetGenerator::FillGenericConfigs(const char* var_name,
222                                         LabelConfigVector* dest) {
223  const Value* value = scope_->GetValue(var_name, true);
224  if (value) {
225    ExtractListOfLabels(*value, scope_->GetSourceDir(),
226                        ToolchainLabelForScope(scope_), dest, err_);
227  }
228}
229
230void TargetGenerator::FillGenericDeps(const char* var_name,
231                                      LabelTargetVector* dest) {
232  const Value* value = scope_->GetValue(var_name, true);
233  if (value) {
234    ExtractListOfLabels(*value, scope_->GetSourceDir(),
235                        ToolchainLabelForScope(scope_), dest, err_);
236  }
237}
238
239void TargetGenerator::FillForwardDependentConfigs() {
240  const Value* value = scope_->GetValue(
241      variables::kForwardDependentConfigsFrom, true);
242  if (value) {
243    ExtractListOfLabels(*value, scope_->GetSourceDir(),
244                        ToolchainLabelForScope(scope_),
245                        &target_->forward_dependent_configs(), err_);
246  }
247}
248