cmCMakeMinimumRequired.cxx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmCMakeMinimumRequired.h"
  4. #include <sstream>
  5. #include <stdio.h>
  6. #include "cmMakefile.h"
  7. #include "cmMessageType.h"
  8. #include "cmSystemTools.h"
  9. #include "cmVersion.h"
  10. class cmExecutionStatus;
  11. // cmCMakeMinimumRequired
  12. bool cmCMakeMinimumRequired::InitialPass(std::vector<std::string> const& args,
  13. cmExecutionStatus&)
  14. {
  15. // Process arguments.
  16. std::string version_string;
  17. bool doing_version = false;
  18. for (std::string const& arg : args) {
  19. if (arg == "VERSION") {
  20. doing_version = true;
  21. } else if (arg == "FATAL_ERROR") {
  22. if (doing_version) {
  23. this->SetError("called with no value for VERSION.");
  24. return false;
  25. }
  26. doing_version = false;
  27. } else if (doing_version) {
  28. doing_version = false;
  29. version_string = arg;
  30. } else {
  31. this->UnknownArguments.push_back(arg);
  32. }
  33. }
  34. if (doing_version) {
  35. this->SetError("called with no value for VERSION.");
  36. return false;
  37. }
  38. // Make sure there was a version to check.
  39. if (version_string.empty()) {
  40. return this->EnforceUnknownArguments(std::string());
  41. }
  42. // Separate the <min> version and any trailing ...<max> component.
  43. std::string::size_type const dd = version_string.find("...");
  44. std::string const version_min = version_string.substr(0, dd);
  45. std::string const version_max = dd != std::string::npos
  46. ? version_string.substr(dd + 3, std::string::npos)
  47. : std::string();
  48. if (dd != std::string::npos &&
  49. (version_min.empty() || version_max.empty())) {
  50. std::ostringstream e;
  51. e << "VERSION \"" << version_string
  52. << "\" does not have a version on both sides of \"...\".";
  53. this->SetError(e.str());
  54. return false;
  55. }
  56. // Save the required version string.
  57. this->Makefile->AddDefinition("CMAKE_MINIMUM_REQUIRED_VERSION",
  58. version_min.c_str());
  59. // Get the current version number.
  60. unsigned int current_major = cmVersion::GetMajorVersion();
  61. unsigned int current_minor = cmVersion::GetMinorVersion();
  62. unsigned int current_patch = cmVersion::GetPatchVersion();
  63. unsigned int current_tweak = cmVersion::GetTweakVersion();
  64. // Parse at least two components of the version number.
  65. // Use zero for those not specified.
  66. unsigned int required_major = 0;
  67. unsigned int required_minor = 0;
  68. unsigned int required_patch = 0;
  69. unsigned int required_tweak = 0;
  70. if (sscanf(version_min.c_str(), "%u.%u.%u.%u", &required_major,
  71. &required_minor, &required_patch, &required_tweak) < 2) {
  72. std::ostringstream e;
  73. e << "could not parse VERSION \"" << version_min << "\".";
  74. this->SetError(e.str());
  75. return false;
  76. }
  77. // Compare the version numbers.
  78. if ((current_major < required_major) ||
  79. (current_major == required_major && current_minor < required_minor) ||
  80. (current_major == required_major && current_minor == required_minor &&
  81. current_patch < required_patch) ||
  82. (current_major == required_major && current_minor == required_minor &&
  83. current_patch == required_patch && current_tweak < required_tweak)) {
  84. // The current version is too low.
  85. std::ostringstream e;
  86. e << "CMake " << version_min
  87. << " or higher is required. You are running version "
  88. << cmVersion::GetCMakeVersion();
  89. this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
  90. cmSystemTools::SetFatalErrorOccured();
  91. return true;
  92. }
  93. // The version is not from the future, so enforce unknown arguments.
  94. if (!this->EnforceUnknownArguments(version_max)) {
  95. return false;
  96. }
  97. if (required_major < 2 || (required_major == 2 && required_minor < 4)) {
  98. this->Makefile->IssueMessage(
  99. MessageType::AUTHOR_WARNING,
  100. "Compatibility with CMake < 2.4 is not supported by CMake >= 3.0.");
  101. this->Makefile->SetPolicyVersion("2.4", version_max);
  102. } else {
  103. this->Makefile->SetPolicyVersion(version_min, version_max);
  104. }
  105. return true;
  106. }
  107. bool cmCMakeMinimumRequired::EnforceUnknownArguments(
  108. std::string const& version_max)
  109. {
  110. if (this->UnknownArguments.empty()) {
  111. return true;
  112. }
  113. // Consider the max version if at least two components were given.
  114. unsigned int max_major = 0;
  115. unsigned int max_minor = 0;
  116. unsigned int max_patch = 0;
  117. unsigned int max_tweak = 0;
  118. if (sscanf(version_max.c_str(), "%u.%u.%u.%u", &max_major, &max_minor,
  119. &max_patch, &max_tweak) >= 2) {
  120. unsigned int current_major = cmVersion::GetMajorVersion();
  121. unsigned int current_minor = cmVersion::GetMinorVersion();
  122. unsigned int current_patch = cmVersion::GetPatchVersion();
  123. unsigned int current_tweak = cmVersion::GetTweakVersion();
  124. if ((current_major < max_major) ||
  125. (current_major == max_major && current_minor < max_minor) ||
  126. (current_major == max_major && current_minor == max_minor &&
  127. current_patch < max_patch) ||
  128. (current_major == max_major && current_minor == max_minor &&
  129. current_patch == max_patch && current_tweak < max_tweak)) {
  130. // A ...<max> version was given that is larger than the current
  131. // version of CMake, so tolerate unknown arguments.
  132. return true;
  133. }
  134. }
  135. std::ostringstream e;
  136. e << "called with unknown argument \"" << this->UnknownArguments[0] << "\".";
  137. this->SetError(e.str());
  138. return false;
  139. }