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_copy_target_writer.h" 6 7#include "base/strings/string_util.h" 8#include "tools/gn/ninja_utils.h" 9#include "tools/gn/output_file.h" 10#include "tools/gn/scheduler.h" 11#include "tools/gn/string_utils.h" 12#include "tools/gn/substitution_list.h" 13#include "tools/gn/substitution_writer.h" 14#include "tools/gn/target.h" 15#include "tools/gn/toolchain.h" 16 17NinjaCopyTargetWriter::NinjaCopyTargetWriter(const Target* target, 18 std::ostream& out) 19 : NinjaTargetWriter(target, out) { 20} 21 22NinjaCopyTargetWriter::~NinjaCopyTargetWriter() { 23} 24 25void NinjaCopyTargetWriter::Run() { 26 const Tool* copy_tool = target_->toolchain()->GetTool(Toolchain::TYPE_COPY); 27 if (!copy_tool) { 28 g_scheduler->FailWithError(Err(NULL, 29 "Copy tool not defined", 30 "The toolchain " + 31 target_->toolchain()->label().GetUserVisibleName(false) + 32 "\n used by target " + target_->label().GetUserVisibleName(false) + 33 "\n doesn't define a \"copy\" tool.")); 34 return; 35 } 36 37 const Tool* stamp_tool = target_->toolchain()->GetTool(Toolchain::TYPE_STAMP); 38 if (!stamp_tool) { 39 g_scheduler->FailWithError(Err(NULL, 40 "Copy tool not defined", 41 "The toolchain " + 42 target_->toolchain()->label().GetUserVisibleName(false) + 43 "\n used by target " + target_->label().GetUserVisibleName(false) + 44 "\n doesn't define a \"stamp\" tool.")); 45 return; 46 } 47 48 // Figure out the substitutions used by the copy and stamp tools. 49 SubstitutionBits required_bits = copy_tool->substitution_bits(); 50 required_bits.MergeFrom(stamp_tool->substitution_bits()); 51 52 // General target-related substitutions needed by both tools. 53 WriteSharedVars(required_bits); 54 55 std::vector<OutputFile> output_files; 56 WriteCopyRules(&output_files); 57 out_ << std::endl; 58 WriteStampForTarget(output_files, std::vector<OutputFile>()); 59} 60 61void NinjaCopyTargetWriter::WriteCopyRules( 62 std::vector<OutputFile>* output_files) { 63 CHECK(target_->action_values().outputs().list().size() == 1); 64 const SubstitutionList& output_subst_list = 65 target_->action_values().outputs(); 66 CHECK_EQ(1u, output_subst_list.list().size()) 67 << "Should have one entry exactly."; 68 const SubstitutionPattern& output_subst = output_subst_list.list()[0]; 69 70 std::string tool_name = 71 GetNinjaRulePrefixForToolchain(settings_) + 72 Toolchain::ToolTypeToName(Toolchain::TYPE_COPY); 73 74 // Note that we don't write implicit deps for copy steps. "copy" only 75 // depends on the output files themselves, rather than having includes 76 // (the possibility of generated #includes is the main reason for implicit 77 // dependencies). 78 // 79 // It would seem that specifying implicit dependencies on the deps of the 80 // copy command would still be harmeless. But Chrome implements copy tools 81 // as hard links (much faster) which don't change the timestamp. If the 82 // ninja rule looks like this: 83 // output: copy input | foo.stamp 84 // The copy will not make a new timestamp on the output file, but the 85 // foo.stamp file generated from a previous step will have a new timestamp. 86 // The copy rule will therefore look out-of-date to Ninja and the rule will 87 // get rebuilt. 88 // 89 // If this copy is copying a generated file, not listing the implicit 90 // dependency will be fine as long as the input to the copy is properly 91 // listed as the output from the step that generated it. 92 // 93 // Moreover, doing this assumes that the copy step is always a simple 94 // locally run command, so there is no need for a toolchain dependency. 95 for (size_t i = 0; i < target_->sources().size(); i++) { 96 const SourceFile& input_file = target_->sources()[i]; 97 98 OutputFile output_file = 99 SubstitutionWriter::ApplyPatternToSourceAsOutputFile( 100 target_->settings(), output_subst, input_file); 101 output_files->push_back(output_file); 102 103 out_ << "build "; 104 path_output_.WriteFile(out_, output_file); 105 out_ << ": " << tool_name << " "; 106 path_output_.WriteFile(out_, input_file); 107 out_ << std::endl; 108 } 109} 110