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 "base/atomicops.h"
6#include "base/bind.h"
7#include "base/command_line.h"
8#include "base/strings/string_number_conversions.h"
9#include "base/timer/elapsed_timer.h"
10#include "tools/gn/build_settings.h"
11#include "tools/gn/commands.h"
12#include "tools/gn/ninja_target_writer.h"
13#include "tools/gn/ninja_writer.h"
14#include "tools/gn/scheduler.h"
15#include "tools/gn/setup.h"
16#include "tools/gn/standard_out.h"
17#include "tools/gn/target.h"
18
19namespace commands {
20
21namespace {
22
23// Suppress output on success.
24const char kSwitchQuiet[] = "q";
25
26const char kSwitchCheck[] = "check";
27
28// Called on worker thread to write the ninja file.
29void BackgroundDoWrite(const Target* target) {
30  NinjaTargetWriter::RunAndWriteFile(target);
31  g_scheduler->DecrementWorkCount();
32}
33
34// Called on the main thread.
35void ItemResolvedCallback(base::subtle::Atomic32* write_counter,
36                          scoped_refptr<Builder> builder,
37                          const BuilderRecord* record) {
38  base::subtle::NoBarrier_AtomicIncrement(write_counter, 1);
39
40  const Item* item = record->item();
41  const Target* target = item->AsTarget();
42  if (target) {
43    g_scheduler->IncrementWorkCount();
44    g_scheduler->ScheduleWork(base::Bind(&BackgroundDoWrite, target));
45  }
46}
47
48}  // namespace
49
50const char kGen[] = "gen";
51const char kGen_HelpShort[] =
52    "gen: Generate ninja files.";
53const char kGen_Help[] =
54    "gn gen: Generate ninja files.\n"
55    "\n"
56    "  gn gen <output_directory>\n"
57    "\n"
58    "  Generates ninja files from the current tree and puts them in the given\n"
59    "  output directory.\n"
60    "\n"
61    "  The output directory can be a source-repo-absolute path name such as:\n"
62    "      //out/foo\n"
63    "  Or it can be a directory relative to the current directory such as:\n"
64    "      out/foo\n"
65    "\n"
66    "  See \"gn help\" for the common command-line switches.\n";
67
68int RunGen(const std::vector<std::string>& args) {
69  base::ElapsedTimer timer;
70
71  if (args.size() != 1) {
72    Err(Location(), "Need exactly one build directory to generate.",
73        "I expected something more like \"gn gen out/foo\"\n"
74        "You can also see \"gn help gen\".").PrintToStdout();
75    return 1;
76  }
77
78  // Deliberately leaked to avoid expensive process teardown.
79  Setup* setup = new Setup();
80  if (!setup->DoSetup(args[0], true))
81    return 1;
82
83  if (CommandLine::ForCurrentProcess()->HasSwitch(kSwitchCheck))
84    setup->set_check_public_headers(true);
85
86  // Cause the load to also generate the ninja files for each target. We wrap
87  // the writing to maintain a counter.
88  base::subtle::Atomic32 write_counter = 0;
89  setup->builder()->set_resolved_callback(
90      base::Bind(&ItemResolvedCallback, &write_counter,
91                 scoped_refptr<Builder>(setup->builder())));
92
93  // Do the actual load. This will also write out the target ninja files.
94  if (!setup->Run())
95    return 1;
96
97  // Write the root ninja files.
98  if (!NinjaWriter::RunAndWriteFiles(&setup->build_settings(),
99                                     setup->builder()))
100    return 1;
101
102  base::TimeDelta elapsed_time = timer.Elapsed();
103
104  if (!CommandLine::ForCurrentProcess()->HasSwitch(kSwitchQuiet)) {
105    OutputString("Done. ", DECORATION_GREEN);
106
107    std::string stats = "Wrote " +
108        base::IntToString(static_cast<int>(write_counter)) +
109        " targets from " +
110        base::IntToString(
111            setup->scheduler().input_file_manager()->GetInputFileCount()) +
112        " files in " +
113        base::IntToString(elapsed_time.InMilliseconds()) + "ms\n";
114    OutputString(stats);
115  }
116
117  return 0;
118}
119
120}  // namespace commands
121