cmLocalUnixMakefileGenerator3.cxx 73.6 KB
Newer Older
1 2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
Ken Martin's avatar
Ken Martin committed
3 4
#include "cmLocalUnixMakefileGenerator3.h"

5 6
#include "cmsys/FStream.hxx"
#include "cmsys/Terminal.h"
7 8 9 10 11 12
#include <algorithm>
#include <functional>
#include <sstream>
#include <stdio.h>
#include <utility>

13
#include "cmAlgorithms.h"
14
#include "cmCustomCommand.h"
15 16
#include "cmCustomCommandGenerator.h"
#include "cmFileTimeComparison.h"
Ken Martin's avatar
Ken Martin committed
17
#include "cmGeneratedFileStream.h"
18 19
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
20
#include "cmGlobalUnixMakefileGenerator3.h"
21
#include "cmLocalGenerator.h"
Ken Martin's avatar
Ken Martin committed
22
#include "cmMakefile.h"
23
#include "cmMakefileTargetGenerator.h"
24
#include "cmOutputConverter.h"
25
#include "cmRulePlaceholderExpander.h"
Ken Martin's avatar
Ken Martin committed
26
#include "cmSourceFile.h"
27 28
#include "cmState.h"
#include "cmStateDirectory.h"
29
#include "cmStateSnapshot.h"
30
#include "cmStateTypes.h"
31
#include "cmSystemTools.h"
32
#include "cmVersion.h"
33
#include "cm_auto_ptr.hxx"
34
#include "cmake.h"
Ken Martin's avatar
Ken Martin committed
35 36 37 38 39

// Include dependency scanners for supported languages.  Only the
// C/C++ scanner is needed for bootstrapping CMake.
#include "cmDependsC.h"
#ifdef CMAKE_BUILD_WITH_CMAKE
40 41
#include "cmDependsFortran.h"
#include "cmDependsJava.h"
Ken Martin's avatar
Ken Martin committed
42 43
#endif

44 45 46 47
// Escape special characters in Makefile dependency lines
class cmMakeSafe
{
public:
48 49 50 51 52 53 54 55 56
  cmMakeSafe(const char* s)
    : Data(s)
  {
  }
  cmMakeSafe(std::string const& s)
    : Data(s.c_str())
  {
  }

57 58
private:
  const char* Data;
59 60 61 62 63 64 65 66 67 68
  friend std::ostream& operator<<(std::ostream& os, cmMakeSafe const& self)
  {
    for (const char* c = self.Data; *c; ++c) {
      switch (*c) {
        case '=':
          os << "$(EQUALS)";
          break;
        default:
          os << *c;
          break;
69 70
      }
    }
71 72
    return os;
  }
73 74
};

75 76 77 78
// Helper function used below.
static std::string cmSplitExtension(std::string const& in, std::string& base)
{
  std::string ext;
79
  std::string::size_type dot_pos = in.rfind('.');
80
  if (dot_pos != std::string::npos) {
81
    // Remove the extension first in case &base == &in.
82
    ext = in.substr(dot_pos);
83
    base = in.substr(0, dot_pos);
84
  } else {
85
    base = in;
86
  }
87 88 89
  return ext;
}

90 91
cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3(
  cmGlobalGenerator* gg, cmMakefile* mf)
92
  : cmLocalCommonGenerator(gg, mf, mf->GetCurrentBinaryDirectory())
Ken Martin's avatar
Ken Martin committed
93
{
Ken Martin's avatar
Ken Martin committed
94
  this->MakefileVariableSize = 0;
95
  this->ColorMakefile = false;
96 97
  this->SkipPreprocessedSourceRules = false;
  this->SkipAssemblySourceRules = false;
98
  this->MakeCommandEscapeTargetTwice = false;
99
  this->BorlandMakeCurlyHack = false;
Ken Martin's avatar
Ken Martin committed
100 101 102 103 104 105
}

cmLocalUnixMakefileGenerator3::~cmLocalUnixMakefileGenerator3()
{
}

