cmGlobalNMakeMakefileGenerator.cxx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file LICENSE.rst or https://cmake.org/licensing for details. */
  3. #include "cmGlobalNMakeMakefileGenerator.h"
  4. #include <ostream>
  5. #include <cmext/algorithm>
  6. #include <cmext/string_view>
  7. #include "cmsys/RegularExpression.hxx"
  8. #include "cmDuration.h"
  9. #include "cmGlobalGenerator.h"
  10. #include "cmMakefile.h"
  11. #include "cmMessageType.h"
  12. #include "cmState.h"
  13. #include "cmStringAlgorithms.h"
  14. #include "cmSystemTools.h"
  15. #include "cmake.h"
  16. cmGlobalNMakeMakefileGenerator::cmGlobalNMakeMakefileGenerator(cmake* cm)
  17. : cmGlobalUnixMakefileGenerator3(cm)
  18. {
  19. this->FindMakeProgramFile = "CMakeNMakeFindMake.cmake";
  20. this->ForceUnixPaths = false;
  21. this->ToolSupportsColor = true;
  22. this->UseLinkScript = false;
  23. cm->GetState()->SetWindowsShell(true);
  24. cm->GetState()->SetNMake(true);
  25. this->DefineWindowsNULL = true;
  26. this->PassMakeflags = true;
  27. this->UnixCD = false;
  28. this->MakeSilentFlag = "/nologo";
  29. // nmake breaks on '!' in long-line dependencies
  30. this->ToolSupportsLongLineDependencies = false;
  31. }
  32. void cmGlobalNMakeMakefileGenerator::EnableLanguage(
  33. std::vector<std::string> const& l, cmMakefile* mf, bool optional)
  34. {
  35. // pick a default
  36. mf->AddDefinition("CMAKE_GENERATOR_CC", "cl");
  37. mf->AddDefinition("CMAKE_GENERATOR_CXX", "cl");
  38. this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
  39. }
  40. bool cmGlobalNMakeMakefileGenerator::FindMakeProgram(cmMakefile* mf)
  41. {
  42. if (!this->cmGlobalGenerator::FindMakeProgram(mf)) {
  43. return false;
  44. }
  45. if (cmValue nmakeCommand = mf->GetDefinition("CMAKE_MAKE_PROGRAM")) {
  46. std::vector<std::string> command{ *nmakeCommand, "-?" };
  47. std::string out;
  48. std::string err;
  49. if (!cmSystemTools::RunSingleCommand(command, &out, &err, nullptr, nullptr,
  50. cmSystemTools::OUTPUT_NONE,
  51. cmDuration(30))) {
  52. mf->IssueMessage(MessageType::FATAL_ERROR,
  53. cmStrCat("Running\n '", cmJoin(command, "' '"),
  54. "'\n"
  55. "failed with:\n ",
  56. err));
  57. cmSystemTools::SetFatalErrorOccurred();
  58. return false;
  59. }
  60. cmsys::RegularExpression regex(
  61. "Program Maintenance Utility Version ([1-9][0-9.]+)");
  62. if (regex.find(err)) {
  63. this->NMakeVersion = regex.match(1);
  64. this->CheckNMakeFeatures();
  65. }
  66. }
  67. return true;
  68. }
  69. void cmGlobalNMakeMakefileGenerator::CheckNMakeFeatures()
  70. {
  71. this->NMakeSupportsUTF8 = !cmSystemTools::VersionCompare(
  72. cmSystemTools::OP_LESS, this->NMakeVersion, "9");
  73. }
  74. cmDocumentationEntry cmGlobalNMakeMakefileGenerator::GetDocumentation()
  75. {
  76. return { cmGlobalNMakeMakefileGenerator::GetActualName(),
  77. "Generates NMake makefiles." };
  78. }
  79. void cmGlobalNMakeMakefileGenerator::PrintCompilerAdvice(
  80. std::ostream& os, std::string const& lang, cmValue envVar) const
  81. {
  82. if (lang == "CXX"_s || lang == "C"_s) {
  83. /* clang-format off */
  84. os <<
  85. "To use the NMake generator with Visual C++, cmake must be run from a "
  86. "shell that can use the compiler cl from the command line. This "
  87. "environment is unable to invoke the cl compiler. To fix this problem, "
  88. "run cmake from the Visual Studio Command Prompt (vcvarsall.bat).\n";
  89. /* clang-format on */
  90. }
  91. this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
  92. }
  93. std::vector<cmGlobalGenerator::GeneratedMakeCommand>
  94. cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
  95. std::string const& makeProgram, std::string const& projectName,
  96. std::string const& projectDir, std::vector<std::string> const& targetNames,
  97. std::string const& config, int /*jobs*/, bool verbose,
  98. cmBuildOptions buildOptions, std::vector<std::string> const& makeOptions)
  99. {
  100. std::vector<std::string> nmakeMakeOptions;
  101. // Since we have full control over the invocation of nmake, let us
  102. // make it quiet.
  103. nmakeMakeOptions.push_back(this->MakeSilentFlag);
  104. cm::append(nmakeMakeOptions, makeOptions);
  105. return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
  106. makeProgram, projectName, projectDir, targetNames, config,
  107. cmake::NO_BUILD_PARALLEL_LEVEL, verbose, buildOptions, nmakeMakeOptions);
  108. }
  109. void cmGlobalNMakeMakefileGenerator::PrintBuildCommandAdvice(std::ostream& os,
  110. int jobs) const
  111. {
  112. if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
  113. // nmake does not support parallel build level
  114. // see https://msdn.microsoft.com/en-us/library/afyyse50.aspx
  115. os << "Warning: NMake does not support parallel builds. "
  116. "Ignoring parallel build command line option.\n";
  117. }
  118. this->cmGlobalUnixMakefileGenerator3::PrintBuildCommandAdvice(
  119. os, cmake::NO_BUILD_PARALLEL_LEVEL);
  120. }