// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "tools/gn/ninja_copy_target_writer.h" #include "base/strings/string_util.h" #include "tools/gn/string_utils.h" #include "tools/gn/substitution_list.h" #include "tools/gn/substitution_writer.h" NinjaCopyTargetWriter::NinjaCopyTargetWriter(const Target* target, const Toolchain* toolchain, std::ostream& out) : NinjaTargetWriter(target, toolchain, out) { } NinjaCopyTargetWriter::~NinjaCopyTargetWriter() { } void NinjaCopyTargetWriter::Run() { CHECK(target_->action_values().outputs().list().size() == 1); const SubstitutionList& output_subst_list = target_->action_values().outputs(); CHECK_EQ(1u, output_subst_list.list().size()) << "Should have one entry exactly."; const SubstitutionPattern& output_subst = output_subst_list.list()[0]; std::vector<OutputFile> output_files; std::string rule_prefix = helper_.GetRulePrefix(target_->settings()); // Note that we don't write implicit deps for copy steps. "copy" only // depends on the output files themselves, rather than having includes // (the possibility of generated #includes is the main reason for implicit // dependencies). // // It would seem that specifying implicit dependencies on the deps of the // copy command would still be harmeless. But Chrome implements copy tools // as hard links (much faster) which don't change the timestamp. If the // ninja rule looks like this: // output: copy input | foo.stamp // The copy will not make a new timestamp on the output file, but the // foo.stamp file generated from a previous step will have a new timestamp. // The copy rule will therefore look out-of-date to Ninja and the rule will // get rebuilt. // // If this copy is copying a generated file, not listing the implicit // dependency will be fine as long as the input to the copy is properly // listed as the output from the step that generated it. // // Moreover, doing this assumes that the copy step is always a simple // locally run command, so there is no need for a toolchain dependency. for (size_t i = 0; i < target_->sources().size(); i++) { const SourceFile& input_file = target_->sources()[i]; OutputFile output_file = SubstitutionWriter::ApplyPatternToSourceAsOutputFile( target_->settings(), output_subst, input_file); output_files.push_back(output_file); out_ << "build "; path_output_.WriteFile(out_, output_file); out_ << ": " << rule_prefix << "copy "; path_output_.WriteFile(out_, input_file); out_ << std::endl; } // Write out the rule for the target to copy all of them. out_ << std::endl << "build "; path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_)); out_ << ": " << rule_prefix << "stamp"; for (size_t i = 0; i < output_files.size(); i++) { out_ << " "; path_output_.WriteFile(out_, output_files[i]); } out_ << std::endl; }