106
void cmLocalUnixMakefileGenerator3::Generate()
Ken Martin's avatar
Ken Martin committed
107
{
108
  // Record whether some options are enabled to avoid checking many
109
  // times later.
110
  if (!this->GetGlobalGenerator()->GetCMakeInstance()->GetIsInTryCompile()) {
111
    this->ColorMakefile = this->Makefile->IsOn("CMAKE_COLOR_MAKEFILE");
112
  }
113 114 115 116
  this->SkipPreprocessedSourceRules =
    this->Makefile->IsOn("CMAKE_SKIP_PREPROCESSED_SOURCE_RULES");
  this->SkipAssemblySourceRules =
    this->Makefile->IsOn("CMAKE_SKIP_ASSEMBLY_SOURCE_RULES");
117

Ken Martin's avatar
Ken Martin committed
118
  // Generate the rule files for each target.
119
  const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
120 121
  cmGlobalUnixMakefileGenerator3* gg =
    static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
122
  for (std::vector<cmGeneratorTarget*>::const_iterator t = targets.begin();
123
       t != targets.end(); ++t) {
124
    if ((*t)->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
125
      continue;
126
    }
127
    CM_AUTO_PTR<cmMakefileTargetGenerator> tg(
128
      cmMakefileTargetGenerator::New(*t));
129
    if (tg.get()) {
130
      tg->WriteRuleFiles();
131
      gg->RecordTargetProgress(tg.get());
Ken Martin's avatar
Ken Martin committed
132
    }
133
  }
Ken Martin's avatar
Ken Martin committed
134

Ken Martin's avatar
Ken Martin committed
135 136
  // write the local Makefile
  this->WriteLocalMakefile();
137

Ken Martin's avatar
Ken Martin committed
138 139
  // Write the cmake file with information for this directory.
  this->WriteDirectoryInformationFile();
140 141
}

142 143 144 145
void cmLocalUnixMakefileGenerator3::ComputeHomeRelativeOutputPath()
{
  // Compute the path to use when referencing the current output
  // directory from the top output directory.
146
  this->HomeRelativeOutputPath = this->MaybeConvertToRelativePath(
147
    this->GetBinaryDirectory(), this->GetCurrentBinaryDirectory());
148
  if (this->HomeRelativeOutputPath == ".") {
149
    this->HomeRelativeOutputPath = "";
150 151
  }
  if (!this->HomeRelativeOutputPath.empty()) {
152
    this->HomeRelativeOutputPath += "/";
153
  }
154 155
}

156
void cmLocalUnixMakefileGenerator3::ComputeObjectFilenames(
157 158
  std::map<cmSourceFile const*, std::string>& mapping,
  cmGeneratorTarget const* gt)
159
{
160 161
  // Determine if these object files should use a custom extension
  char const* custom_ext = gt->GetCustomObjectExtension();
162 163 164
  for (std::map<cmSourceFile const*, std::string>::iterator si =
         mapping.begin();
       si != mapping.end(); ++si) {
165
    cmSourceFile const* sf = si->first;
166 167 168
    bool keptSourceExtension;
    si->second = this->GetObjectFileNameWithoutTarget(
      *sf, gt->ObjectDirectory, &keptSourceExtension, custom_ext);
169
  }
170 171
}

172 173
void cmLocalUnixMakefileGenerator3::GetLocalObjectFiles(
  std::map<std::string, LocalObjectInfo>& localObjectFiles)
174
{
175 176
  const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
  for (std::vector<cmGeneratorTarget*>::const_iterator ti = targets.begin();
177
       ti != targets.end(); ++ti) {
178
    cmGeneratorTarget* gt = *ti;
179
    if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
180
      continue;
181
    }
182
    std::vector<cmSourceFile const*> objectSources;
183 184
    gt->GetObjectSources(
      objectSources, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
185
    // Compute full path to object file directory for this target.
186
    std::string dir;
187
    dir += gt->LocalGenerator->GetCurrentBinaryDirectory();
188
    dir += "/";
189
    dir += this->GetTargetDirectory(gt);
190
    dir += "/";
191
    // Compute the name of each object file.
192 193
    for (std::vector<cmSourceFile const*>::iterator si = objectSources.begin();
         si != objectSources.end(); ++si) {
194
      cmSourceFile const* sf = *si;
195
      bool hasSourceExtension = true;
196 197 198
      std::string objectName =
        this->GetObjectFileNameWithoutTarget(*sf, dir, &hasSourceExtension);
      if (cmSystemTools::FileIsFullPath(objectName.c_str())) {
199
        objectName = cmSystemTools::GetFilenameName(objectName);
200
      }
201 202
      LocalObjectInfo& info = localObjectFiles[objectName];
      info.HasSourceExtension = hasSourceExtension;
203
      info.push_back(LocalObjectEntry(gt, sf->GetLanguage()));
204
    }
205
  }
206 207
}

208 209
void cmLocalUnixMakefileGenerator3::GetIndividualFileTargets(
  std::vector<std::string>& targets)
210
{
211 212
  std::map<std::string, LocalObjectInfo> localObjectFiles;
  this->GetLocalObjectFiles(localObjectFiles);
213
  for (std::map<std::string, LocalObjectInfo>::iterator lo =
214
         localObjectFiles.begin();
215
       lo != localObjectFiles.end(); ++lo) {
216 217 218 219
    targets.push_back(lo->first);

    std::string::size_type dot_pos = lo->first.rfind(".");
    std::string base = lo->first.substr(0, dot_pos);
220
    if (lo->second.HasPreprocessRule) {
221
      targets.push_back(base + ".i");
222
    }
223

224
    if (lo->second.HasAssembleRule) {
225 226
      targets.push_back(base + ".s");
    }
227
  }
228 229
}

