summaryrefslogtreecommitdiffstats
path: root/Source/cmGlobalNMakeMakefileGenerator.cxx
blob: eabacf6b1e6329ceb954c51ef30b0497b1fe2fed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
#include "cmGlobalNMakeMakefileGenerator.h"

#include <ostream>

#include <cmext/algorithm>

#include "cmsys/RegularExpression.hxx"

#include "cmDocumentationEntry.h"
#include "cmDuration.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmState.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmake.h"

cmGlobalNMakeMakefileGenerator::cmGlobalNMakeMakefileGenerator(cmake* cm)
  : cmGlobalUnixMakefileGenerator3(cm)
{
  this->FindMakeProgramFile = "CMakeNMakeFindMake.cmake";
  this->ForceUnixPaths = false;
  this->ToolSupportsColor = true;
  this->UseLinkScript = false;
  cm->GetState()->SetWindowsShell(true);
  cm->GetState()->SetNMake(true);
  this->DefineWindowsNULL = true;
  this->PassMakeflags = true;
  this->UnixCD = false;
  this->MakeSilentFlag = "/nologo";
  // nmake breaks on '!' in long-line dependencies
  this->ToolSupportsLongLineDependencies = false;
}

void cmGlobalNMakeMakefileGenerator::EnableLanguage(
  std::vector<std::string> const& l, cmMakefile* mf, bool optional)
{
  // pick a default
  mf->AddDefinition("CMAKE_GENERATOR_CC", "cl");
  mf->AddDefinition("CMAKE_GENERATOR_CXX", "cl");
  this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
}

bool cmGlobalNMakeMakefileGenerator::FindMakeProgram(cmMakefile* mf)
{
  if (!this->cmGlobalGenerator::FindMakeProgram(mf)) {
    return false;
  }
  if (cmValue nmakeCommand = mf->GetDefinition("CMAKE_MAKE_PROGRAM")) {
    std::vector<std::string> command{ *nmakeCommand, "-?" };
    std::string out;
    std::string err;
    if (!cmSystemTools::RunSingleCommand(command, &out, &err, nullptr, nullptr,
                                         cmSystemTools::OUTPUT_NONE,
                                         cmDuration(30))) {
      mf->IssueMessage(MessageType::FATAL_ERROR,
                       cmStrCat("Running\n '", cmJoin(command, "' '"),
                                "'\n"
                                "failed with:\n ",
                                err));
      cmSystemTools::SetFatalErrorOccurred();
      return false;
    }
    cmsys::RegularExpression regex(
      "Program Maintenance Utility Version ([1-9][0-9.]+)");
    if (regex.find(err)) {
      this->NMakeVersion = regex.match(1);
      this->CheckNMakeFeatures();
    }
  }
  return true;
}

void cmGlobalNMakeMakefileGenerator::CheckNMakeFeatures()
{
  this->NMakeSupportsUTF8 = !cmSystemTools::VersionCompare(
    cmSystemTools::OP_LESS, this->NMakeVersion, "9");
}

void cmGlobalNMakeMakefileGenerator::GetDocumentation(
  cmDocumentationEntry& entry)
{
  entry.Name = cmGlobalNMakeMakefileGenerator::GetActualName();
  entry.Brief = "Generates NMake makefiles.";
}

void cmGlobalNMakeMakefileGenerator::PrintCompilerAdvice(
  std::ostream& os, std::string const& lang, cmValue envVar) const
{
  if (lang == "CXX" || lang == "C") {
    /* clang-format off */
    os <<
      "To use the NMake generator with Visual C++, cmake must be run from a "
      "shell that can use the compiler cl from the command line. This "
      "environment is unable to invoke the cl compiler. To fix this problem, "
      "run cmake from the Visual Studio Command Prompt (vcvarsall.bat).\n";
    /* clang-format on */
  }
  this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
}

std::vector<cmGlobalGenerator::GeneratedMakeCommand>
cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
  const std::string& makeProgram, const std::string& projectName,
  const std::string& projectDir, std::vector<std::string> const& targetNames,
  const std::string& config, int /*jobs*/, bool verbose,
  const cmBuildOptions& buildOptions,
  std::vector<std::string> const& makeOptions)
{
  std::vector<std::string> nmakeMakeOptions;

  // Since we have full control over the invocation of nmake, let us
  // make it quiet.
  nmakeMakeOptions.push_back(this->MakeSilentFlag);
  cm::append(nmakeMakeOptions, makeOptions);

  return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
    makeProgram, projectName, projectDir, targetNames, config,
    cmake::NO_BUILD_PARALLEL_LEVEL, verbose, buildOptions, nmakeMakeOptions);
}

void cmGlobalNMakeMakefileGenerator::PrintBuildCommandAdvice(std::ostream& os,
                                                             int jobs) const
{
  if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
    // nmake does not support parallel build level
    // see https://msdn.microsoft.com/en-us/library/afyyse50.aspx

    /* clang-format off */
    os <<
      "Warning: NMake does not support parallel builds. "
      "Ignoring parallel build command line option.\n";
    /* clang-format on */
  }

  this->cmGlobalUnixMakefileGenerator3::PrintBuildCommandAdvice(
    os, cmake::NO_BUILD_PARALLEL_LEVEL);
}