mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-24 14:26:09 +03:00
333 lines
12 KiB
C++
333 lines
12 KiB
C++
|
// Copyright 2016 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_create_bundle_target_writer.h"
|
||
|
|
||
|
#include "base/macros.h"
|
||
|
#include "base/strings/string_util.h"
|
||
|
#include "tools/gn/filesystem_utils.h"
|
||
|
#include "tools/gn/ninja_utils.h"
|
||
|
#include "tools/gn/output_file.h"
|
||
|
#include "tools/gn/scheduler.h"
|
||
|
#include "tools/gn/substitution_writer.h"
|
||
|
#include "tools/gn/target.h"
|
||
|
#include "tools/gn/toolchain.h"
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
void FailWithMissingToolError(Toolchain::ToolType tool, const Target* target) {
|
||
|
const std::string& tool_name = Toolchain::ToolTypeToName(tool);
|
||
|
g_scheduler->FailWithError(Err(
|
||
|
nullptr, tool_name + " tool not defined",
|
||
|
"The toolchain " +
|
||
|
target->toolchain()->label().GetUserVisibleName(false) + "\n"
|
||
|
"used by target " + target->label().GetUserVisibleName(false) + "\n"
|
||
|
"doesn't define a \"" + tool_name + "\" tool."));
|
||
|
}
|
||
|
|
||
|
bool EnsureAllToolsAvailable(const Target* target) {
|
||
|
const Toolchain::ToolType kRequiredTools[] = {
|
||
|
Toolchain::TYPE_COPY_BUNDLE_DATA, Toolchain::TYPE_COMPILE_XCASSETS,
|
||
|
Toolchain::TYPE_STAMP,
|
||
|
};
|
||
|
|
||
|
for (size_t i = 0; i < arraysize(kRequiredTools); ++i) {
|
||
|
if (!target->toolchain()->GetTool(kRequiredTools[i])) {
|
||
|
FailWithMissingToolError(kRequiredTools[i], target);
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
NinjaCreateBundleTargetWriter::NinjaCreateBundleTargetWriter(
|
||
|
const Target* target,
|
||
|
std::ostream& out)
|
||
|
: NinjaTargetWriter(target, out) {}
|
||
|
|
||
|
NinjaCreateBundleTargetWriter::~NinjaCreateBundleTargetWriter() = default;
|
||
|
|
||
|
void NinjaCreateBundleTargetWriter::Run() {
|
||
|
if (!EnsureAllToolsAvailable(target_))
|
||
|
return;
|
||
|
|
||
|
// Stamp users are CopyBundleData, CompileAssetsCatalog, CodeSigning and
|
||
|
// StampForTarget.
|
||
|
size_t num_stamp_uses = 4;
|
||
|
std::vector<OutputFile> order_only_deps = WriteInputDepsStampAndGetDep(
|
||
|
std::vector<const Target*>(), num_stamp_uses);
|
||
|
|
||
|
std::string code_signing_rule_name = WriteCodeSigningRuleDefinition();
|
||
|
|
||
|
std::vector<OutputFile> output_files;
|
||
|
WriteCopyBundleDataSteps(order_only_deps, &output_files);
|
||
|
WriteCompileAssetsCatalogStep(order_only_deps, &output_files);
|
||
|
WriteCodeSigningStep(code_signing_rule_name, order_only_deps, &output_files);
|
||
|
|
||
|
for (const auto& pair : target_->data_deps())
|
||
|
order_only_deps.push_back(pair.ptr->dependency_output_file());
|
||
|
WriteStampForTarget(output_files, order_only_deps);
|
||
|
|
||
|
// Write a phony target for the outer bundle directory. This allows other
|
||
|
// targets to treat the entire bundle as a single unit, even though it is
|
||
|
// a directory, so that it can be depended upon as a discrete build edge.
|
||
|
out_ << "build ";
|
||
|
path_output_.WriteFile(
|
||
|
out_,
|
||
|
OutputFile(settings_->build_settings(),
|
||
|
target_->bundle_data().GetBundleRootDirOutput(settings_)));
|
||
|
out_ << ": phony " << target_->dependency_output_file().value();
|
||
|
out_ << std::endl;
|
||
|
}
|
||
|
|
||
|
std::string NinjaCreateBundleTargetWriter::WriteCodeSigningRuleDefinition() {
|
||
|
if (target_->bundle_data().code_signing_script().is_null())
|
||
|
return std::string();
|
||
|
|
||
|
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("_code_signing_rule");
|
||
|
|
||
|
out_ << "rule " << custom_rule_name << std::endl;
|
||
|
out_ << " command = ";
|
||
|
path_output_.WriteFile(out_, settings_->build_settings()->python_path());
|
||
|
out_ << " ";
|
||
|
path_output_.WriteFile(out_, target_->bundle_data().code_signing_script());
|
||
|
|
||
|
const SubstitutionList& args = target_->bundle_data().code_signing_args();
|
||
|
EscapeOptions args_escape_options;
|
||
|
args_escape_options.mode = ESCAPE_NINJA_COMMAND;
|
||
|
|
||
|
for (const auto& arg : args.list()) {
|
||
|
out_ << " ";
|
||
|
SubstitutionWriter::WriteWithNinjaVariables(arg, args_escape_options, out_);
|
||
|
}
|
||
|
out_ << std::endl;
|
||
|
out_ << " description = CODE SIGNING " << target_label << std::endl;
|
||
|
out_ << " restat = 1" << std::endl;
|
||
|
out_ << std::endl;
|
||
|
|
||
|
return custom_rule_name;
|
||
|
}
|
||
|
|
||
|
void NinjaCreateBundleTargetWriter::WriteCopyBundleDataSteps(
|
||
|
const std::vector<OutputFile>& order_only_deps,
|
||
|
std::vector<OutputFile>* output_files) {
|
||
|
for (const BundleFileRule& file_rule : target_->bundle_data().file_rules())
|
||
|
WriteCopyBundleFileRuleSteps(file_rule, order_only_deps, output_files);
|
||
|
}
|
||
|
|
||
|
void NinjaCreateBundleTargetWriter::WriteCopyBundleFileRuleSteps(
|
||
|
const BundleFileRule& file_rule,
|
||
|
const std::vector<OutputFile>& order_only_deps,
|
||
|
std::vector<OutputFile>* output_files) {
|
||
|
// Note that we don't write implicit deps for copy steps. "copy_bundle_data"
|
||
|
// steps as this is most likely implemented using hardlink in the common case.
|
||
|
// See NinjaCopyTargetWriter::WriteCopyRules() for a detailed explanation.
|
||
|
for (const SourceFile& source_file : file_rule.sources()) {
|
||
|
OutputFile output_file = file_rule.ApplyPatternToSourceAsOutputFile(
|
||
|
settings_, target_->bundle_data(), source_file);
|
||
|
output_files->push_back(output_file);
|
||
|
|
||
|
out_ << "build ";
|
||
|
path_output_.WriteFile(out_, output_file);
|
||
|
out_ << ": " << GetNinjaRulePrefixForToolchain(settings_)
|
||
|
<< Toolchain::ToolTypeToName(Toolchain::TYPE_COPY_BUNDLE_DATA) << " ";
|
||
|
path_output_.WriteFile(out_, source_file);
|
||
|
|
||
|
if (!order_only_deps.empty()) {
|
||
|
out_ << " ||";
|
||
|
path_output_.WriteFiles(out_, order_only_deps);
|
||
|
}
|
||
|
|
||
|
out_ << std::endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void NinjaCreateBundleTargetWriter::WriteCompileAssetsCatalogStep(
|
||
|
const std::vector<OutputFile>& order_only_deps,
|
||
|
std::vector<OutputFile>* output_files) {
|
||
|
if (target_->bundle_data().assets_catalog_sources().empty() &&
|
||
|
target_->bundle_data().partial_info_plist().is_null())
|
||
|
return;
|
||
|
|
||
|
OutputFile compiled_catalog;
|
||
|
if (!target_->bundle_data().assets_catalog_sources().empty()) {
|
||
|
compiled_catalog =
|
||
|
OutputFile(settings_->build_settings(),
|
||
|
target_->bundle_data().GetCompiledAssetCatalogPath());
|
||
|
output_files->push_back(compiled_catalog);
|
||
|
}
|
||
|
|
||
|
OutputFile partial_info_plist;
|
||
|
if (!target_->bundle_data().partial_info_plist().is_null()) {
|
||
|
partial_info_plist =
|
||
|
OutputFile(settings_->build_settings(),
|
||
|
target_->bundle_data().partial_info_plist());
|
||
|
|
||
|
output_files->push_back(partial_info_plist);
|
||
|
}
|
||
|
|
||
|
// If there are no asset catalog to compile but the "partial_info_plist" is
|
||
|
// non-empty, then add a target to generate an empty file (to avoid breaking
|
||
|
// code that depends on this file existence).
|
||
|
if (target_->bundle_data().assets_catalog_sources().empty()) {
|
||
|
DCHECK(!target_->bundle_data().partial_info_plist().is_null());
|
||
|
|
||
|
out_ << "build ";
|
||
|
path_output_.WriteFile(out_, partial_info_plist);
|
||
|
out_ << ": " << GetNinjaRulePrefixForToolchain(settings_)
|
||
|
<< Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP);
|
||
|
if (!order_only_deps.empty()) {
|
||
|
out_ << " ||";
|
||
|
path_output_.WriteFiles(out_, order_only_deps);
|
||
|
}
|
||
|
out_ << std::endl;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
OutputFile input_dep = WriteCompileAssetsCatalogInputDepsStamp(
|
||
|
target_->bundle_data().assets_catalog_deps());
|
||
|
DCHECK(!input_dep.value().empty());
|
||
|
|
||
|
out_ << "build ";
|
||
|
path_output_.WriteFile(out_, compiled_catalog);
|
||
|
if (partial_info_plist != OutputFile()) {
|
||
|
// If "partial_info_plist" is non-empty, then add it to list of implicit
|
||
|
// outputs of the asset catalog compilation, so that target can use it
|
||
|
// without getting the ninja error "'foo', needed by 'bar', missing and
|
||
|
// no known rule to make it".
|
||
|
out_ << " | ";
|
||
|
path_output_.WriteFile(out_, partial_info_plist);
|
||
|
}
|
||
|
|
||
|
out_ << ": " << GetNinjaRulePrefixForToolchain(settings_)
|
||
|
<< Toolchain::ToolTypeToName(Toolchain::TYPE_COMPILE_XCASSETS);
|
||
|
|
||
|
std::set<SourceFile> asset_catalog_bundles;
|
||
|
for (const auto& source : target_->bundle_data().assets_catalog_sources()) {
|
||
|
out_ << " ";
|
||
|
path_output_.WriteFile(out_, source);
|
||
|
asset_catalog_bundles.insert(source);
|
||
|
}
|
||
|
|
||
|
out_ << " | ";
|
||
|
path_output_.WriteFile(out_, input_dep);
|
||
|
|
||
|
if (!order_only_deps.empty()) {
|
||
|
out_ << " ||";
|
||
|
path_output_.WriteFiles(out_, order_only_deps);
|
||
|
}
|
||
|
|
||
|
out_ << std::endl;
|
||
|
|
||
|
out_ << " product_type = " << target_->bundle_data().product_type()
|
||
|
<< std::endl;
|
||
|
|
||
|
if (partial_info_plist != OutputFile()) {
|
||
|
out_ << " partial_info_plist = ";
|
||
|
path_output_.WriteFile(out_, partial_info_plist);
|
||
|
out_ << std::endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
OutputFile
|
||
|
NinjaCreateBundleTargetWriter::WriteCompileAssetsCatalogInputDepsStamp(
|
||
|
const std::vector<const Target*>& dependencies) {
|
||
|
DCHECK(!dependencies.empty());
|
||
|
if (dependencies.size() == 1)
|
||
|
return dependencies[0]->dependency_output_file();
|
||
|
|
||
|
OutputFile xcassets_input_stamp_file =
|
||
|
GetBuildDirForTargetAsOutputFile(target_, BuildDirType::OBJ);
|
||
|
xcassets_input_stamp_file.value().append(target_->label().name());
|
||
|
xcassets_input_stamp_file.value().append(".xcassets.inputdeps.stamp");
|
||
|
|
||
|
out_ << "build ";
|
||
|
path_output_.WriteFile(out_, xcassets_input_stamp_file);
|
||
|
out_ << ": " << GetNinjaRulePrefixForToolchain(settings_)
|
||
|
<< Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP);
|
||
|
|
||
|
for (const Target* target : dependencies) {
|
||
|
out_ << " ";
|
||
|
path_output_.WriteFile(out_, target->dependency_output_file());
|
||
|
}
|
||
|
out_ << std::endl;
|
||
|
return xcassets_input_stamp_file;
|
||
|
}
|
||
|
|
||
|
void NinjaCreateBundleTargetWriter::WriteCodeSigningStep(
|
||
|
const std::string& code_signing_rule_name,
|
||
|
const std::vector<OutputFile>& order_only_deps,
|
||
|
std::vector<OutputFile>* output_files) {
|
||
|
if (code_signing_rule_name.empty())
|
||
|
return;
|
||
|
|
||
|
OutputFile code_signing_input_stamp_file =
|
||
|
WriteCodeSigningInputDepsStamp(order_only_deps, output_files);
|
||
|
DCHECK(!code_signing_input_stamp_file.value().empty());
|
||
|
|
||
|
out_ << "build";
|
||
|
std::vector<OutputFile> code_signing_output_files;
|
||
|
SubstitutionWriter::GetListAsOutputFiles(
|
||
|
settings_, target_->bundle_data().code_signing_outputs(),
|
||
|
&code_signing_output_files);
|
||
|
path_output_.WriteFiles(out_, code_signing_output_files);
|
||
|
|
||
|
// Since the code signature step depends on all the files from the bundle,
|
||
|
// the create_bundle stamp can just depends on the output of the signature
|
||
|
// script (dependencies are transitive).
|
||
|
output_files->swap(code_signing_output_files);
|
||
|
|
||
|
out_ << ": " << code_signing_rule_name;
|
||
|
out_ << " | ";
|
||
|
path_output_.WriteFile(out_, code_signing_input_stamp_file);
|
||
|
out_ << std::endl;
|
||
|
}
|
||
|
|
||
|
OutputFile NinjaCreateBundleTargetWriter::WriteCodeSigningInputDepsStamp(
|
||
|
const std::vector<OutputFile>& order_only_deps,
|
||
|
std::vector<OutputFile>* output_files) {
|
||
|
std::vector<SourceFile> code_signing_input_files;
|
||
|
code_signing_input_files.push_back(
|
||
|
target_->bundle_data().code_signing_script());
|
||
|
code_signing_input_files.insert(
|
||
|
code_signing_input_files.end(),
|
||
|
target_->bundle_data().code_signing_sources().begin(),
|
||
|
target_->bundle_data().code_signing_sources().end());
|
||
|
for (const OutputFile& output_file : *output_files) {
|
||
|
code_signing_input_files.push_back(
|
||
|
output_file.AsSourceFile(settings_->build_settings()));
|
||
|
}
|
||
|
|
||
|
DCHECK(!code_signing_input_files.empty());
|
||
|
if (code_signing_input_files.size() == 1 && order_only_deps.empty())
|
||
|
return OutputFile(settings_->build_settings(), code_signing_input_files[0]);
|
||
|
|
||
|
OutputFile code_signing_input_stamp_file =
|
||
|
GetBuildDirForTargetAsOutputFile(target_, BuildDirType::OBJ);
|
||
|
code_signing_input_stamp_file.value().append(target_->label().name());
|
||
|
code_signing_input_stamp_file.value().append(".codesigning.inputdeps.stamp");
|
||
|
|
||
|
out_ << "build ";
|
||
|
path_output_.WriteFile(out_, code_signing_input_stamp_file);
|
||
|
out_ << ": " << GetNinjaRulePrefixForToolchain(settings_)
|
||
|
<< Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP);
|
||
|
|
||
|
for (const SourceFile& source : code_signing_input_files) {
|
||
|
out_ << " ";
|
||
|
path_output_.WriteFile(out_, source);
|
||
|
}
|
||
|
if (!order_only_deps.empty()) {
|
||
|
out_ << " ||";
|
||
|
path_output_.WriteFiles(out_, order_only_deps);
|
||
|
}
|
||
|
out_ << std::endl;
|
||
|
return code_signing_input_stamp_file;
|
||
|
}
|