230 231 232 233 234 235 236 237
void cmLocalUnixMakefileGenerator3::WriteLocalMakefile()
{
  // generate the includes
  std::string ruleFileName = "Makefile";

  // Open the rule file.  This should be copy-if-different because the
  // rules may depend on this file itself.
  std::string ruleFileNameFull = this->ConvertToFullPath(ruleFileName);
238 239 240
  cmGeneratedFileStream ruleFileStream(
    ruleFileNameFull.c_str(), false,
    this->GlobalGenerator->GetMakefileEncoding());
241
  if (!ruleFileStream) {
242
    return;
243
  }
244
  // always write the top makefile
245
  if (!this->IsRootMakefile()) {
246
    ruleFileStream.SetCopyIfDifferent(true);
247
  }
248

249 250
  // write the all rules
  this->WriteLocalAllRules(ruleFileStream);
251

252 253
  // only write local targets unless at the top Keep track of targets already
  // listed.
254
  std::set<std::string> emittedTargets;
255
  if (!this->IsRootMakefile()) {
256 257
    // write our targets, and while doing it collect up the object
    // file rules
258 259 260
    this->WriteLocalMakefileTargets(ruleFileStream, emittedTargets);
  } else {
    cmGlobalUnixMakefileGenerator3* gg =
Ken Martin's avatar
Ken Martin committed
261
      static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
262 263
    gg->WriteConvenienceRules(ruleFileStream, emittedTargets);
  }
264

265 266
  bool do_preprocess_rules = this->GetCreatePreprocessedSourceRules();
  bool do_assembly_rules = this->GetCreateAssemblySourceRules();
267

268 269 270
  std::map<std::string, LocalObjectInfo> localObjectFiles;
  this->GetLocalObjectFiles(localObjectFiles);

271 272
  // now write out the object rules
  // for each object file name
273
  for (std::map<std::string, LocalObjectInfo>::iterator lo =
274
         localObjectFiles.begin();
275
       lo != localObjectFiles.end(); ++lo) {
276
    // Add a convenience rule for building the object file.
277 278 279
    this->WriteObjectConvenienceRule(ruleFileStream,
                                     "target to build an object file",
                                     lo->first.c_str(), lo->second);
280

281 282
    // Check whether preprocessing and assembly rules make sense.
    // They make sense only for C and C++ sources.
283 284 285
    bool lang_has_preprocessor = false;
    bool lang_has_assembly = false;

286 287 288
    for (std::vector<LocalObjectEntry>::const_iterator ei = lo->second.begin();
         ei != lo->second.end(); ++ei) {
      if (ei->Language == "C" || ei->Language == "CXX" ||
289 290
          ei->Language == "CUDA" || ei->Language == "Fortran") {
        // Right now, C, C++, Fortran and CUDA have both a preprocessor and the
291 292 293
        // ability to generate assembly code
        lang_has_preprocessor = true;
        lang_has_assembly = true;
294
        break;
295
      }
296
    }
297

298
    // Add convenience rules for preprocessed and assembly files.
299
    if (lang_has_preprocessor && do_preprocess_rules) {
300 301
      std::string::size_type dot_pos = lo->first.rfind(".");
      std::string base = lo->first.substr(0, dot_pos);
302 303 304
      this->WriteObjectConvenienceRule(ruleFileStream,
                                       "target to preprocess a source file",
                                       (base + ".i").c_str(), lo->second);
305
      lo->second.HasPreprocessRule = true;
306
    }
307

308
    if (lang_has_assembly && do_assembly_rules) {
309 310 311
      std::string::size_type dot_pos = lo->first.rfind(".");
      std::string base = lo->first.substr(0, dot_pos);
      this->WriteObjectConvenienceRule(
312 313
        ruleFileStream, "target to generate assembly for a file",
        (base + ".s").c_str(), lo->second);
314
      lo->second.HasAssembleRule = true;
315
    }
316
  }
317 318

  // add a help target as long as there isn;t a real target named help
319 320
  if (emittedTargets.insert("help").second) {
    cmGlobalUnixMakefileGenerator3* gg =
Ken Martin's avatar
Ken Martin committed
321
      static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
322 323
    gg->WriteHelpRule(ruleFileStream, this);
  }
324 325 326

  this->WriteSpecialTargetsBottom(ruleFileStream);
}
Ken Martin's avatar
Ken Martin committed
327

328 329 330
void cmLocalUnixMakefileGenerator3::WriteObjectConvenienceRule(
  std::ostream& ruleFileStream, const char* comment, const char* output,
  LocalObjectInfo const& info)
