• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 namespace commands {
19 
20 namespace {
21 
22 // Suppress output on success.
23 const char kSwitchQuiet[] = "q";
24 
25 const char kSwitchCheck[] = "check";
26 
BackgroundDoWrite(const Target * target,const Toolchain * toolchain,const std::vector<const Item * > & deps_for_visibility)27 void BackgroundDoWrite(const Target* target,
28                        const Toolchain* toolchain,
29                        const std::vector<const Item*>& deps_for_visibility) {
30   // Validate visibility.
31   Err err;
32   for (size_t i = 0; i < deps_for_visibility.size(); i++) {
33     if (!Visibility::CheckItemVisibility(target, deps_for_visibility[i],
34                                          &err)) {
35       g_scheduler->FailWithError(err);
36       break;  // Don't return early since we need DecrementWorkCount below.
37     }
38   }
39 
40   if (!err.has_error())
41     NinjaTargetWriter::RunAndWriteFile(target, toolchain);
42   g_scheduler->DecrementWorkCount();
43 }
44 
45 // Called on the main thread.
ItemResolvedCallback(base::subtle::Atomic32 * write_counter,scoped_refptr<Builder> builder,const BuilderRecord * record)46 void ItemResolvedCallback(base::subtle::Atomic32* write_counter,
47                           scoped_refptr<Builder> builder,
48                           const BuilderRecord* record) {
49   base::subtle::NoBarrier_AtomicIncrement(write_counter, 1);
50 
51   const Item* item = record->item();
52   const Target* target = item->AsTarget();
53   if (target) {
54     const Toolchain* toolchain =
55         builder->GetToolchain(target->settings()->toolchain_label());
56     DCHECK(toolchain);
57 
58     // Collect all dependencies.
59     std::vector<const Item*> deps;
60     for (BuilderRecord::BuilderRecordSet::const_iterator iter =
61              record->all_deps().begin();
62          iter != record->all_deps().end();
63          ++iter)
64       deps.push_back((*iter)->item());
65 
66     g_scheduler->IncrementWorkCount();
67     g_scheduler->ScheduleWork(
68         base::Bind(&BackgroundDoWrite, target, toolchain, deps));
69   }
70 }
71 
72 }  // namespace
73 
74 const char kGen[] = "gen";
75 const char kGen_HelpShort[] =
76     "gen: Generate ninja files.";
77 const char kGen_Help[] =
78     "gn gen: Generate ninja files.\n"
79     "\n"
80     "  gn gen <output_directory>\n"
81     "\n"
82     "  Generates ninja files from the current tree and puts them in the given\n"
83     "  output directory.\n"
84     "\n"
85     "  The output directory can be a source-repo-absolute path name such as:\n"
86     "      //out/foo\n"
87     "  Or it can be a directory relative to the current directory such as:\n"
88     "      out/foo\n"
89     "\n"
90     "  See \"gn help\" for the common command-line switches.\n";
91 
RunGen(const std::vector<std::string> & args)92 int RunGen(const std::vector<std::string>& args) {
93   base::ElapsedTimer timer;
94 
95   if (args.size() != 1) {
96     Err(Location(), "Need exactly one build directory to generate.",
97         "I expected something more like \"gn gen out/foo\"\n"
98         "You can also see \"gn help gen\".").PrintToStdout();
99     return 1;
100   }
101 
102   // Deliberately leaked to avoid expensive process teardown.
103   Setup* setup = new Setup();
104   if (!setup->DoSetup(args[0]))
105     return 1;
106 
107   if (CommandLine::ForCurrentProcess()->HasSwitch(kSwitchCheck))
108     setup->set_check_public_headers(true);
109 
110   // Cause the load to also generate the ninja files for each target. We wrap
111   // the writing to maintain a counter.
112   base::subtle::Atomic32 write_counter = 0;
113   setup->builder()->set_resolved_callback(
114       base::Bind(&ItemResolvedCallback, &write_counter,
115                  scoped_refptr<Builder>(setup->builder())));
116 
117   // Do the actual load. This will also write out the target ninja files.
118   if (!setup->Run())
119     return 1;
120 
121   // Write the root ninja files.
122   if (!NinjaWriter::RunAndWriteFiles(&setup->build_settings(),
123                                      setup->builder()))
124     return 1;
125 
126   base::TimeDelta elapsed_time = timer.Elapsed();
127 
128   if (!CommandLine::ForCurrentProcess()->HasSwitch(kSwitchQuiet)) {
129     OutputString("Done. ", DECORATION_GREEN);
130 
131     std::string stats = "Wrote " +
132         base::IntToString(static_cast<int>(write_counter)) +
133         " targets from " +
134         base::IntToString(
135             setup->scheduler().input_file_manager()->GetInputFileCount()) +
136         " files in " +
137         base::IntToString(elapsed_time.InMilliseconds()) + "ms\n";
138     OutputString(stats);
139   }
140 
141   return 0;
142 }
143 
144 }  // namespace commands
145