Chromium Code Reviews| 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/xcode_writer.h" | 5 #include "tools/gn/xcode_writer.h" |
| 6 | 6 |
| 7 #include <iomanip> | 7 #include <iomanip> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <sstream> | 10 #include <sstream> |
| 11 #include <string> | 11 #include <string> |
| 12 #include <utility> | 12 #include <utility> |
| 13 | 13 |
| 14 #include "base/environment.h" | 14 #include "base/environment.h" |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/sha1.h" | 16 #include "base/sha1.h" |
| 17 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
| 18 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
| 19 #include "tools/gn/args.h" | 19 #include "tools/gn/args.h" |
| 20 #include "tools/gn/build_settings.h" | 20 #include "tools/gn/build_settings.h" |
| 21 #include "tools/gn/builder.h" | 21 #include "tools/gn/builder.h" |
| 22 #include "tools/gn/commands.h" | 22 #include "tools/gn/commands.h" |
| 23 #include "tools/gn/deps_iterator.h" | 23 #include "tools/gn/deps_iterator.h" |
| 24 #include "tools/gn/filesystem_utils.h" | 24 #include "tools/gn/filesystem_utils.h" |
| 25 #include "tools/gn/scope.h" | |
| 25 #include "tools/gn/settings.h" | 26 #include "tools/gn/settings.h" |
| 26 #include "tools/gn/source_file.h" | 27 #include "tools/gn/source_file.h" |
| 27 #include "tools/gn/target.h" | 28 #include "tools/gn/target.h" |
| 28 #include "tools/gn/value.h" | 29 #include "tools/gn/value.h" |
| 29 #include "tools/gn/variables.h" | 30 #include "tools/gn/variables.h" |
| 30 #include "tools/gn/xcode_object.h" | 31 #include "tools/gn/xcode_object.h" |
| 31 | 32 |
| 32 namespace { | 33 namespace { |
| 33 | 34 |
| 34 XcodeWriter::TargetOsType GetTargetOs(const Args& args) { | 35 bool GetTargetOs(const Scope* scope, std::string* target_os, Err* err) { |
| 35 const Value* target_os_value = args.GetArgOverride(variables::kTargetOs); | 36 const char* variable_names[] = {variables::kTargetOs, variables::kHostOs}; |
| 36 if (target_os_value) { | 37 for (size_t i = 0; i < arraysize(variable_names); ++i) { |
| 37 if (target_os_value->type() == Value::STRING) { | 38 const Value* value = scope->GetValue(variable_names[i]); |
| 38 if (target_os_value->string_value() == "ios") | 39 if (value && value->type() == Value::STRING && |
| 39 return XcodeWriter::WRITER_TARGET_OS_IOS; | 40 !value->string_value().empty()) { |
| 41 target_os->assign(value->string_value()); | |
| 42 return true; | |
| 40 } | 43 } |
| 41 } | 44 } |
| 42 return XcodeWriter::WRITER_TARGET_OS_MACOS; | 45 *err = Err(nullptr, "cannot determine target_os"); |
| 46 return false; | |
| 43 } | 47 } |
| 44 | 48 |
| 45 std::string GetArchs(const Args& args) { | 49 bool GetTargetCpu(const Scope* scope, std::string* target_cpu, Err* err) { |
| 46 const Value* target_cpu_value = args.GetArgOverride(variables::kTargetCpu); | 50 const char* variable_names[] = {variables::kTargetCpu, variables::kHostCpu}; |
| 47 if (target_cpu_value) { | 51 for (size_t i = 0; i < arraysize(variable_names); ++i) { |
| 48 if (target_cpu_value->type() == Value::STRING) { | 52 const Value* value = scope->GetValue(variable_names[i]); |
| 49 if (target_cpu_value->string_value() == "x86") | 53 if (value && value->type() == Value::STRING && |
| 50 return "i386"; | 54 !value->string_value().empty()) { |
| 51 if (target_cpu_value->string_value() == "x64") | 55 if (value->string_value() == "x86") { |
| 52 return "x86_64"; | 56 target_cpu->assign("i386"); |
| 53 if (target_cpu_value->string_value() == "arm") | 57 return true; |
| 54 return "armv7"; | 58 } |
| 55 if (target_cpu_value->string_value() == "armv7") | 59 if (value->string_value() == "x64") { |
| 56 return "armv7"; | 60 target_cpu->assign("x86_64"); |
| 57 if (target_cpu_value->string_value() == "arm64") | 61 return true; |
| 58 return "armv64"; | 62 } |
| 63 if (value->string_value() == "arm") { | |
| 64 target_cpu->assign("armv7"); | |
| 65 return true; | |
| 66 } | |
| 67 if (value->string_value() == "arm64") { | |
| 68 target_cpu->assign("arm64"); | |
| 69 return true; | |
| 70 } | |
| 59 } | 71 } |
| 60 } | 72 } |
| 61 return "x86_64"; | 73 *err = Err(nullptr, "cannot determine target_cpu"); |
| 74 return false; | |
| 75 } | |
| 76 | |
| 77 bool GetDeploymentTarget(const Scope* scope, | |
| 78 const char* variable, | |
| 79 std::string* deployment_target, | |
| 80 Err* err) { | |
| 81 const Value* value = scope->GetValue(variable); | |
| 82 if (!value || value->type() != Value::STRING) { | |
| 83 *err = Err(nullptr, "cannot determine deployment target"); | |
| 84 return false; | |
| 85 } | |
| 86 | |
| 87 deployment_target->assign(value->string_value()); | |
| 88 return true; | |
| 62 } | 89 } |
| 63 | 90 |
| 64 std::string GetBuildScript(const std::string& target_name, | 91 std::string GetBuildScript(const std::string& target_name, |
| 65 const std::string& build_path, | 92 const std::string& build_path, |
| 66 const std::string& ninja_extra_args) { | 93 const std::string& ninja_extra_args) { |
| 67 std::stringstream script; | 94 std::stringstream script; |
| 68 script << "echo note: \"Compile and copy " << target_name << " via ninja\"\n" | 95 script << "echo note: \"Compile and copy " << target_name << " via ninja\"\n" |
| 69 << "exec "; | 96 << "exec "; |
| 70 if (!build_path.empty()) | 97 if (!build_path.empty()) |
| 71 script << "env PATH=\"" << build_path << "\" "; | 98 script << "env PATH=\"" << build_path << "\" "; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 140 } // namespace | 167 } // namespace |
| 141 | 168 |
| 142 // static | 169 // static |
| 143 bool XcodeWriter::RunAndWriteFiles(const std::string& workspace_name, | 170 bool XcodeWriter::RunAndWriteFiles(const std::string& workspace_name, |
| 144 const std::string& root_target_name, | 171 const std::string& root_target_name, |
| 145 const std::string& ninja_extra_args, | 172 const std::string& ninja_extra_args, |
| 146 const std::string& dir_filters_string, | 173 const std::string& dir_filters_string, |
| 147 const BuildSettings* build_settings, | 174 const BuildSettings* build_settings, |
| 148 Builder* builder, | 175 Builder* builder, |
| 149 Err* err) { | 176 Err* err) { |
| 150 const XcodeWriter::TargetOsType target_os = | |
| 151 GetTargetOs(build_settings->build_args()); | |
| 152 | |
| 153 PBXAttributes attributes; | 177 PBXAttributes attributes; |
| 154 switch (target_os) { | 178 if (!GetProjectsAttributes(build_settings, &attributes, err)) |
| 155 case XcodeWriter::WRITER_TARGET_OS_IOS: | 179 return false; |
| 156 attributes["SDKROOT"] = "iphoneos"; | |
| 157 attributes["TARGETED_DEVICE_FAMILY"] = "1,2"; | |
| 158 break; | |
| 159 case XcodeWriter::WRITER_TARGET_OS_MACOS: | |
| 160 attributes["ARCHS"] = GetArchs(build_settings->build_args()); | |
| 161 attributes["SDKROOT"] = "macosx10.11"; | |
| 162 break; | |
| 163 } | |
| 164 | 180 |
| 165 const std::string source_path = | 181 const std::string source_path = |
| 166 base::FilePath::FromUTF8Unsafe( | 182 base::FilePath::FromUTF8Unsafe( |
| 167 RebasePath("//", build_settings->build_dir())) | 183 RebasePath("//", build_settings->build_dir())) |
| 168 .StripTrailingSeparators() | 184 .StripTrailingSeparators() |
| 169 .AsUTF8Unsafe(); | 185 .AsUTF8Unsafe(); |
| 170 | 186 |
| 171 std::string config_name = build_settings->build_dir() | 187 std::string config_name = build_settings->build_dir() |
| 172 .Resolve(base::FilePath()) | 188 .Resolve(base::FilePath()) |
| 173 .StripTrailingSeparators() | 189 .StripTrailingSeparators() |
| 174 .BaseName() | 190 .BaseName() |
| 175 .AsUTF8Unsafe(); | 191 .AsUTF8Unsafe(); |
| 176 DCHECK(!config_name.empty()); | 192 DCHECK(!config_name.empty()); |
| 177 | 193 |
| 178 std::string::size_type separator = config_name.find('-'); | 194 std::string::size_type separator = config_name.find('-'); |
| 179 if (separator != std::string::npos) | 195 if (separator != std::string::npos) |
| 180 config_name = config_name.substr(0, separator); | 196 config_name = config_name.substr(0, separator); |
| 181 | 197 |
| 182 std::vector<const Target*> targets; | 198 std::vector<const Target*> targets; |
| 183 std::vector<const Target*> all_targets = builder->GetAllResolvedTargets(); | 199 std::vector<const Target*> all_targets = builder->GetAllResolvedTargets(); |
| 184 if (!XcodeWriter::FilterTargets(build_settings, all_targets, | 200 if (!XcodeWriter::FilterTargets(build_settings, all_targets, |
| 185 dir_filters_string, &targets, err)) { | 201 dir_filters_string, &targets, err)) { |
| 186 return false; | 202 return false; |
| 187 } | 203 } |
| 188 | 204 |
| 189 XcodeWriter workspace(workspace_name); | 205 XcodeWriter workspace(workspace_name); |
| 190 workspace.CreateProductsProject(targets, attributes, source_path, config_name, | 206 workspace.CreateProductsProject(targets, attributes, source_path, config_name, |
| 191 root_target_name, ninja_extra_args, | 207 root_target_name, ninja_extra_args, |
| 192 build_settings, target_os); | 208 build_settings); |
| 193 | 209 |
| 194 workspace.CreateSourcesProject(all_targets, build_settings->build_dir(), | 210 workspace.CreateSourcesProject(all_targets, build_settings->build_dir(), |
| 195 attributes, source_path, config_name, | 211 attributes, source_path, config_name); |
| 196 target_os); | |
| 197 | 212 |
| 198 return workspace.WriteFiles(build_settings, err); | 213 return workspace.WriteFiles(build_settings, err); |
| 199 } | 214 } |
| 200 | 215 |
| 201 XcodeWriter::XcodeWriter(const std::string& name) : name_(name) { | 216 XcodeWriter::XcodeWriter(const std::string& name) : name_(name) { |
| 202 if (name_.empty()) | 217 if (name_.empty()) |
| 203 name_.assign("all"); | 218 name_.assign("all"); |
| 204 } | 219 } |
| 205 | 220 |
| 206 XcodeWriter::~XcodeWriter() {} | 221 XcodeWriter::~XcodeWriter() {} |
| 207 | 222 |
| 208 // static | 223 // static |
| 224 bool XcodeWriter::GetProjectsAttributes(const BuildSettings* build_settings, | |
| 225 PBXAttributes* attributes, | |
| 226 Err* err) { | |
| 227 Settings* null_settings = nullptr; | |
|
sdefresne
2016/06/14 17:45:10
I'm not sure about this code. Previously the code
| |
| 228 Scope global_scope(null_settings); | |
| 229 Scope::KeyValueMap declared_arguments; | |
| 230 build_settings->build_args().MergeDeclaredArguments(&declared_arguments); | |
| 231 for (const auto& pair : declared_arguments) { | |
| 232 global_scope.SetValue(pair.first, pair.second, nullptr); | |
| 233 } | |
| 234 build_settings->build_args().SetupRootScope(&global_scope, | |
| 235 Scope::KeyValueMap()); | |
| 236 | |
| 237 std::string target_os; | |
| 238 if (!GetTargetOs(&global_scope, &target_os, err)) | |
| 239 return false; | |
| 240 | |
| 241 std::string target_cpu; | |
| 242 if (!GetTargetCpu(&global_scope, &target_cpu, err)) | |
| 243 return false; | |
| 244 | |
| 245 if (target_os == "ios") { | |
| 246 std::string deployment_target; | |
| 247 if (!GetDeploymentTarget(&global_scope, "ios_deployment_target", | |
| 248 &deployment_target, err)) | |
| 249 return false; | |
| 250 | |
| 251 attributes->insert(std::make_pair("SDKROOT", "iphoneos")); | |
| 252 attributes->insert(std::make_pair("TARGETED_DEVICE_FAMILY", "1,2")); | |
| 253 attributes->insert( | |
| 254 std::make_pair("IPHONEOS_DEPLOYMENT_TARGET", deployment_target)); | |
| 255 } else { | |
| 256 std::string deployment_target; | |
| 257 if (!GetDeploymentTarget(&global_scope, "mac_deployment_target", | |
| 258 &deployment_target, err)) | |
| 259 return false; | |
| 260 | |
| 261 attributes->insert(std::make_pair("ARCHS", target_cpu)); | |
| 262 attributes->insert(std::make_pair("SDKROOT", "macosx")); | |
| 263 attributes->insert( | |
| 264 std::make_pair("MACOSX_DEPLOYMENT_TARGET", deployment_target)); | |
| 265 } | |
| 266 | |
| 267 return true; | |
| 268 } | |
| 269 | |
| 270 // static | |
| 209 bool XcodeWriter::FilterTargets(const BuildSettings* build_settings, | 271 bool XcodeWriter::FilterTargets(const BuildSettings* build_settings, |
| 210 const std::vector<const Target*>& all_targets, | 272 const std::vector<const Target*>& all_targets, |
| 211 const std::string& dir_filters_string, | 273 const std::string& dir_filters_string, |
| 212 std::vector<const Target*>* targets, | 274 std::vector<const Target*>* targets, |
| 213 Err* err) { | 275 Err* err) { |
| 214 // Filter targets according to the semicolon-delimited list of label patterns, | 276 // Filter targets according to the semicolon-delimited list of label patterns, |
| 215 // if defined, first. | 277 // if defined, first. |
| 216 targets->reserve(all_targets.size()); | 278 targets->reserve(all_targets.size()); |
| 217 if (dir_filters_string.empty()) { | 279 if (dir_filters_string.empty()) { |
| 218 *targets = all_targets; | 280 *targets = all_targets; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 259 return true; | 321 return true; |
| 260 } | 322 } |
| 261 | 323 |
| 262 void XcodeWriter::CreateProductsProject( | 324 void XcodeWriter::CreateProductsProject( |
| 263 const std::vector<const Target*>& targets, | 325 const std::vector<const Target*>& targets, |
| 264 const PBXAttributes& attributes, | 326 const PBXAttributes& attributes, |
| 265 const std::string& source_path, | 327 const std::string& source_path, |
| 266 const std::string& config_name, | 328 const std::string& config_name, |
| 267 const std::string& root_target, | 329 const std::string& root_target, |
| 268 const std::string& ninja_extra_args, | 330 const std::string& ninja_extra_args, |
| 269 const BuildSettings* build_settings, | 331 const BuildSettings* build_settings) { |
| 270 TargetOsType target_os) { | |
| 271 std::unique_ptr<PBXProject> main_project( | 332 std::unique_ptr<PBXProject> main_project( |
| 272 new PBXProject("products", config_name, source_path, attributes)); | 333 new PBXProject("products", config_name, source_path, attributes)); |
| 273 | 334 |
| 274 std::string build_path; | 335 std::string build_path; |
| 275 std::unique_ptr<base::Environment> env(base::Environment::Create()); | 336 std::unique_ptr<base::Environment> env(base::Environment::Create()); |
| 276 env->GetVar("PATH", &build_path); | 337 env->GetVar("PATH", &build_path); |
| 277 | 338 |
| 278 main_project->AddAggregateTarget( | 339 main_project->AddAggregateTarget( |
| 279 "All", GetBuildScript(root_target, build_path, ninja_extra_args)); | 340 "All", GetBuildScript(root_target, build_path, ninja_extra_args)); |
| 280 | 341 |
| 342 const auto iter = attributes.find("SDKROOT"); | |
| 343 const bool skip_executable_targets = | |
| 344 iter != attributes.end() && iter->second == "iphoneos"; | |
| 345 | |
| 281 for (const Target* target : targets) { | 346 for (const Target* target : targets) { |
| 282 switch (target->output_type()) { | 347 switch (target->output_type()) { |
| 283 case Target::EXECUTABLE: | 348 case Target::EXECUTABLE: |
| 284 if (target_os == XcodeWriter::WRITER_TARGET_OS_IOS) | 349 if (skip_executable_targets) |
| 285 continue; | 350 continue; |
| 286 | 351 |
| 287 main_project->AddNativeTarget( | 352 main_project->AddNativeTarget( |
| 288 target->label().name(), "compiled.mach-o.executable", | 353 target->label().name(), "compiled.mach-o.executable", |
| 289 target->output_name().empty() ? target->label().name() | 354 target->output_name().empty() ? target->label().name() |
| 290 : target->output_name(), | 355 : target->output_name(), |
| 291 "com.apple.product-type.tool", | 356 "com.apple.product-type.tool", |
| 292 GetBuildScript(target->label().name(), build_path, | 357 GetBuildScript(target->label().name(), build_path, |
| 293 ninja_extra_args)); | 358 ninja_extra_args)); |
| 294 break; | 359 break; |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 314 } | 379 } |
| 315 | 380 |
| 316 projects_.push_back(std::move(main_project)); | 381 projects_.push_back(std::move(main_project)); |
| 317 } | 382 } |
| 318 | 383 |
| 319 void XcodeWriter::CreateSourcesProject( | 384 void XcodeWriter::CreateSourcesProject( |
| 320 const std::vector<const Target*>& targets, | 385 const std::vector<const Target*>& targets, |
| 321 const SourceDir& root_build_dir, | 386 const SourceDir& root_build_dir, |
| 322 const PBXAttributes& attributes, | 387 const PBXAttributes& attributes, |
| 323 const std::string& source_path, | 388 const std::string& source_path, |
| 324 const std::string& config_name, | 389 const std::string& config_name) { |
| 325 TargetOsType target_os) { | |
| 326 std::vector<SourceFile> sources; | 390 std::vector<SourceFile> sources; |
| 327 for (const Target* target : targets) { | 391 for (const Target* target : targets) { |
| 328 if (!target->settings()->is_default()) | 392 if (!target->settings()->is_default()) |
| 329 continue; | 393 continue; |
| 330 | 394 |
| 331 for (const SourceFile& source : target->sources()) { | 395 for (const SourceFile& source : target->sources()) { |
| 332 if (source.is_system_absolute()) | 396 if (source.is_system_absolute()) |
| 333 continue; | 397 continue; |
| 334 | 398 |
| 335 if (IsStringInOutputDir(root_build_dir, source.value())) | 399 if (IsStringInOutputDir(root_build_dir, source.value())) |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 425 for (const auto& object : pair.second) { | 489 for (const auto& object : pair.second) { |
| 426 object->Print(out, 2); | 490 object->Print(out, 2); |
| 427 } | 491 } |
| 428 out << "/* End " << ToString(pair.first) << " section */\n"; | 492 out << "/* End " << ToString(pair.first) << " section */\n"; |
| 429 } | 493 } |
| 430 | 494 |
| 431 out << "\t};\n" | 495 out << "\t};\n" |
| 432 << "\trootObject = " << project->Reference() << ";\n" | 496 << "\trootObject = " << project->Reference() << ";\n" |
| 433 << "}\n"; | 497 << "}\n"; |
| 434 } | 498 } |
| OLD | NEW |