331
{
332 333 334 335
  // If the rule includes the source file extension then create a
  // version that has the extension removed.  The help should include
  // only the version without source extension.
  bool inHelp = true;
336
  if (info.HasSourceExtension) {
337 338 339 340 341 342 343 344 345 346 347 348 349
    // Remove the last extension.  This should be kept.
    std::string outBase1 = output;
    std::string outExt1 = cmSplitExtension(outBase1, outBase1);

    // Now remove the source extension and put back the last
    // extension.
    std::string outNoExt;
    cmSplitExtension(outBase1, outNoExt);
    outNoExt += outExt1;

    // Add a rule to drive the rule below.
    std::vector<std::string> depends;
    depends.push_back(output);
350
    std::vector<std::string> no_commands;
Daniel Pfeifer's avatar
Daniel Pfeifer committed
351 352
    this->WriteMakeRule(ruleFileStream, CM_NULLPTR, outNoExt, depends,
                        no_commands, true, true);
353
    inHelp = false;
354
  }
355

356 357
  // Recursively make the rule for each target using the object file.
  std::vector<std::string> commands;
358 359 360
  for (std::vector<LocalObjectEntry>::const_iterator t = info.begin();
       t != info.end(); ++t) {
    std::string tgtMakefileName = this->GetRelativeTargetDirectory(t->Target);
361 362 363 364 365
    std::string targetName = tgtMakefileName;
    tgtMakefileName += "/build.make";
    targetName += "/";
    targetName += output;
    commands.push_back(
366 367 368
      this->GetRecursiveMakeCall(tgtMakefileName.c_str(), targetName));
  }
  this->CreateCDCommand(commands, this->GetBinaryDirectory(),
369
                        this->GetCurrentBinaryDirectory());
370 371 372

  // Write the rule to the makefile.
  std::vector<std::string> no_depends;
373 374
  this->WriteMakeRule(ruleFileStream, comment, output, no_depends, commands,
                      true, inHelp);
375 376
}

377 378
void cmLocalUnixMakefileGenerator3::WriteLocalMakefileTargets(
  std::ostream& ruleFileStream, std::set<std::string>& emitted)
Ken Martin's avatar
Ken Martin committed
379
{
380 381 382 383 384
  std::vector<std::string> depends;
  std::vector<std::string> commands;

  // for each target we just provide a rule to cd up to the top and do a make
  // on the target
385
  const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
386
  std::string localName;
387
  for (std::vector<cmGeneratorTarget*>::const_iterator t = targets.begin();
388
       t != targets.end(); ++t) {
389 390 391 392 393 394
    if (((*t)->GetType() == cmStateEnums::EXECUTABLE) ||
        ((*t)->GetType() == cmStateEnums::STATIC_LIBRARY) ||
        ((*t)->GetType() == cmStateEnums::SHARED_LIBRARY) ||
        ((*t)->GetType() == cmStateEnums::MODULE_LIBRARY) ||
        ((*t)->GetType() == cmStateEnums::OBJECT_LIBRARY) ||
        ((*t)->GetType() == cmStateEnums::UTILITY)) {
395
      emitted.insert((*t)->GetName());
396 397

      // for subdirs add a rule to build this specific target by name.
398
      localName = this->GetRelativeTargetDirectory(*t);
399 400 401
      localName += "/rule";
      commands.clear();
      depends.clear();
402

403
      // Build the target for this pass.
404 405
      std::string makefile2 = cmake::GetCMakeFilesDirectoryPostSlash();
      makefile2 += "Makefile2";
406 407 408
      commands.push_back(
        this->GetRecursiveMakeCall(makefile2.c_str(), localName));
      this->CreateCDCommand(commands, this->GetBinaryDirectory(),
409
                            this->GetCurrentBinaryDirectory());
410
      this->WriteMakeRule(ruleFileStream, "Convenience name for target.",
Stephen Kelly's avatar
Stephen Kelly committed
411
                          localName, depends, commands, true);
412

413
      // Add a target with the canonical name (no prefix, suffix or path).
414
      if (localName != (*t)->GetName()) {
415 416 417
        commands.clear();
        depends.push_back(localName);
        this->WriteMakeRule(ruleFileStream, "Convenience name for target.",
418
                            (*t)->GetName(), depends, commands, true);
419
      }
420 421

      // Add a fast rule to build the target
422
      std::string makefileName = this->GetRelativeTargetDirectory(*t);
423
      makefileName += "/build.make";
424
      // make sure the makefile name is suitable for a makefile
425
      std::string makeTargetName = this->GetRelativeTargetDirectory(*t);
426
      makeTargetName += "/build";
427
      localName = (*t)->GetName();
428 429 430
      localName += "/fast";
      depends.clear();
      commands.clear();
431 432 433
      commands.push_back(
        this->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName));
      this->CreateCDCommand(commands, this->GetBinaryDirectory(),
434
                            this->GetCurrentBinaryDirectory());
435
      this->WriteMakeRule(ruleFileStream, "fast build rule for target.",
Stephen Kelly's avatar
Stephen Kelly committed
436
                          localName, depends, commands, true);
437 438 439

      // Add a local name for the rule to relink the target before
      // installation.
440
      if ((*t)->NeedRelinkBeforeInstall(this->ConfigName)) {
441
        makeTargetName = this->GetRelativeTargetDirectory(*t);
442
        makeTargetName += "/preinstall";
443
        localName = (*t)->GetName();
444 445 446
        localName += "/preinstall";
        depends.clear();
        commands.clear();
447 448 449
        commands.push_back(
          this->GetRecursiveMakeCall(makefile2.c_str(), makeTargetName));
        this->CreateCDCommand(commands, this->GetBinaryDirectory(),
450
                              this->GetCurrentBinaryDirectory());
451 452
        this->WriteMakeRule(ruleFileStream,
                            "Manual pre-install relink rule for target.",
Stephen Kelly's avatar
Stephen Kelly committed
453
                            localName, depends, commands, true);
Ken Martin's avatar
Ken Martin committed
454 455
      }
    }
456
  }
