Home | History | Annotate | Download | only in gn
      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/ninja_build_writer.h"
      6 
      7 #include <fstream>
      8 
      9 #include "base/command_line.h"
     10 #include "base/file_util.h"
     11 #include "base/process/process_handle.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "build/build_config.h"
     14 #include "tools/gn/build_settings.h"
     15 #include "tools/gn/escape.h"
     16 #include "tools/gn/filesystem_utils.h"
     17 #include "tools/gn/input_file_manager.h"
     18 #include "tools/gn/scheduler.h"
     19 #include "tools/gn/target.h"
     20 
     21 #if defined(OS_WIN)
     22 #include <windows.h>
     23 #endif
     24 
     25 namespace {
     26 
     27 std::string GetSelfInvocationCommand(const BuildSettings* build_settings) {
     28 #if defined(OS_WIN)
     29   wchar_t module[MAX_PATH];
     30   GetModuleFileName(NULL, module, MAX_PATH);
     31   //result = "\"" + WideToUTF8(module) + "\"";
     32   base::FilePath executable(module);
     33 #elif defined(OS_MACOSX)
     34   // FIXME(brettw) write this on Mac!
     35   base::FilePath executable("../Debug/gn");
     36 #else
     37   base::FilePath executable =
     38       base::GetProcessExecutablePath(base::GetCurrentProcessHandle());
     39 #endif
     40 
     41 /*
     42   // Append the root path.
     43   CommandLine* cmdline = CommandLine::ForCurrentProcess();
     44   result += " --root=\"" + FilePathToUTF8(settings->root_path()) + "\"";
     45 */
     46 
     47   CommandLine cmdline(executable);
     48   cmdline.AppendSwitchPath("--root", build_settings->root_path());
     49 
     50   // TODO(brettw) append other parameters.
     51 
     52 #if defined(OS_WIN)
     53   return WideToUTF8(cmdline.GetCommandLineString());
     54 #else
     55   return cmdline.GetCommandLineString();
     56 #endif
     57 }
     58 
     59 }  // namespace
     60 
     61 NinjaBuildWriter::NinjaBuildWriter(
     62     const BuildSettings* build_settings,
     63     const std::vector<const Settings*>& all_settings,
     64     const std::vector<const Target*>& default_toolchain_targets,
     65     std::ostream& out)
     66     : build_settings_(build_settings),
     67       all_settings_(all_settings),
     68       default_toolchain_targets_(default_toolchain_targets),
     69       out_(out),
     70       path_output_(build_settings->build_dir(), ESCAPE_NINJA, true),
     71       helper_(build_settings) {
     72 }
     73 
     74 NinjaBuildWriter::~NinjaBuildWriter() {
     75 }
     76 
     77 void NinjaBuildWriter::Run() {
     78   WriteNinjaRules();
     79   WriteSubninjas();
     80   WritePhonyAndAllRules();
     81 }
     82 
     83 // static
     84 bool NinjaBuildWriter::RunAndWriteFile(
     85     const BuildSettings* build_settings,
     86     const std::vector<const Settings*>& all_settings,
     87     const std::vector<const Target*>& default_toolchain_targets) {
     88   base::FilePath ninja_file(build_settings->GetFullPath(
     89       SourceFile(build_settings->build_dir().value() + "build.ninja")));
     90   file_util::CreateDirectory(ninja_file.DirName());
     91 
     92   std::ofstream file;
     93   file.open(FilePathToUTF8(ninja_file).c_str(),
     94             std::ios_base::out | std::ios_base::binary);
     95   if (file.fail())
     96     return false;
     97 
     98   NinjaBuildWriter gen(build_settings, all_settings,
     99                        default_toolchain_targets, file);
    100   gen.Run();
    101   return true;
    102 }
    103 
    104 void NinjaBuildWriter::WriteNinjaRules() {
    105   out_ << "rule gn\n";
    106   out_ << "  command = " << GetSelfInvocationCommand(build_settings_) << "\n";
    107   out_ << "  description = GN the world\n\n";
    108 
    109   out_ << "build build.ninja: gn";
    110 
    111   // Input build files.
    112   std::vector<base::FilePath> input_files;
    113   g_scheduler->input_file_manager()->GetAllPhysicalInputFileNames(&input_files);
    114   EscapeOptions ninja_options;
    115   ninja_options.mode = ESCAPE_NINJA;
    116   for (size_t i = 0; i < input_files.size(); i++)
    117     out_ << " " << EscapeString(FilePathToUTF8(input_files[i]), ninja_options);
    118 
    119   // Other files read by the build.
    120   std::vector<SourceFile> other_files = g_scheduler->GetGenDependencies();
    121   for (size_t i = 0; i < other_files.size(); i++) {
    122     out_ << " ";
    123     path_output_.WriteFile(out_, other_files[i]);
    124   }
    125 
    126   out_ << std::endl << std::endl;
    127 }
    128 
    129 void NinjaBuildWriter::WriteSubninjas() {
    130   for (size_t i = 0; i < all_settings_.size(); i++) {
    131     out_ << "subninja ";
    132     path_output_.WriteFile(out_,
    133                            helper_.GetNinjaFileForToolchain(all_settings_[i]));
    134     out_ << std::endl;
    135   }
    136   out_ << std::endl;
    137 }
    138 
    139 void NinjaBuildWriter::WritePhonyAndAllRules() {
    140   std::string all_rules;
    141 
    142   // Write phony rules for the default toolchain (don't do other toolchains or
    143   // we'll get naming conflicts).
    144   for (size_t i = 0; i < default_toolchain_targets_.size(); i++) {
    145     const Target* target = default_toolchain_targets_[i];
    146     if (target->output_type() == Target::NONE)
    147       continue;  // Nothing to generate.
    148 
    149     OutputFile target_file = helper_.GetTargetOutputFile(target);
    150     if (target_file.value() != target->label().name()) {
    151       out_ << "build " << target->label().name() << ": phony ";
    152       path_output_.WriteFile(out_, target_file);
    153       out_ << std::endl;
    154     }
    155 
    156     if (!all_rules.empty())
    157       all_rules.append(" $\n    ");
    158     all_rules.append(target_file.value());
    159   }
    160 
    161   if (!all_rules.empty()) {
    162     out_ << "\nbuild all: phony " << all_rules << std::endl;
    163     out_ << "default all" << std::endl;
    164   }
    165 }
    166 
    167