1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 file Copyright.txt or https://cmake.org/licensing for details. */ 3 #pragma once 4 5 #include "cmConfigure.h" // IWYU pragma: keep 6 7 #include <iosfwd> 8 #include <map> 9 #include <memory> 10 #include <set> 11 #include <string> 12 #include <unordered_map> 13 #include <unordered_set> 14 #include <utility> 15 #include <vector> 16 17 #include <cm/optional> 18 19 #include "cm_codecvt.hxx" 20 21 #include "cmGeneratedFileStream.h" 22 #include "cmGlobalCommonGenerator.h" 23 #include "cmGlobalGeneratorFactory.h" 24 #include "cmNinjaTypes.h" 25 #include "cmPolicies.h" 26 #include "cmStringAlgorithms.h" 27 #include "cmTransformDepfile.h" 28 29 class cmCustomCommand; 30 class cmGeneratorTarget; 31 class cmLinkLineComputer; 32 class cmLocalGenerator; 33 class cmMakefile; 34 class cmOutputConverter; 35 class cmStateDirectory; 36 class cmake; 37 struct cmDocumentationEntry; 38 39 /** 40 * \class cmGlobalNinjaGenerator 41 * \brief Write a build.ninja file. 42 * 43 * The main differences between this generator and the UnixMakefile 44 * generator family are: 45 * - We don't care about VERBOSE variable or RULE_MESSAGES property since 46 * it is handle by Ninja's -v option. 47 * - We don't care about computing any progress status since Ninja manages 48 * it itself. 49 * - We generate one build.ninja and one rules.ninja per project. 50 * - We try to minimize the number of generated rules: one per target and 51 * language. 52 * - We use Ninja special variable $in and $out to produce nice output. 53 * - We extensively use Ninja variable overloading system to minimize the 54 * number of generated rules. 55 */ 56 class cmGlobalNinjaGenerator : public cmGlobalCommonGenerator 57 { 58 public: 59 /// The default name of Ninja's build file. Typically: build.ninja. 60 static const char* NINJA_BUILD_FILE; 61 62 /// The default name of Ninja's rules file. Typically: rules.ninja. 63 /// It is included in the main build.ninja file. 64 static const char* NINJA_RULES_FILE; 65 66 /// The indentation string used when generating Ninja's build file. 67 static const char* INDENT; 68 69 /// The shell command used for a no-op. 70 static std::string const SHELL_NOOP; 71 72 /// Write @a count times INDENT level to output stream @a os. 73 static void Indent(std::ostream& os, int count); 74 75 /// Write a divider in the given output stream @a os. 76 static void WriteDivider(std::ostream& os); 77 78 static std::string EncodeRuleName(std::string const& name); 79 std::string EncodeLiteral(const std::string& lit); 80 std::string EncodePath(const std::string& path); 81 82 std::unique_ptr<cmLinkLineComputer> CreateLinkLineComputer( 83 cmOutputConverter* outputConverter, 84 cmStateDirectory const& stateDir) const override; 85 86 /** 87 * Write the given @a comment to the output stream @a os. It 88 * handles new line character properly. 89 */ 90 static void WriteComment(std::ostream& os, const std::string& comment); 91 92 /** 93 * Utilized by the generator factory to determine if this generator 94 * supports toolsets. 95 */ SupportsToolset()96 static bool SupportsToolset() { return false; } 97 98 /** 99 * Utilized by the generator factory to determine if this generator 100 * supports platforms. 101 */ SupportsPlatform()102 static bool SupportsPlatform() { return false; } 103 IsIPOSupported()104 bool IsIPOSupported() const override { return true; } 105 106 /** 107 * Write a build statement @a build to @a os. 108 * @warning no escaping of any kind is done here. 109 */ 110 void WriteBuild(std::ostream& os, cmNinjaBuild const& build, 111 int cmdLineLimit = 0, bool* usedResponseFile = nullptr); 112 113 class CCOutputs 114 { 115 cmGlobalNinjaGenerator* GG; 116 117 public: CCOutputs(cmGlobalNinjaGenerator * gg)118 CCOutputs(cmGlobalNinjaGenerator* gg) 119 : GG(gg) 120 { 121 } 122 void Add(std::vector<std::string> const& outputs); 123 cmNinjaDeps ExplicitOuts; 124 cmNinjaDeps WorkDirOuts; 125 }; 126 127 void WriteCustomCommandBuild(std::string const& command, 128 std::string const& description, 129 std::string const& comment, 130 std::string const& depfile, 131 std::string const& pool, bool uses_terminal, 132 bool restat, std::string const& config, 133 CCOutputs outputs, 134 cmNinjaDeps explicitDeps = cmNinjaDeps(), 135 cmNinjaDeps orderOnlyDeps = cmNinjaDeps()); 136 137 void WriteMacOSXContentBuild(std::string input, std::string output, 138 const std::string& config); 139 140 /** 141 * Write a rule statement to @a os. 142 * @warning no escaping of any kind is done here. 143 */ 144 static void WriteRule(std::ostream& os, cmNinjaRule const& rule); 145 146 /** 147 * Write a variable named @a name to @a os with value @a value and an 148 * optional @a comment. An @a indent level can be specified. 149 * @warning no escaping of any kind is done here. 150 */ 151 static void WriteVariable(std::ostream& os, const std::string& name, 152 const std::string& value, 153 const std::string& comment = "", int indent = 0); 154 155 /** 156 * Write an include statement including @a filename with an optional 157 * @a comment to the @a os stream. 158 */ 159 static void WriteInclude(std::ostream& os, const std::string& filename, 160 const std::string& comment = ""); 161 162 /** 163 * Write a default target statement specifying @a targets as 164 * the default targets. 165 */ 166 static void WriteDefault(std::ostream& os, const cmNinjaDeps& targets, 167 const std::string& comment = ""); 168 IsGCCOnWindows()169 bool IsGCCOnWindows() const { return this->UsingGCCOnWindows; } 170 171 cmGlobalNinjaGenerator(cmake* cm); 172 NewFactory()173 static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory() 174 { 175 return std::unique_ptr<cmGlobalGeneratorFactory>( 176 new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaGenerator>()); 177 } 178 179 std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( 180 cmMakefile* mf) override; 181 GetName()182 std::string GetName() const override 183 { 184 return cmGlobalNinjaGenerator::GetActualName(); 185 } 186 GetActualName()187 static std::string GetActualName() { return "Ninja"; } 188 IsNinja()189 bool IsNinja() const override { return true; } 190 191 /** Get encoding used by generator for ninja files */ 192 codecvt::Encoding GetMakefileEncoding() const override; 193 194 static void GetDocumentation(cmDocumentationEntry& entry); 195 196 void EnableLanguage(std::vector<std::string> const& languages, 197 cmMakefile* mf, bool optional) override; 198 199 std::vector<GeneratedMakeCommand> GenerateBuildCommand( 200 const std::string& makeProgram, const std::string& projectName, 201 const std::string& projectDir, std::vector<std::string> const& targetNames, 202 const std::string& config, bool fast, int jobs, bool verbose, 203 std::vector<std::string> const& makeOptions = 204 std::vector<std::string>()) override; 205 206 // Setup target names GetAllTargetName()207 const char* GetAllTargetName() const override { return "all"; } GetInstallTargetName()208 const char* GetInstallTargetName() const override { return "install"; } GetInstallLocalTargetName()209 const char* GetInstallLocalTargetName() const override 210 { 211 return "install/local"; 212 } GetInstallStripTargetName()213 const char* GetInstallStripTargetName() const override 214 { 215 return "install/strip"; 216 } GetTestTargetName()217 const char* GetTestTargetName() const override { return "test"; } GetPackageTargetName()218 const char* GetPackageTargetName() const override { return "package"; } GetPackageSourceTargetName()219 const char* GetPackageSourceTargetName() const override 220 { 221 return "package_source"; 222 } GetRebuildCacheTargetName()223 const char* GetRebuildCacheTargetName() const override 224 { 225 return "rebuild_cache"; 226 } GetCleanTargetName()227 const char* GetCleanTargetName() const override { return "clean"; } 228 SupportsCustomCommandDepfile()229 bool SupportsCustomCommandDepfile() const override { return true; } DepfileFormat()230 cm::optional<cmDepfileFormat> DepfileFormat() const override 231 { 232 return cmDepfileFormat::GccDepfile; 233 } 234 GetImplFileStream(const std::string &)235 virtual cmGeneratedFileStream* GetImplFileStream( 236 const std::string& /*config*/) const 237 { 238 return this->BuildFileStream.get(); 239 } 240 GetConfigFileStream(const std::string &)241 virtual cmGeneratedFileStream* GetConfigFileStream( 242 const std::string& /*config*/) const 243 { 244 return this->BuildFileStream.get(); 245 } 246 GetDefaultFileStream()247 virtual cmGeneratedFileStream* GetDefaultFileStream() const 248 { 249 return this->BuildFileStream.get(); 250 } 251 GetCommonFileStream()252 virtual cmGeneratedFileStream* GetCommonFileStream() const 253 { 254 return this->BuildFileStream.get(); 255 } 256 GetRulesFileStream()257 cmGeneratedFileStream* GetRulesFileStream() const 258 { 259 return this->RulesFileStream.get(); 260 } 261 262 std::string const& ConvertToNinjaPath(const std::string& path) const; 263 std::string ConvertToNinjaAbsPath(std::string path) const; 264 265 struct MapToNinjaPathImpl 266 { 267 cmGlobalNinjaGenerator* GG; MapToNinjaPathImplMapToNinjaPathImpl268 MapToNinjaPathImpl(cmGlobalNinjaGenerator* gg) 269 : GG(gg) 270 { 271 } operatorMapToNinjaPathImpl272 std::string operator()(std::string const& path) const 273 { 274 return this->GG->ConvertToNinjaPath(path); 275 } 276 }; MapToNinjaPath()277 MapToNinjaPathImpl MapToNinjaPath() { return { this }; } 278 279 // -- Additional clean files 280 void AddAdditionalCleanFile(std::string fileName, const std::string& config); GetAdditionalCleanTargetName()281 const char* GetAdditionalCleanTargetName() const 282 { 283 return "CMakeFiles/clean.additional"; 284 } 285 GetByproductsForCleanTargetName()286 static const char* GetByproductsForCleanTargetName() 287 { 288 return "CMakeFiles/cmake_byproducts_for_clean_target"; 289 } 290 291 void AddCXXCompileCommand(const std::string& commandLine, 292 const std::string& sourceFile); 293 294 /** 295 * Add a rule to the generated build system. 296 * Call WriteRule() behind the scene but perform some check before like: 297 * - Do not add twice the same rule. 298 */ 299 void AddRule(cmNinjaRule const& rule); 300 301 bool HasRule(const std::string& name); 302 303 void AddCustomCommandRule(); 304 void AddMacOSXContentRule(); 305 HasCustomCommandOutput(const std::string & output)306 bool HasCustomCommandOutput(const std::string& output) 307 { 308 return this->CustomCommandOutputs.find(output) != 309 this->CustomCommandOutputs.end(); 310 } 311 312 /// Called when we have seen the given custom command. Returns true 313 /// if we has seen it before. SeenCustomCommand(cmCustomCommand const * cc,const std::string & config)314 bool SeenCustomCommand(cmCustomCommand const* cc, const std::string& config) 315 { 316 return !this->Configs[config].CustomCommands.insert(cc).second; 317 } 318 319 /// Called when we have seen the given custom command output. SeenCustomCommandOutput(const std::string & output)320 void SeenCustomCommandOutput(const std::string& output) 321 { 322 this->CustomCommandOutputs.insert(output); 323 // We don't need the assumed dependencies anymore, because we have 324 // an output. 325 this->AssumedSourceDependencies.erase(output); 326 } 327 AddAssumedSourceDependencies(const std::string & source,const cmNinjaDeps & deps)328 void AddAssumedSourceDependencies(const std::string& source, 329 const cmNinjaDeps& deps) 330 { 331 std::set<std::string>& ASD = this->AssumedSourceDependencies[source]; 332 // Because we may see the same source file multiple times (same source 333 // specified in multiple targets), compute the union of any assumed 334 // dependencies. 335 ASD.insert(deps.begin(), deps.end()); 336 } 337 338 virtual std::string OrderDependsTargetForTarget( 339 cmGeneratorTarget const* target, const std::string& config) const; 340 341 void AppendTargetOutputs(cmGeneratorTarget const* target, 342 cmNinjaDeps& outputs, const std::string& config, 343 cmNinjaTargetDepends depends) const; 344 void AppendTargetDepends(cmGeneratorTarget const* target, 345 cmNinjaDeps& outputs, const std::string& config, 346 const std::string& fileConfig, 347 cmNinjaTargetDepends depends); 348 void AppendTargetDependsClosure(cmGeneratorTarget const* target, 349 cmNinjaDeps& outputs, 350 const std::string& config, 351 const std::string& fileConfig, 352 bool genexOutput); 353 void AppendTargetDependsClosure(cmGeneratorTarget const* target, 354 cmNinjaOuts& outputs, 355 const std::string& config, 356 const std::string& fileConfig, 357 bool genexOutput, bool omit_self); 358 359 void AppendDirectoryForConfig(const std::string& prefix, 360 const std::string& config, 361 const std::string& suffix, 362 std::string& dir) override; 363 AppendNinjaFileArgument(GeneratedMakeCommand &,const std::string &)364 virtual void AppendNinjaFileArgument(GeneratedMakeCommand& /*command*/, 365 const std::string& /*config*/) const 366 { 367 } 368 AddRebuildManifestOutputs(cmNinjaDeps & outputs)369 virtual void AddRebuildManifestOutputs(cmNinjaDeps& outputs) const 370 { 371 outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE)); 372 } 373 GetRuleCmdLength(const std::string & name)374 int GetRuleCmdLength(const std::string& name) 375 { 376 return this->RuleCmdLength[name]; 377 } 378 379 void AddTargetAlias(const std::string& alias, cmGeneratorTarget* target, 380 const std::string& config); 381 382 void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override; 383 384 // Ninja generator uses 'deps' and 'msvc_deps_prefix' introduced in 1.3 RequiredNinjaVersion()385 static std::string RequiredNinjaVersion() { return "1.3"; } RequiredNinjaVersionForConsolePool()386 static std::string RequiredNinjaVersionForConsolePool() { return "1.5"; } RequiredNinjaVersionForImplicitOuts()387 static std::string RequiredNinjaVersionForImplicitOuts() { return "1.7"; } RequiredNinjaVersionForManifestRestat()388 static std::string RequiredNinjaVersionForManifestRestat() { return "1.8"; } RequiredNinjaVersionForMultilineDepfile()389 static std::string RequiredNinjaVersionForMultilineDepfile() 390 { 391 return "1.9"; 392 } RequiredNinjaVersionForDyndeps()393 static std::string RequiredNinjaVersionForDyndeps() { return "1.10"; } RequiredNinjaVersionForRestatTool()394 static std::string RequiredNinjaVersionForRestatTool() { return "1.10"; } RequiredNinjaVersionForUnconditionalRecompactTool()395 static std::string RequiredNinjaVersionForUnconditionalRecompactTool() 396 { 397 return "1.10"; 398 } RequiredNinjaVersionForMultipleOutputs()399 static std::string RequiredNinjaVersionForMultipleOutputs() 400 { 401 return "1.10"; 402 } RequiredNinjaVersionForMetadataOnRegeneration()403 static std::string RequiredNinjaVersionForMetadataOnRegeneration() 404 { 405 return "1.10.2"; 406 } RequiredNinjaVersionForCodePage()407 static std::string RequiredNinjaVersionForCodePage() { return "1.11"; } 408 bool SupportsDirectConsole() const override; 409 bool SupportsImplicitOuts() const; 410 bool SupportsManifestRestat() const; 411 bool SupportsMultilineDepfile() const; 412 413 std::string NinjaOutputPath(std::string const& path) const; HasOutputPathPrefix()414 bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); } 415 void StripNinjaOutputPathPrefixAsSuffix(std::string& path); 416 417 bool WriteDyndepFile( 418 std::string const& dir_top_src, std::string const& dir_top_bld, 419 std::string const& dir_cur_src, std::string const& dir_cur_bld, 420 std::string const& arg_dd, std::vector<std::string> const& arg_ddis, 421 std::string const& module_dir, 422 std::vector<std::string> const& linked_target_dirs, 423 std::string const& arg_lang, std::string const& arg_modmapfmt); 424 BuildAlias(const std::string & alias,const std::string &)425 virtual std::string BuildAlias(const std::string& alias, 426 const std::string& /*config*/) const 427 { 428 return alias; 429 } 430 ConfigDirectory(const std::string &)431 virtual std::string ConfigDirectory(const std::string& /*config*/) const 432 { 433 return ""; 434 } 435 GetByproductsForCleanTarget()436 cmNinjaDeps& GetByproductsForCleanTarget() 437 { 438 return this->ByproductsForCleanTarget; 439 } 440 GetByproductsForCleanTarget(const std::string & config)441 cmNinjaDeps& GetByproductsForCleanTarget(const std::string& config) 442 { 443 return this->Configs[config].ByproductsForCleanTarget; 444 } 445 446 bool EnableCrossConfigBuild() const; 447 448 std::set<std::string> GetCrossConfigs(const std::string& config) const; 449 GetDefaultConfigs()450 const std::set<std::string>& GetDefaultConfigs() const 451 { 452 return this->DefaultConfigs; 453 } 454 GetPerConfigUtilityTargets()455 const std::set<std::string>& GetPerConfigUtilityTargets() const 456 { 457 return this->PerConfigUtilityTargets; 458 } 459 AddPerConfigUtilityTarget(const std::string & name)460 void AddPerConfigUtilityTarget(const std::string& name) 461 { 462 this->PerConfigUtilityTargets.insert(name); 463 } 464 465 bool IsSingleConfigUtility(cmGeneratorTarget const* target) const; 466 467 bool CheckCxxModuleSupport(); 468 469 protected: 470 void Generate() override; 471 CheckALLOW_DUPLICATE_CUSTOM_TARGETS()472 bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const override { return true; } 473 474 virtual bool OpenBuildFileStreams(); 475 virtual void CloseBuildFileStreams(); 476 477 bool OpenFileStream(std::unique_ptr<cmGeneratedFileStream>& stream, 478 const std::string& name); 479 480 static cm::optional<std::set<std::string>> ListSubsetWithAll( 481 const std::set<std::string>& all, const std::set<std::string>& defaults, 482 const std::vector<std::string>& items); 483 484 std::set<std::string> CrossConfigs; 485 std::set<std::string> DefaultConfigs; 486 std::string DefaultFileConfig; 487 488 private: 489 bool FindMakeProgram(cmMakefile* mf) override; 490 void CheckNinjaFeatures(); 491 void CheckNinjaCodePage(); 492 bool CheckLanguages(std::vector<std::string> const& languages, 493 cmMakefile* mf) const override; 494 bool CheckFortran(cmMakefile* mf) const; 495 bool CheckISPC(cmMakefile* mf) const; 496 497 void CloseCompileCommandsStream(); 498 499 bool OpenRulesFileStream(); 500 void CloseRulesFileStream(); 501 void CleanMetaData(); 502 503 /// Write the common disclaimer text at the top of each build file. 504 void WriteDisclaimer(std::ostream& os) const; 505 506 void WriteAssumedSourceDependencies(); 507 508 void WriteTargetAliases(std::ostream& os); 509 void WriteFolderTargets(std::ostream& os); 510 void WriteUnknownExplicitDependencies(std::ostream& os); 511 512 void WriteBuiltinTargets(std::ostream& os); 513 void WriteTargetDefault(std::ostream& os); 514 void WriteTargetRebuildManifest(std::ostream& os); 515 bool WriteTargetCleanAdditional(std::ostream& os); 516 void WriteTargetClean(std::ostream& os); 517 void WriteTargetHelp(std::ostream& os); 518 519 void ComputeTargetDependsClosure( 520 cmGeneratorTarget const* target, 521 std::set<cmGeneratorTarget const*>& depends); 522 523 std::string CMakeCmd() const; 524 std::string NinjaCmd() const; 525 526 /// The file containing the build statement. (the relationship of the 527 /// compilation DAG). 528 std::unique_ptr<cmGeneratedFileStream> BuildFileStream; 529 /// The file containing the rule statements. (The action attached to each 530 /// edge of the compilation DAG). 531 std::unique_ptr<cmGeneratedFileStream> RulesFileStream; 532 std::unique_ptr<cmGeneratedFileStream> CompileCommandsStream; 533 534 /// The set of rules added to the generated build system. 535 std::unordered_set<std::string> Rules; 536 537 /// Length of rule command, used by rsp file evaluation 538 std::unordered_map<std::string, int> RuleCmdLength; 539 540 bool UsingGCCOnWindows = false; 541 542 /// The set of custom command outputs we have seen. 543 std::set<std::string> CustomCommandOutputs; 544 545 /// Whether we are collecting known build outputs and needed 546 /// dependencies to determine unknown dependencies. 547 bool ComputingUnknownDependencies = false; 548 cmPolicies::PolicyStatus PolicyCMP0058 = cmPolicies::WARN; 549 550 /// The combined explicit dependencies of custom build commands 551 std::set<std::string> CombinedCustomCommandExplicitDependencies; 552 553 /// When combined with CombinedCustomCommandExplicitDependencies it allows 554 /// us to detect the set of explicit dependencies that have 555 std::set<std::string> CombinedBuildOutputs; 556 557 /// The mapping from source file to assumed dependencies. 558 std::map<std::string, std::set<std::string>> AssumedSourceDependencies; 559 560 /// Utility targets which have per-config outputs 561 std::set<std::string> PerConfigUtilityTargets; 562 563 struct TargetAlias 564 { 565 cmGeneratorTarget* GeneratorTarget; 566 std::string Config; 567 }; 568 using TargetAliasMap = std::map<std::string, TargetAlias>; 569 TargetAliasMap TargetAliases; 570 TargetAliasMap DefaultTargetAliases; 571 572 /// the local cache for calls to ConvertToNinjaPath 573 mutable std::unordered_map<std::string, std::string> ConvertToNinjaPathCache; 574 575 std::string NinjaCommand; 576 std::string NinjaVersion; 577 bool NinjaSupportsConsolePool = false; 578 bool NinjaSupportsImplicitOuts = false; 579 bool NinjaSupportsManifestRestat = false; 580 bool NinjaSupportsMultilineDepfile = false; 581 bool NinjaSupportsDyndeps = false; 582 bool NinjaSupportsRestatTool = false; 583 bool NinjaSupportsUnconditionalRecompactTool = false; 584 bool NinjaSupportsMultipleOutputs = false; 585 bool NinjaSupportsMetadataOnRegeneration = false; 586 bool NinjaSupportsCodePage = false; 587 588 codecvt::Encoding NinjaExpectedEncoding = codecvt::None; 589 590 bool DiagnosedCxxModuleSupport = false; 591 592 void InitOutputPathPrefix(); 593 594 std::string OutputPathPrefix; 595 std::string TargetAll; 596 std::string CMakeCacheFile; 597 bool DisableCleandead = false; 598 599 struct ByConfig 600 { 601 std::set<std::string> AdditionalCleanFiles; 602 603 /// The set of custom commands we have seen. 604 std::set<cmCustomCommand const*> CustomCommands; 605 606 struct TargetDependsClosureKey 607 { 608 cmGeneratorTarget const* Target; 609 std::string Config; 610 bool GenexOutput; 611 }; 612 613 std::map<TargetDependsClosureKey, cmNinjaOuts> TargetDependsClosures; 614 615 TargetAliasMap TargetAliases; 616 617 cmNinjaDeps ByproductsForCleanTarget; 618 }; 619 std::map<std::string, ByConfig> Configs; 620 621 cmNinjaDeps ByproductsForCleanTarget; 622 623 friend bool operator==(const ByConfig::TargetDependsClosureKey& lhs, 624 const ByConfig::TargetDependsClosureKey& rhs); 625 friend bool operator!=(const ByConfig::TargetDependsClosureKey& lhs, 626 const ByConfig::TargetDependsClosureKey& rhs); 627 friend bool operator<(const ByConfig::TargetDependsClosureKey& lhs, 628 const ByConfig::TargetDependsClosureKey& rhs); 629 friend bool operator>(const ByConfig::TargetDependsClosureKey& lhs, 630 const ByConfig::TargetDependsClosureKey& rhs); 631 friend bool operator<=(const ByConfig::TargetDependsClosureKey& lhs, 632 const ByConfig::TargetDependsClosureKey& rhs); 633 friend bool operator>=(const ByConfig::TargetDependsClosureKey& lhs, 634 const ByConfig::TargetDependsClosureKey& rhs); 635 }; 636 637 class cmGlobalNinjaMultiGenerator : public cmGlobalNinjaGenerator 638 { 639 public: 640 /// The default name of Ninja's common file. Typically: common.ninja. 641 static const char* NINJA_COMMON_FILE; 642 /// The default file extension to use for per-config Ninja files. 643 static const char* NINJA_FILE_EXTENSION; 644 645 cmGlobalNinjaMultiGenerator(cmake* cm); IsMultiConfig()646 bool IsMultiConfig() const override { return true; } NewFactory()647 static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory() 648 { 649 return std::unique_ptr<cmGlobalGeneratorFactory>( 650 new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaMultiGenerator>()); 651 } 652 653 static void GetDocumentation(cmDocumentationEntry& entry); 654 GetName()655 std::string GetName() const override 656 { 657 return cmGlobalNinjaMultiGenerator::GetActualName(); 658 } 659 GetActualName()660 static std::string GetActualName() { return "Ninja Multi-Config"; } 661 BuildAlias(const std::string & alias,const std::string & config)662 std::string BuildAlias(const std::string& alias, 663 const std::string& config) const override 664 { 665 if (config.empty()) { 666 return alias; 667 } 668 return cmStrCat(alias, ":", config); 669 } 670 ConfigDirectory(const std::string & config)671 std::string ConfigDirectory(const std::string& config) const override 672 { 673 if (!config.empty()) { 674 return cmStrCat('/', config); 675 } 676 return ""; 677 } 678 GetCMakeCFGIntDir()679 const char* GetCMakeCFGIntDir() const override { return "${CONFIGURATION}"; } 680 681 std::string ExpandCFGIntDir(const std::string& str, 682 const std::string& config) const override; 683 GetImplFileStream(const std::string & config)684 cmGeneratedFileStream* GetImplFileStream( 685 const std::string& config) const override 686 { 687 return this->ImplFileStreams.at(config).get(); 688 } 689 GetConfigFileStream(const std::string & config)690 cmGeneratedFileStream* GetConfigFileStream( 691 const std::string& config) const override 692 { 693 return this->ConfigFileStreams.at(config).get(); 694 } 695 GetDefaultFileStream()696 cmGeneratedFileStream* GetDefaultFileStream() const override 697 { 698 return this->DefaultFileStream.get(); 699 } 700 GetCommonFileStream()701 cmGeneratedFileStream* GetCommonFileStream() const override 702 { 703 return this->CommonFileStream.get(); 704 } 705 706 void AppendNinjaFileArgument(GeneratedMakeCommand& command, 707 const std::string& config) const override; 708 709 static std::string GetNinjaImplFilename(const std::string& config); 710 static std::string GetNinjaConfigFilename(const std::string& config); 711 712 void AddRebuildManifestOutputs(cmNinjaDeps& outputs) const override; 713 714 void GetQtAutoGenConfigs(std::vector<std::string>& configs) const override; 715 716 bool InspectConfigTypeVariables() override; 717 718 std::string GetDefaultBuildConfig() const override; 719 SupportsDefaultBuildType()720 bool SupportsDefaultBuildType() const override { return true; } SupportsCrossConfigs()721 bool SupportsCrossConfigs() const override { return true; } SupportsDefaultConfigs()722 bool SupportsDefaultConfigs() const override { return true; } 723 724 std::string OrderDependsTargetForTarget( 725 cmGeneratorTarget const* target, const std::string& config) const override; 726 727 protected: 728 bool OpenBuildFileStreams() override; 729 void CloseBuildFileStreams() override; 730 731 private: 732 std::map<std::string, std::unique_ptr<cmGeneratedFileStream>> 733 ImplFileStreams; 734 std::map<std::string, std::unique_ptr<cmGeneratedFileStream>> 735 ConfigFileStreams; 736 std::unique_ptr<cmGeneratedFileStream> CommonFileStream; 737 std::unique_ptr<cmGeneratedFileStream> DefaultFileStream; 738 }; 739