Ken Martin's avatar
Ken Martin committed
457 458
}

Ken Martin's avatar
Ken Martin committed
459
void cmLocalUnixMakefileGenerator3::WriteDirectoryInformationFile()
Ken Martin's avatar
Ken Martin committed
460
{
461
  std::string infoFileName = this->GetCurrentBinaryDirectory();
462 463
  infoFileName += cmake::GetCMakeFilesDirectory();
  infoFileName += "/CMakeDirectoryInformation.cmake";
Ken Martin's avatar
Ken Martin committed
464 465 466

  // Open the output file.
  cmGeneratedFileStream infoFileStream(infoFileName.c_str());
467
  if (!infoFileStream) {
Ken Martin's avatar
Ken Martin committed
468
    return;
469
  }
Ken Martin's avatar
Ken Martin committed
470

471
  infoFileStream.SetCopyIfDifferent(true);
Ken Martin's avatar
Ken Martin committed
472 473 474
  // Write the do not edit header.
  this->WriteDisclaimer(infoFileStream);

475
  // Setup relative path conversion tops.
476
  /* clang-format off */
477 478
  infoFileStream
    << "# Relative path conversion top directories.\n"
479
    << "set(CMAKE_RELATIVE_PATH_TOP_SOURCE \""
480
    << this->StateSnapshot.GetDirectory().GetRelativePathTopSource()
481
    << "\")\n"
482
    << "set(CMAKE_RELATIVE_PATH_TOP_BINARY \""
483
    << this->StateSnapshot.GetDirectory().GetRelativePathTopBinary()
484 485
    << "\")\n"
    << "\n";
486
  /* clang-format on */
487

Ken Martin's avatar
Ken Martin committed
488
  // Tell the dependency scanner to use unix paths if necessary.
489
  if (cmSystemTools::GetForceUnixPaths()) {
490
    /* clang-format off */
Ken Martin's avatar
Ken Martin committed
491 492
    infoFileStream
      << "# Force unix paths in dependencies.\n"
493
      << "set(CMAKE_FORCE_UNIX_PATHS 1)\n"
Ken Martin's avatar
Ken Martin committed
494
      << "\n";
495
    /* clang-format on */
496
  }
Ken Martin's avatar
Ken Martin committed
497 498

  // Store the include regular expressions for this directory.
499 500 501 502
  infoFileStream << "\n"
                 << "# The C and CXX include file regular expressions for "
                 << "this directory.\n";
  infoFileStream << "set(CMAKE_C_INCLUDE_REGEX_SCAN ";
Ken Martin's avatar
Ken Martin committed
503
  this->WriteCMakeArgument(infoFileStream,
Ken Martin's avatar
Ken Martin committed
504
                           this->Makefile->GetIncludeRegularExpression());
505 506
  infoFileStream << ")\n";
  infoFileStream << "set(CMAKE_C_INCLUDE_REGEX_COMPLAIN ";
Ken Martin's avatar
Ken Martin committed
507
  this->WriteCMakeArgument(infoFileStream,
Ken Martin's avatar
Ken Martin committed
508
                           this->Makefile->GetComplainRegularExpression());
509
  infoFileStream << ")\n";
Ken Martin's avatar
Ken Martin committed
510
  infoFileStream
511
    << "set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN})\n";
512 513
  infoFileStream << "set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN "
                    "${CMAKE_C_INCLUDE_REGEX_COMPLAIN})\n";
Ken Martin's avatar
Ken Martin committed
514 515
}

516 517
std::string cmLocalUnixMakefileGenerator3::ConvertToFullPath(
  const std::string& localPath)
