OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/gn/ninja_create_bundle_target_writer.h" | 5 #include "tools/gn/ninja_create_bundle_target_writer.h" |
6 | 6 |
| 7 #include "base/macros.h" |
| 8 #include "base/strings/string_util.h" |
7 #include "tools/gn/filesystem_utils.h" | 9 #include "tools/gn/filesystem_utils.h" |
8 #include "tools/gn/ninja_utils.h" | 10 #include "tools/gn/ninja_utils.h" |
9 #include "tools/gn/output_file.h" | 11 #include "tools/gn/output_file.h" |
10 #include "tools/gn/scheduler.h" | 12 #include "tools/gn/scheduler.h" |
11 #include "tools/gn/substitution_writer.h" | 13 #include "tools/gn/substitution_writer.h" |
12 #include "tools/gn/target.h" | 14 #include "tools/gn/target.h" |
13 #include "tools/gn/toolchain.h" | 15 #include "tools/gn/toolchain.h" |
14 | 16 |
15 namespace { | 17 namespace { |
16 | 18 |
17 void FailWithMissingToolError(Toolchain::ToolType tool, const Target* target) { | 19 void FailWithMissingToolError(Toolchain::ToolType tool, const Target* target) { |
18 const std::string& tool_name = Toolchain::ToolTypeToName(tool); | 20 const std::string& tool_name = Toolchain::ToolTypeToName(tool); |
19 g_scheduler->FailWithError(Err( | 21 g_scheduler->FailWithError(Err( |
20 nullptr, tool_name + " tool not defined", | 22 nullptr, tool_name + " tool not defined", |
21 "The toolchain " + | 23 "The toolchain " + |
22 target->toolchain()->label().GetUserVisibleName(false) + "\n" | 24 target->toolchain()->label().GetUserVisibleName(false) + "\n" |
23 "used by target " + target->label().GetUserVisibleName(false) + "\n" | 25 "used by target " + target->label().GetUserVisibleName(false) + "\n" |
24 "doesn't define a \"" + tool_name + "\" tool.")); | 26 "doesn't define a \"" + tool_name + "\" tool.")); |
25 } | 27 } |
26 | 28 |
| 29 bool EnsureAllToolsAvailable(const Target* target) { |
| 30 const Toolchain::ToolType kRequiredTools[] = { |
| 31 Toolchain::TYPE_COPY_BUNDLE_DATA, Toolchain::TYPE_COMPILE_XCASSETS, |
| 32 Toolchain::TYPE_STAMP, |
| 33 }; |
| 34 |
| 35 for (size_t i = 0; i < arraysize(kRequiredTools); ++i) { |
| 36 if (!target->toolchain()->GetTool(kRequiredTools[i])) { |
| 37 FailWithMissingToolError(kRequiredTools[i], target); |
| 38 return false; |
| 39 } |
| 40 } |
| 41 |
| 42 return true; |
| 43 } |
| 44 |
27 } // namespace | 45 } // namespace |
28 | 46 |
29 NinjaCreateBundleTargetWriter::NinjaCreateBundleTargetWriter( | 47 NinjaCreateBundleTargetWriter::NinjaCreateBundleTargetWriter( |
30 const Target* target, | 48 const Target* target, |
31 std::ostream& out) | 49 std::ostream& out) |
32 : NinjaTargetWriter(target, out) {} | 50 : NinjaTargetWriter(target, out) {} |
33 | 51 |
34 NinjaCreateBundleTargetWriter::~NinjaCreateBundleTargetWriter() {} | 52 NinjaCreateBundleTargetWriter::~NinjaCreateBundleTargetWriter() {} |
35 | 53 |
36 void NinjaCreateBundleTargetWriter::Run() { | 54 void NinjaCreateBundleTargetWriter::Run() { |
37 if (!target_->toolchain()->GetTool(Toolchain::TYPE_COPY_BUNDLE_DATA)) { | 55 if (!EnsureAllToolsAvailable(target_)) |
38 FailWithMissingToolError(Toolchain::TYPE_COPY_BUNDLE_DATA, target_); | |
39 return; | 56 return; |
40 } | |
41 | 57 |
42 if (!target_->toolchain()->GetTool(Toolchain::TYPE_COMPILE_XCASSETS)) { | 58 std::string code_signing_rule_name = WriteCodeSigningRuleDefinition(); |
43 FailWithMissingToolError(Toolchain::TYPE_COMPILE_XCASSETS, target_); | |
44 return; | |
45 } | |
46 | 59 |
47 if (!target_->toolchain()->GetTool(Toolchain::TYPE_STAMP)) { | |
48 FailWithMissingToolError(Toolchain::TYPE_STAMP, target_); | |
49 return; | |
50 } | |
51 | |
52 std::vector<OutputFile> output_files; | |
53 OutputFile input_dep = | 60 OutputFile input_dep = |
54 WriteInputDepsStampAndGetDep(std::vector<const Target*>()); | 61 WriteInputDepsStampAndGetDep(std::vector<const Target*>()); |
55 | 62 |
| 63 std::vector<OutputFile> output_files; |
| 64 WriteCopyBundleDataRules(input_dep, &output_files); |
| 65 WriteCompileAssetsCatalogRule(input_dep, &output_files); |
| 66 WriteCodeSigningRules(code_signing_rule_name, input_dep, &output_files); |
| 67 |
| 68 std::vector<OutputFile> order_only_deps; |
| 69 for (const auto& pair : target_->data_deps()) |
| 70 order_only_deps.push_back(pair.ptr->dependency_output_file()); |
| 71 WriteStampForTarget(output_files, order_only_deps); |
| 72 |
| 73 // Write a phony target for the outer bundle directory. This allows other |
| 74 // targets to treat the entire bundle as a single unit, even though it is |
| 75 // a directory, so that it can be depended upon as a discrete build edge. |
| 76 out_ << "build "; |
| 77 path_output_.WriteFile( |
| 78 out_, |
| 79 OutputFile(settings_->build_settings(), |
| 80 target_->bundle_data().GetBundleRootDirOutput(settings_))); |
| 81 out_ << ": phony " << target_->dependency_output_file().value(); |
| 82 out_ << std::endl; |
| 83 } |
| 84 |
| 85 std::string NinjaCreateBundleTargetWriter::WriteCodeSigningRuleDefinition() { |
| 86 if (target_->bundle_data().code_signing_script().is_null()) |
| 87 return std::string(); |
| 88 |
| 89 std::string target_label = target_->label().GetUserVisibleName(true); |
| 90 std::string custom_rule_name(target_label); |
| 91 base::ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name); |
| 92 custom_rule_name.append("_code_signing_rule"); |
| 93 |
| 94 out_ << "rule " << custom_rule_name << std::endl; |
| 95 out_ << " command = "; |
| 96 path_output_.WriteFile(out_, settings_->build_settings()->python_path()); |
| 97 out_ << " "; |
| 98 path_output_.WriteFile(out_, target_->bundle_data().code_signing_script()); |
| 99 |
| 100 const SubstitutionList& args = target_->bundle_data().code_signing_args(); |
| 101 EscapeOptions args_escape_options; |
| 102 args_escape_options.mode = ESCAPE_NINJA_COMMAND; |
| 103 |
| 104 for (const auto& arg : args.list()) { |
| 105 out_ << " "; |
| 106 SubstitutionWriter::WriteWithNinjaVariables(arg, args_escape_options, out_); |
| 107 } |
| 108 out_ << std::endl; |
| 109 out_ << " description = CODE SIGNING " << target_label << std::endl; |
| 110 out_ << " restat = 1" << std::endl; |
| 111 out_ << std::endl; |
| 112 |
| 113 return custom_rule_name; |
| 114 } |
| 115 |
| 116 void NinjaCreateBundleTargetWriter::WriteCopyBundleDataRules( |
| 117 const OutputFile& input_dep, |
| 118 std::vector<OutputFile>* output_files) { |
56 for (const BundleFileRule& file_rule : target_->bundle_data().file_rules()) { | 119 for (const BundleFileRule& file_rule : target_->bundle_data().file_rules()) { |
57 for (const SourceFile& source_file : file_rule.sources()) { | 120 for (const SourceFile& source_file : file_rule.sources()) { |
58 OutputFile output_file = file_rule.ApplyPatternToSourceAsOutputFile( | 121 OutputFile output_file = file_rule.ApplyPatternToSourceAsOutputFile( |
59 settings_, target_->bundle_data(), source_file); | 122 settings_, target_->bundle_data(), source_file); |
60 output_files.push_back(output_file); | 123 output_files->push_back(output_file); |
61 | 124 |
62 out_ << "build "; | 125 out_ << "build "; |
63 path_output_.WriteFile(out_, output_file); | 126 path_output_.WriteFile(out_, output_file); |
64 out_ << ": " | 127 out_ << ": " |
65 << GetNinjaRulePrefixForToolchain(settings_) | 128 << GetNinjaRulePrefixForToolchain(settings_) |
66 << Toolchain::ToolTypeToName(Toolchain::TYPE_COPY_BUNDLE_DATA) | 129 << Toolchain::ToolTypeToName(Toolchain::TYPE_COPY_BUNDLE_DATA) |
67 << " "; | 130 << " "; |
68 path_output_.WriteFile(out_, source_file); | 131 path_output_.WriteFile(out_, source_file); |
69 if (!input_dep.value().empty()) { | 132 if (!input_dep.value().empty()) { |
70 out_ << " || "; | 133 out_ << " | "; |
71 path_output_.WriteFile(out_, input_dep); | 134 path_output_.WriteFile(out_, input_dep); |
72 } | 135 } |
73 out_ << std::endl; | 136 out_ << std::endl; |
74 } | 137 } |
75 } | 138 } |
| 139 } |
76 | 140 |
77 if (!target_->bundle_data().asset_catalog_sources().empty()) { | 141 void NinjaCreateBundleTargetWriter::WriteCompileAssetsCatalogRule( |
78 OutputFile output_file( | 142 const OutputFile& input_dep, |
79 settings_->build_settings(), | 143 std::vector<OutputFile>* output_files) { |
80 target_->bundle_data().GetCompiledAssetCatalogPath()); | 144 if (target_->bundle_data().asset_catalog_sources().empty()) |
81 output_files.push_back(output_file); | 145 return; |
82 | 146 |
83 out_ << "build "; | 147 OutputFile output_file(settings_->build_settings(), |
84 path_output_.WriteFile(out_, output_file); | 148 target_->bundle_data().GetCompiledAssetCatalogPath()); |
85 out_ << ": " | 149 output_files->push_back(output_file); |
86 << GetNinjaRulePrefixForToolchain(settings_) | |
87 << Toolchain::ToolTypeToName(Toolchain::TYPE_COMPILE_XCASSETS); | |
88 | 150 |
89 std::set<SourceFile> asset_catalog_bundles; | 151 out_ << "build "; |
90 for (const auto& source : target_->bundle_data().asset_catalog_sources()) { | 152 path_output_.WriteFile(out_, output_file); |
91 SourceFile asset_catalog_bundle; | 153 out_ << ": " << GetNinjaRulePrefixForToolchain(settings_) |
92 CHECK(IsSourceFileFromAssetCatalog(source, &asset_catalog_bundle)); | 154 << Toolchain::ToolTypeToName(Toolchain::TYPE_COMPILE_XCASSETS); |
93 if (asset_catalog_bundles.find(asset_catalog_bundle) != | |
94 asset_catalog_bundles.end()) | |
95 continue; | |
96 out_ << " "; | |
97 path_output_.WriteFile(out_, asset_catalog_bundle); | |
98 asset_catalog_bundles.insert(asset_catalog_bundle); | |
99 } | |
100 | 155 |
101 out_ << " |"; | 156 std::set<SourceFile> asset_catalog_bundles; |
102 for (const auto& source : target_->bundle_data().asset_catalog_sources()) { | 157 for (const auto& source : target_->bundle_data().asset_catalog_sources()) { |
103 out_ << " "; | 158 SourceFile asset_catalog_bundle; |
104 path_output_.WriteFile(out_, source); | 159 CHECK(IsSourceFileFromAssetCatalog(source, &asset_catalog_bundle)); |
105 } | 160 if (asset_catalog_bundles.find(asset_catalog_bundle) != |
106 if (!input_dep.value().empty()) { | 161 asset_catalog_bundles.end()) |
107 out_ << " || "; | 162 continue; |
108 path_output_.WriteFile(out_, input_dep); | 163 out_ << " "; |
109 } | 164 path_output_.WriteFile(out_, asset_catalog_bundle); |
110 out_ << std::endl; | 165 asset_catalog_bundles.insert(asset_catalog_bundle); |
111 } | 166 } |
112 | 167 |
113 out_ << std::endl; | 168 out_ << " |"; |
| 169 for (const auto& source : target_->bundle_data().asset_catalog_sources()) { |
| 170 out_ << " "; |
| 171 path_output_.WriteFile( |
| 172 out_, OutputFile(settings_->build_settings(), source)); |
| 173 } |
114 | 174 |
115 std::vector<OutputFile> order_only_deps; | 175 if (!input_dep.value().empty()) { |
116 for (const auto& pair : target_->data_deps()) | 176 out_ << " "; |
117 order_only_deps.push_back(pair.ptr->dependency_output_file()); | 177 path_output_.WriteFile(out_, input_dep); |
118 WriteStampForTarget(output_files, order_only_deps); | 178 } |
119 | |
120 // Write a phony target for the outer bundle directory. This allows other | |
121 // targets to treat the entire bundle as a single unit, even though it is | |
122 // a directory, so that it can be depended upon as a discrete build edge. | |
123 out_ << "build "; | |
124 path_output_.WriteFile( | |
125 out_, | |
126 OutputFile(settings_->build_settings(), | |
127 target_->bundle_data().GetBundleRootDirOutput(settings_))); | |
128 out_ << ": phony " << target_->dependency_output_file().value(); | |
129 out_ << std::endl; | 179 out_ << std::endl; |
130 } | 180 } |
| 181 |
| 182 void NinjaCreateBundleTargetWriter::WriteCodeSigningRules( |
| 183 const std::string& code_signing_rule_name, |
| 184 const OutputFile& input_dep, |
| 185 std::vector<OutputFile>* output_files) { |
| 186 if (code_signing_rule_name.empty()) |
| 187 return; |
| 188 |
| 189 OutputFile code_signing_input_stamp_file = |
| 190 WriteCodeSigningInputDepsStamp(input_dep, output_files); |
| 191 |
| 192 out_ << "build"; |
| 193 std::vector<OutputFile> code_signing_output_files; |
| 194 SubstitutionWriter::GetListAsOutputFiles( |
| 195 settings_, target_->bundle_data().code_signing_outputs(), |
| 196 &code_signing_output_files); |
| 197 path_output_.WriteFiles(out_, code_signing_output_files); |
| 198 |
| 199 // Since the code signature step depends on all the files from the bundle, |
| 200 // the create_bundle stamp can just depends on the output of the signature. |
| 201 output_files->swap(code_signing_output_files); |
| 202 |
| 203 out_ << ": " << code_signing_rule_name; |
| 204 if (!code_signing_input_stamp_file.value().empty()) { |
| 205 out_ << " | "; |
| 206 path_output_.WriteFile(out_, code_signing_input_stamp_file); |
| 207 } |
| 208 out_ << std::endl; |
| 209 } |
| 210 |
| 211 OutputFile NinjaCreateBundleTargetWriter::WriteCodeSigningInputDepsStamp( |
| 212 const OutputFile& input_dep, |
| 213 std::vector<OutputFile>* output_files) { |
| 214 std::vector<SourceFile> code_signing_input_files; |
| 215 code_signing_input_files.push_back( |
| 216 target_->bundle_data().code_signing_script()); |
| 217 code_signing_input_files.insert( |
| 218 code_signing_input_files.end(), |
| 219 target_->bundle_data().code_signing_sources().begin(), |
| 220 target_->bundle_data().code_signing_sources().end()); |
| 221 for (const OutputFile& output_file : *output_files) { |
| 222 code_signing_input_files.push_back( |
| 223 output_file.AsSourceFile(settings_->build_settings())); |
| 224 } |
| 225 if (!input_dep.value().empty()) { |
| 226 code_signing_input_files.push_back( |
| 227 input_dep.AsSourceFile(settings_->build_settings())); |
| 228 } |
| 229 |
| 230 DCHECK(!code_signing_input_files.empty()); |
| 231 if (code_signing_input_files.size() == 1) |
| 232 return OutputFile(settings_->build_settings(), code_signing_input_files[0]); |
| 233 |
| 234 OutputFile code_signing_input_stamp_file = |
| 235 OutputFile(RebasePath(GetTargetOutputDir(target_).value(), |
| 236 settings_->build_settings()->build_dir(), |
| 237 settings_->build_settings()->root_path_utf8())); |
| 238 code_signing_input_stamp_file.value().append(target_->label().name()); |
| 239 code_signing_input_stamp_file.value().append(".codesigning.inputdeps.stamp"); |
| 240 |
| 241 out_ << "build "; |
| 242 path_output_.WriteFile(out_, code_signing_input_stamp_file); |
| 243 out_ << ": " << GetNinjaRulePrefixForToolchain(settings_) |
| 244 << Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP); |
| 245 |
| 246 for (const SourceFile& source : code_signing_input_files) { |
| 247 out_ << " "; |
| 248 path_output_.WriteFile(out_, source); |
| 249 } |
| 250 out_ << std::endl; |
| 251 return code_signing_input_stamp_file; |
| 252 } |
OLD | NEW |