mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-24 06:16:30 +03:00
240 lines
9.1 KiB
C++
240 lines
9.1 KiB
C++
|
// 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_action_target_writer.h"
|
||
|
|
||
|
#include <stddef.h>
|
||
|
|
||
|
#include "base/strings/string_util.h"
|
||
|
#include "tools/gn/deps_iterator.h"
|
||
|
#include "tools/gn/err.h"
|
||
|
#include "tools/gn/pool.h"
|
||
|
#include "tools/gn/settings.h"
|
||
|
#include "tools/gn/string_utils.h"
|
||
|
#include "tools/gn/substitution_writer.h"
|
||
|
#include "tools/gn/target.h"
|
||
|
|
||
|
NinjaActionTargetWriter::NinjaActionTargetWriter(const Target* target,
|
||
|
std::ostream& out)
|
||
|
: NinjaTargetWriter(target, out),
|
||
|
path_output_no_escaping_(
|
||
|
target->settings()->build_settings()->build_dir(),
|
||
|
target->settings()->build_settings()->root_path_utf8(),
|
||
|
ESCAPE_NONE) {
|
||
|
}
|
||
|
|
||
|
NinjaActionTargetWriter::~NinjaActionTargetWriter() = default;
|
||
|
|
||
|
void NinjaActionTargetWriter::Run() {
|
||
|
std::string custom_rule_name = WriteRuleDefinition();
|
||
|
|
||
|
// Collect our deps to pass as "extra hard dependencies" for input deps. This
|
||
|
// will force all of the action's dependencies to be completed before the
|
||
|
// action is run. Usually, if an action has a dependency, it will be
|
||
|
// operating on the result of that previous step, so we need to be sure to
|
||
|
// serialize these.
|
||
|
std::vector<const Target*> extra_hard_deps;
|
||
|
for (const auto& pair : target_->GetDeps(Target::DEPS_LINKED))
|
||
|
extra_hard_deps.push_back(pair.ptr);
|
||
|
|
||
|
// For ACTIONs, the input deps appear only once in the generated ninja
|
||
|
// file, so WriteInputDepsStampAndGetDep() won't create a stamp file
|
||
|
// and the action will just depend on all the input deps directly.
|
||
|
size_t num_stamp_uses =
|
||
|
target_->output_type() == Target::ACTION ? 1u : target_->sources().size();
|
||
|
std::vector<OutputFile> input_deps =
|
||
|
WriteInputDepsStampAndGetDep(extra_hard_deps, num_stamp_uses);
|
||
|
out_ << std::endl;
|
||
|
|
||
|
// Collects all output files for writing below.
|
||
|
std::vector<OutputFile> output_files;
|
||
|
|
||
|
if (target_->output_type() == Target::ACTION_FOREACH) {
|
||
|
// Write separate build lines for each input source file.
|
||
|
WriteSourceRules(custom_rule_name, input_deps, &output_files);
|
||
|
} else {
|
||
|
DCHECK(target_->output_type() == Target::ACTION);
|
||
|
|
||
|
// Write a rule that invokes the script once with the outputs as outputs,
|
||
|
// and the data as inputs. It does not depend on the sources.
|
||
|
out_ << "build";
|
||
|
SubstitutionWriter::GetListAsOutputFiles(
|
||
|
settings_, target_->action_values().outputs(), &output_files);
|
||
|
path_output_.WriteFiles(out_, output_files);
|
||
|
|
||
|
out_ << ": " << custom_rule_name;
|
||
|
if (!input_deps.empty()) {
|
||
|
// As in WriteSourceRules, we want to force this target to rebuild any
|
||
|
// time any of its dependencies change.
|
||
|
out_ << " |";
|
||
|
path_output_.WriteFiles(out_, input_deps);
|
||
|
}
|
||
|
out_ << std::endl;
|
||
|
if (target_->action_values().has_depfile()) {
|
||
|
out_ << " depfile = ";
|
||
|
WriteDepfile(SourceFile());
|
||
|
out_ << std::endl;
|
||
|
}
|
||
|
if (target_->action_values().pool().ptr) {
|
||
|
out_ << " pool = ";
|
||
|
out_ << target_->action_values().pool().ptr->GetNinjaName(
|
||
|
settings_->default_toolchain_label());
|
||
|
out_ << std::endl;
|
||
|
}
|
||
|
}
|
||
|
out_ << std::endl;
|
||
|
|
||
|
// Write the stamp, which also depends on all data deps. These are needed at
|
||
|
// runtime and should be compiled when the action is, but don't need to be
|
||
|
// done before we run the action.
|
||
|
// TODO(thakis): If the action has just a single output, make things depend
|
||
|
// on that output directly without writing a stamp file.
|
||
|
std::vector<OutputFile> data_outs;
|
||
|
for (const auto& dep : target_->data_deps())
|
||
|
data_outs.push_back(dep.ptr->dependency_output_file());
|
||
|
WriteStampForTarget(output_files, data_outs);
|
||
|
}
|
||
|
|
||
|
std::string NinjaActionTargetWriter::WriteRuleDefinition() {
|
||
|
// Make a unique name for this rule.
|
||
|
//
|
||
|
// Use a unique name for the response file when there are multiple build
|
||
|
// steps so that they don't stomp on each other. When there are no sources,
|
||
|
// there will be only one invocation so we can use a simple name.
|
||
|
std::string target_label = target_->label().GetUserVisibleName(true);
|
||
|
std::string custom_rule_name(target_label);
|
||
|
base::ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name);
|
||
|
custom_rule_name.append("_rule");
|
||
|
|
||
|
const SubstitutionList& args = target_->action_values().args();
|
||
|
EscapeOptions args_escape_options;
|
||
|
args_escape_options.mode = ESCAPE_NINJA_COMMAND;
|
||
|
|
||
|
out_ << "rule " << custom_rule_name << std::endl;
|
||
|
|
||
|
if (target_->action_values().uses_rsp_file()) {
|
||
|
// Needs a response file. The unique_name part is for action_foreach so
|
||
|
// each invocation of the rule gets a different response file. This isn't
|
||
|
// strictly necessary for regular one-shot actions, but it's easier to
|
||
|
// just always define unique_name.
|
||
|
std::string rspfile = custom_rule_name;
|
||
|
if (!target_->sources().empty())
|
||
|
rspfile += ".$unique_name";
|
||
|
rspfile += ".rsp";
|
||
|
out_ << " rspfile = " << rspfile << std::endl;
|
||
|
|
||
|
// Response file contents.
|
||
|
out_ << " rspfile_content =";
|
||
|
for (const auto& arg :
|
||
|
target_->action_values().rsp_file_contents().list()) {
|
||
|
out_ << " ";
|
||
|
SubstitutionWriter::WriteWithNinjaVariables(
|
||
|
arg, args_escape_options, out_);
|
||
|
}
|
||
|
out_ << std::endl;
|
||
|
}
|
||
|
|
||
|
out_ << " command = ";
|
||
|
path_output_.WriteFile(out_, settings_->build_settings()->python_path());
|
||
|
out_ << " ";
|
||
|
path_output_.WriteFile(out_, target_->action_values().script());
|
||
|
for (const auto& arg : args.list()) {
|
||
|
out_ << " ";
|
||
|
SubstitutionWriter::WriteWithNinjaVariables(
|
||
|
arg, args_escape_options, out_);
|
||
|
}
|
||
|
out_ << std::endl;
|
||
|
out_ << " description = ACTION " << target_label << std::endl;
|
||
|
out_ << " restat = 1" << std::endl;
|
||
|
const Tool* tool = target_->toolchain()->GetTool(Toolchain::TYPE_ACTION);
|
||
|
if (tool && tool->pool().ptr) {
|
||
|
out_ << " pool = ";
|
||
|
out_ << tool->pool().ptr->GetNinjaName(
|
||
|
settings_->default_toolchain_label());
|
||
|
out_ << std::endl;
|
||
|
}
|
||
|
|
||
|
return custom_rule_name;
|
||
|
}
|
||
|
|
||
|
void NinjaActionTargetWriter::WriteSourceRules(
|
||
|
const std::string& custom_rule_name,
|
||
|
const std::vector<OutputFile>& input_deps,
|
||
|
std::vector<OutputFile>* output_files) {
|
||
|
EscapeOptions args_escape_options;
|
||
|
args_escape_options.mode = ESCAPE_NINJA_COMMAND;
|
||
|
// We're writing the substitution values, these should not be quoted since
|
||
|
// they will get pasted into the real command line.
|
||
|
args_escape_options.inhibit_quoting = true;
|
||
|
|
||
|
const Target::FileList& sources = target_->sources();
|
||
|
for (size_t i = 0; i < sources.size(); i++) {
|
||
|
out_ << "build";
|
||
|
WriteOutputFilesForBuildLine(sources[i], output_files);
|
||
|
|
||
|
out_ << ": " << custom_rule_name << " ";
|
||
|
path_output_.WriteFile(out_, sources[i]);
|
||
|
if (!input_deps.empty()) {
|
||
|
// Using "|" for the dependencies forces all implicit dependencies to be
|
||
|
// fully up to date before running the action, and will re-run this
|
||
|
// action if any input dependencies change. This is important because
|
||
|
// this action may consume the outputs of previous steps.
|
||
|
out_ << " |";
|
||
|
path_output_.WriteFiles(out_, input_deps);
|
||
|
}
|
||
|
out_ << std::endl;
|
||
|
|
||
|
// Response files require a unique name be defined.
|
||
|
if (target_->action_values().uses_rsp_file())
|
||
|
out_ << " unique_name = " << i << std::endl;
|
||
|
|
||
|
// The required types is the union of the args and response file. This
|
||
|
// might theoretically duplicate a definition if the same substitution is
|
||
|
// used in both the args and the response file. However, this should be
|
||
|
// very unusual (normally the substitutions will go in one place or the
|
||
|
// other) and the redundant assignment won't bother Ninja.
|
||
|
SubstitutionWriter::WriteNinjaVariablesForSource(
|
||
|
target_, settings_, sources[i],
|
||
|
target_->action_values().args().required_types(),
|
||
|
args_escape_options, out_);
|
||
|
SubstitutionWriter::WriteNinjaVariablesForSource(
|
||
|
target_, settings_, sources[i],
|
||
|
target_->action_values().rsp_file_contents().required_types(),
|
||
|
args_escape_options, out_);
|
||
|
|
||
|
if (target_->action_values().has_depfile()) {
|
||
|
out_ << " depfile = ";
|
||
|
WriteDepfile(sources[i]);
|
||
|
out_ << std::endl;
|
||
|
}
|
||
|
if (target_->action_values().pool().ptr) {
|
||
|
out_ << " pool = ";
|
||
|
out_ << target_->action_values().pool().ptr->GetNinjaName(
|
||
|
settings_->default_toolchain_label());
|
||
|
out_ << std::endl;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void NinjaActionTargetWriter::WriteOutputFilesForBuildLine(
|
||
|
const SourceFile& source,
|
||
|
std::vector<OutputFile>* output_files) {
|
||
|
size_t first_output_index = output_files->size();
|
||
|
|
||
|
SubstitutionWriter::ApplyListToSourceAsOutputFile(
|
||
|
target_, settings_, target_->action_values().outputs(), source,
|
||
|
output_files);
|
||
|
|
||
|
for (size_t i = first_output_index; i < output_files->size(); i++) {
|
||
|
out_ << " ";
|
||
|
path_output_.WriteFile(out_, (*output_files)[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void NinjaActionTargetWriter::WriteDepfile(const SourceFile& source) {
|
||
|
path_output_.WriteFile(out_,
|
||
|
SubstitutionWriter::ApplyPatternToSourceAsOutputFile(
|
||
|
target_, settings_, target_->action_values().depfile(), source));
|
||
|
}
|