Ken Martin's avatar
Ken Martin committed
518
{
519
  std::string dir = this->GetCurrentBinaryDirectory();
Ken Martin's avatar
Ken Martin committed
520 521 522 523 524
  dir += "/";
  dir += localPath;
  return dir;
}

525
const std::string& cmLocalUnixMakefileGenerator3::GetHomeRelativeOutputPath()
Ken Martin's avatar
Ken Martin committed
526
{
Ken Martin's avatar
Ken Martin committed
527
  return this->HomeRelativeOutputPath;
Ken Martin's avatar
Ken Martin committed
528 529
}

530 531 532 533
void cmLocalUnixMakefileGenerator3::WriteMakeRule(
  std::ostream& os, const char* comment, const std::string& target,
  const std::vector<std::string>& depends,
  const std::vector<std::string>& commands, bool symbolic, bool in_help)
Ken Martin's avatar
Ken Martin committed
534
{
535
  // Make sure there is a target.
536
  if (target.empty()) {
537 538
    cmSystemTools::Error("No target for WriteMakeRule! called with comment: ",
                         comment);
539
    return;
540
  }
541 542 543 544

  std::string replace;

  // Write the comment describing the rule in the makefile.
545
  if (comment) {
546 547 548
    replace = comment;
    std::string::size_type lpos = 0;
    std::string::size_type rpos;
549 550 551
    while ((rpos = replace.find('\n', lpos)) != std::string::npos) {
      os << "# " << replace.substr(lpos, rpos - lpos) << "\n";
      lpos = rpos + 1;
Ken Martin's avatar
Ken Martin committed
552
    }
553 554
    os << "# " << replace.substr(lpos) << "\n";
  }
555 556

  // Construct the left hand side of the rule.
557
  std::string tgt = cmSystemTools::ConvertToOutputPath(
558 559
    this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), target)
      .c_str());
560

561
  const char* space = "";
562
  if (tgt.size() == 1) {
563 564 565
    // Add a space before the ":" to avoid drive letter confusion on
    // Windows.
    space = " ";
566
  }
567

568
  // Mark the rule as symbolic if requested.
569 570 571
  if (symbolic) {
    if (const char* sym =
          this->Makefile->GetDefinition("CMAKE_MAKE_SYMBOLIC_RULE")) {
572
      os << cmMakeSafe(tgt) << space << ": " << sym << "\n";
573
    }
574
  }
575

576
  // Write the rule.
577
  if (depends.empty()) {
578
    // No dependencies.  The commands will always run.
579
    os << cmMakeSafe(tgt) << space << ":\n";
580
  } else {
581 582
    // Split dependencies into multiple rule lines.  This allows for
    // very long dependency lists even on older make implementations.
583
    std::string binDir = this->GetBinaryDirectory();
584 585
    for (std::vector<std::string>::const_iterator dep = depends.begin();
         dep != depends.end(); ++dep) {
586
      replace = *dep;
587
      replace = cmSystemTools::ConvertToOutputPath(
588
        this->MaybeConvertToRelativePath(binDir, replace).c_str());
589
      os << cmMakeSafe(tgt) << space << ": " << cmMakeSafe(replace) << "\n";
590
    }
591
  }
592

593
  // Write the list of commands.
Stephen Kelly's avatar
Stephen Kelly committed
594
  os << cmWrap("\t", commands, "", "\n") << "\n";
595
  if (symbolic && !this->IsWatcomWMake()) {
596
    os << ".PHONY : " << cmMakeSafe(tgt) << "\n";
597
  }
598
  os << "\n";
599
  // Add the output to the local help if requested.
600
  if (in_help) {
601
    this->LocalHelp.push_back(target);
602
  }
603 604
}

605 606
std::string cmLocalUnixMakefileGenerator3::MaybeConvertWatcomShellCommand(
  std::string const& cmd)
607
{
608
  if (this->IsWatcomWMake() && cmSystemTools::FileIsFullPath(cmd.c_str()) &&
609
      cmd.find_first_of("( )") != std::string::npos) {
610 611 612 613
    // On Watcom WMake use the windows short path for the command
    // name.  This is needed to avoid funny quoting problems on
    // lines with shell redirection operators.
    std::string scmd;
614
    if (cmSystemTools::GetShortPath(cmd, scmd)) {
615
      return this->ConvertToOutputFormat(scmd, cmOutputConverter::SHELL);
616
    }
617
  }
618
  return std::string();
619 620
}

621 622
void cmLocalUnixMakefileGenerator3::WriteMakeVariables(
  std::ostream& makefileStream)
