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