Ken Martin's avatar
Ken Martin committed
623 624
{
  this->WriteDivider(makefileStream);
625 626
  makefileStream << "# Set environment variables for the build.\n"
                 << "\n";
627 628
  cmGlobalUnixMakefileGenerator3* gg =
    static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
629 630 631 632 633 634 635 636 637 638 639
  if (gg->DefineWindowsNULL) {
    makefileStream << "!IF \"$(OS)\" == \"Windows_NT\"\n"
                   << "NULL=\n"
                   << "!ELSE\n"
                   << "NULL=nul\n"
                   << "!ENDIF\n";
  }
  if (this->IsWindowsShell()) {
    makefileStream << "SHELL = cmd.exe\n"
                   << "\n";
  } else {
640
#if !defined(__VMS)
641
    /* clang-format off */
642 643 644 645
      makefileStream
        << "# The shell in which to execute make rules.\n"
        << "SHELL = /bin/sh\n"
        << "\n";
646
/* clang-format on */
647
#endif
648
  }
Ken Martin's avatar
Ken Martin committed
649

650 651 652
  std::string cmakeShellCommand =
    this->MaybeConvertWatcomShellCommand(cmSystemTools::GetCMakeCommand());
  if (cmakeShellCommand.empty()) {
653 654 655
    cmakeShellCommand = this->ConvertToOutputFormat(
      cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()),
      cmOutputConverter::SHELL);
656
  }
657

658
  /* clang-format off */
Ken Martin's avatar
Ken Martin committed
659 660 661
  makefileStream
    << "# The CMake executable.\n"
    << "CMAKE_COMMAND = "
662
    << cmakeShellCommand
663
    << "\n"
Ken Martin's avatar
Ken Martin committed
664 665 666 667
    << "\n";
  makefileStream
    << "# The command to remove a file.\n"
    << "RM = "
668
    << cmakeShellCommand
Ken Martin's avatar
Ken Martin committed
669 670
    << " -E remove -f\n"
    << "\n";
671 672 673 674
  makefileStream
    << "# Escaping for special characters.\n"
    << "EQUALS = =\n"
    << "\n";
Ken Martin's avatar
Ken Martin committed
675 676 677
  makefileStream
    << "# The top-level source directory on which CMake was run.\n"
    << "CMAKE_SOURCE_DIR = "
678 679
    << this->ConvertToOutputFormat(
      cmSystemTools::CollapseFullPath(this->GetSourceDirectory()),
680
                     cmOutputConverter::SHELL)
Ken Martin's avatar
Ken Martin committed
681 682 683 684
    << "\n"
    << "\n";
  makefileStream
    << "# The top-level build directory on which CMake was run.\n"
685
    << "CMAKE_BINARY_DIR = "
686 687
    << this->ConvertToOutputFormat(
      cmSystemTools::CollapseFullPath(this->GetBinaryDirectory()),
688
                     cmOutputConverter::SHELL)
Ken Martin's avatar
Ken Martin committed
689 690
    << "\n"
    << "\n";
691
  /* clang-format on */
Ken Martin's avatar
Ken Martin committed
692 693
}

694 695
void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsTop(
  std::ostream& makefileStream)
Ken Martin's avatar
Ken Martin committed
696 697
{
  this->WriteDivider(makefileStream);
698 699
  makefileStream << "# Special targets provided by cmake.\n"
                 << "\n";
Ken Martin's avatar
Ken Martin committed
700

701 702 703 704 705 706
  std::vector<std::string> no_commands;
  std::vector<std::string> no_depends;

  // Special target to cleanup operation of make tool.
  // This should be the first target except for the default_target in
  // the interface Makefile.
707 708 709
  this->WriteMakeRule(makefileStream,
                      "Disable implicit rules so canonical targets will work.",
                      ".SUFFIXES", no_depends, no_commands, false);
710

711 712
  if (!this->IsNMake() && !this->IsWatcomWMake() &&
      !this->BorlandMakeCurlyHack) {
713
    // turn off RCS and SCCS automatic stuff from gmake
714 715
    makefileStream
      << "# Remove some rules from gmake that .SUFFIXES does not remove.\n"
716
      << "SUFFIXES =\n\n";
717
  }
718 719 720
  // Add a fake suffix to keep HP happy.  Must be max 32 chars for SGI make.
  std::vector<std::string> depends;
  depends.push_back(".hpux_make_needs_suffix_list");
Daniel Pfeifer's avatar
Daniel Pfeifer committed
721 722
  this->WriteMakeRule(makefileStream, CM_NULLPTR, ".SUFFIXES", depends,
                      no_commands, false);
723
  if (this->IsWatcomWMake()) {
724 725 726
    // Switch on WMake feature, if an error or interrupt occurs during
    // makefile processing, the current target being made may be deleted
    // without prompting (the same as command line -e option).
727
    /* clang-format off */
728 729 730 731 732
    makefileStream <<
      "\n"
      ".ERASE\n"
      "\n"
      ;
733
    /* clang-format on */
734 735
  }
  if (this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")) {
736
    /* clang-format off */
737 738 739 740
    makefileStream
      << "# Produce verbose output by default.\n"
      << "VERBOSE = 1\n"
      << "\n";
741
    /* clang-format on */
742 743
  }
  if (this->IsWatcomWMake()) {
744
    /* clang-format off */
745 746 747 748
    makefileStream <<
      "!ifndef VERBOSE\n"
      ".SILENT\n"
      "!endif\n"
749
      "\n"
750
      ;
751
    /* clang-format on */
752
  } else {
753 754 755 756 757 758
    // Write special target to silence make output.  This must be after
    // the default target in case VERBOSE is set (which changes the
    // name).  The setting of CMAKE_VERBOSE_MAKEFILE to ON will cause a
    // "VERBOSE=1" to be added as a make variable which will change the
    // name of this special target.  This gives a make-time choice to
    // the user.
759 760
    this->WriteMakeRule(makefileStream,
                        "Suppress display of executed commands.",
761 762
                        "$(VERBOSE).SILENT", no_depends, no_commands, false);
  }
763

764 765
  // Work-around for makes that drop rules that have no dependencies
  // or commands.
766 767
  cmGlobalUnixMakefileGenerator3* gg =
    static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
768
  std::string hack = gg->GetEmptyRuleHackDepends();
769
  if (!hack.empty()) {
770
    no_depends.push_back(hack);
771
  }
772
  std::string hack_cmd = gg->GetEmptyRuleHackCommand();
773
  if (!hack_cmd.empty()) {
774
    no_commands.push_back(hack_cmd);
775
  }
776

777 778
  // Special symbolic target that never exists to force dependers to
  // run their rules.
779 780
  this->WriteMakeRule(makefileStream, "A target that is always out of date.",
                      "cmake_force", no_depends, no_commands, true);
781

782 783
  // Variables for reference by other rules.
  this->WriteMakeVariables(makefileStream);
Ken Martin's avatar
Ken Martin committed
784 785
}

786 787
void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom(
  std::ostream& makefileStream)
Ken Martin's avatar
Ken Martin committed
788 789
{
  this->WriteDivider(makefileStream);
790 791
  makefileStream << "# Special targets to cleanup operation of make.\n"
                 << "\n";
Ken Martin's avatar
Ken Martin committed
792 793 794 795

  // Write special "cmake_check_build_system" target to run cmake with
  // the --check-build-system flag.
  {
796 797 798 799 800 801
    // Build command to run CMake to check if anything needs regenerating.
    std::string cmakefileName = cmake::GetCMakeFilesDirectoryPostSlash();
    cmakefileName += "Makefile.cmake";
    std::string runRule =
      "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)";
    runRule += " --check-build-system ";
802 803
    runRule +=
      this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL);
804
    runRule += " 0";
805

806 807 808 809 810
    std::vector<std::string> no_depends;
    std::vector<std::string> commands;
    commands.push_back(runRule);
    if (!this->IsRootMakefile()) {
      this->CreateCDCommand(commands, this->GetBinaryDirectory(),
811
                            this->GetCurrentBinaryDirectory());
812
    }
813 814
    this->WriteMakeRule(
      makefileStream, "Special rule to run CMake to check the build system "
Ken Martin's avatar
Ken Martin committed
815 816 817 818
                      "integrity.\n"
                      "No rule that depends on this can have "
                      "commands that come from listfiles\n"
                      "because they might be regenerated.",
819
      "cmake_check_build_system", no_depends, commands, true);
Ken Martin's avatar
Ken Martin committed
820 821 822
  }
}

823 824 825
void cmLocalUnixMakefileGenerator3::WriteConvenienceRule(
  std::ostream& ruleFileStream, const std::string& realTarget,
  const std::string& helpTarget)
Ken Martin's avatar
Ken Martin committed
826 827
{
  // A rule is only needed if the names are different.
828
  if (realTarget != helpTarget) {
Ken Martin's avatar
Ken Martin committed
829 830 831 832 833 834 835 836 837
    // The helper target depends on the real target.
    std::vector<std::string> depends;
    depends.push_back(realTarget);

    // There are no commands.
    std::vector<std::string> no_commands;

    // Write the rule.
    this->WriteMakeRule(ruleFileStream, "Convenience name for target.",
838
                        helpTarget, depends, no_commands, true);
839
  }
Ken Martin's avatar
Ken Martin committed
840 841
}

842 843
std::string cmLocalUnixMakefileGenerator3::GetRelativeTargetDirectory(
  cmGeneratorTarget* target)
Ken Martin's avatar
Ken Martin committed
844
{
845
  std::string dir = this->HomeRelativeOutputPath;
846
  dir += this->GetTargetDirectory(target);
847
  return dir;
848 849
}

Bill Hoffman's avatar