cmNinjaTargetGenerator.cxx 39.9 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.  */
3
#include "cmNinjaTargetGenerator.h"
4

5 6 7 8 9 10 11 12 13
#include <algorithm>
#include <assert.h>
#include <cm_jsoncpp_value.h>
#include <cm_jsoncpp_writer.h>
#include <iterator>
#include <map>
#include <sstream>
#include <string.h>

14 15 16
#include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h"
#include "cmCustomCommandGenerator.h"
17
#include "cmGeneratedFileStream.h"
18
#include "cmGeneratorExpression.h"
19
#include "cmGeneratorTarget.h"
20
#include "cmGlobalNinjaGenerator.h"
21
#include "cmLocalGenerator.h"
22 23
#include "cmLocalNinjaGenerator.h"
#include "cmMakefile.h"
24 25
#include "cmNinjaNormalTargetGenerator.h"
#include "cmNinjaUtilityTargetGenerator.h"
26
#include "cmOutputConverter.h"
27
#include "cmRulePlaceholderExpander.h"
28
#include "cmSourceFile.h"
29
#include "cmState.h"
30
#include "cmStateTypes.h"
31
#include "cmSystemTools.h"
32
#include "cm_auto_ptr.hxx"
33
#include "cmake.h"
34

35
cmNinjaTargetGenerator* cmNinjaTargetGenerator::New(cmGeneratorTarget* target)
36
{
37
  switch (target->GetType()) {
38 39 40 41 42
    case cmStateEnums::EXECUTABLE:
    case cmStateEnums::SHARED_LIBRARY:
    case cmStateEnums::STATIC_LIBRARY:
    case cmStateEnums::MODULE_LIBRARY:
    case cmStateEnums::OBJECT_LIBRARY:
43 44
      return new cmNinjaNormalTargetGenerator(target);

45 46
    case cmStateEnums::UTILITY:
    case cmStateEnums::GLOBAL_TARGET:
47 48 49
      return new cmNinjaUtilityTargetGenerator(target);

    default:
Daniel Pfeifer's avatar
Daniel Pfeifer committed
50
      return CM_NULLPTR;
51
  }
52 53
}

54
cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmGeneratorTarget* target)
55
  : cmCommonTargetGenerator(target)
Daniel Pfeifer's avatar
Daniel Pfeifer committed
56 57
  , MacOSXContentGenerator(CM_NULLPTR)
  , OSXBundleGenerator(CM_NULLPTR)
58 59 60 61
  , MacContentFolders()
  , LocalGenerator(
      static_cast<cmLocalNinjaGenerator*>(target->GetLocalGenerator()))
  , Objects()
62
{
Peter Kümmel's avatar
Peter Kümmel committed
63
  MacOSXContentGenerator = new MacOSXContentGeneratorType(this);
64 65 66 67
}

cmNinjaTargetGenerator::~cmNinjaTargetGenerator()
{
Nicolas Despres's avatar
Nicolas Despres committed
68
  delete this->MacOSXContentGenerator;
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
}

cmGeneratedFileStream& cmNinjaTargetGenerator::GetBuildFileStream() const
{
  return *this->GetGlobalGenerator()->GetBuildFileStream();
}

cmGeneratedFileStream& cmNinjaTargetGenerator::GetRulesFileStream() const
{
  return *this->GetGlobalGenerator()->GetRulesFileStream();
}

cmGlobalNinjaGenerator* cmNinjaTargetGenerator::GetGlobalGenerator() const
{
  return this->LocalGenerator->GetGlobalNinjaGenerator();
}

86 87 88 89
std::string cmNinjaTargetGenerator::LanguageCompilerRule(
  const std::string& lang) const
{
  return lang + "_COMPILER__" +
90
    cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
91 92
}

93 94 95 96 97 98 99 100 101 102 103 104 105
std::string cmNinjaTargetGenerator::LanguagePreprocessRule(
  std::string const& lang) const
{
  return lang + "_PREPROCESS__" +
    cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
}

bool cmNinjaTargetGenerator::NeedExplicitPreprocessing(
  std::string const& lang) const
{
  return lang == "Fortran";
}

106 107 108 109 110 111 112 113 114 115 116 117
std::string cmNinjaTargetGenerator::LanguageDyndepRule(
  const std::string& lang) const
{
  return lang + "_DYNDEP__" +
    cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
}

bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang) const
{
  return lang == "Fortran";
}

118
std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget()
119 120 121 122
{
  return "cmake_order_depends_target_" + this->GetTargetName();
}

123 124 125 126
// TODO: Most of the code is picked up from
// void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink),
// void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
// Refactor it.
127 128
std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
  cmSourceFile const* source, const std::string& language)
129
{
130
  std::string flags = this->GetFlags(language);
131

132
  // Add Fortran format flags.
133
  if (language == "Fortran") {
134
    this->AppendFortranFormatFlags(flags, *source);
135
  }
136

137
  // Add source file specific flags.
138 139 140 141 142 143 144 145
  if (const char* cflags = source->GetProperty("COMPILE_FLAGS")) {
    std::string config = this->LocalGenerator->GetConfigName();
    cmGeneratorExpression ge;
    CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(cflags);
    const char* evaluatedFlags = cge->Evaluate(this->LocalGenerator, config,
                                               false, this->GeneratorTarget);
    this->LocalGenerator->AppendFlags(flags, evaluatedFlags);
  }
146 147 148 149

  return flags;
}

150 151 152 153
void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags,
                                             std::string const& language)
{
  std::vector<std::string> includes;
154 155
  this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
                                              language, this->GetConfigName());
156
  // Add include directory flags.
157 158
  std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
    includes, this->GeneratorTarget, language,
159
    language == "RC", // full include paths for RC needed by cmcldeps
160
    false, this->GetConfigName());
161
  if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
162
    std::replace(includeFlags.begin(), includeFlags.end(), '\\', '/');
163
  }
164 165 166 167

  this->LocalGenerator->AppendFlags(languageFlags, includeFlags);
}

168
bool cmNinjaTargetGenerator::NeedDepTypeMSVC(const std::string& lang) const
169
{
170 171 172
  return strcmp(this->GetMakefile()->GetSafeDefinition("CMAKE_NINJA_DEPTYPE_" +
                                                       lang),
                "msvc") == 0;
173 174
}

175 176
// TODO: Refactor with
// void cmMakefileTargetGenerator::WriteTargetLanguageFlags().
177 178
std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source,
                                                   const std::string& language)
179
{
180
  std::set<std::string> defines;
181 182
  this->LocalGenerator->AppendDefines(
    defines, source->GetProperty("COMPILE_DEFINITIONS"));
183
  {
184 185 186 187
    std::string defPropName = "COMPILE_DEFINITIONS_";
    defPropName += cmSystemTools::UpperCase(this->GetConfigName());
    this->LocalGenerator->AppendDefines(defines,
                                        source->GetProperty(defPropName));
188 189
  }

190
  std::string definesString = this->GetDefines(language);
191
  this->LocalGenerator->JoinDefines(defines, definesString, language);
192 193

  return definesString;
194 195 196 197 198
}

cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const
{
  // Static libraries never depend on other targets for linking.
199 200
  if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY ||
      this->GeneratorTarget->GetType() == cmStateEnums::OBJECT_LIBRARY) {
201
    return cmNinjaDeps();
202
  }
203 204

  cmComputeLinkInformation* cli =
205
    this->GeneratorTarget->GetLinkInformation(this->GetConfigName());
206
  if (!cli) {
207
    return cmNinjaDeps();
208
  }
209

210
  const std::vector<std::string>& deps = cli->GetDepends();
211 212
  cmNinjaDeps result(deps.size());
  std::transform(deps.begin(), deps.end(), result.begin(), MapToNinjaPath());
213 214

  // Add a dependency on the link definitions file, if any.
215 216 217 218
  if (this->ModuleDefinitionFile) {
    result.push_back(
      this->ConvertToNinjaPath(this->ModuleDefinitionFile->GetFullPath()));
  }
219

220 221 222 223
  // Add a dependency on user-specified manifest files, if any.
  std::vector<cmSourceFile const*> manifest_srcs;
  this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName);
  for (std::vector<cmSourceFile const*>::iterator mi = manifest_srcs.begin();
224
       mi != manifest_srcs.end(); ++mi) {
225
    result.push_back(this->ConvertToNinjaPath((*mi)->GetFullPath()));
226
  }
227

228
  // Add user-specified dependencies.
229
  if (const char* linkDepends =
230
        this->GeneratorTarget->GetProperty("LINK_DEPENDS")) {
231 232 233 234
    std::vector<std::string> linkDeps;
    cmSystemTools::ExpandListArgument(linkDepends, linkDeps);
    std::transform(linkDeps.begin(), linkDeps.end(),
                   std::back_inserter(result), MapToNinjaPath());
235
  }
236

237 238 239
  return result;
}

240 241
std::string cmNinjaTargetGenerator::GetSourceFilePath(
  cmSourceFile const* source) const
242
{
243
  return ConvertToNinjaPath(source->GetFullPath());
244 245
}

246 247
std::string cmNinjaTargetGenerator::GetObjectFilePath(
  cmSourceFile const* source) const
248 249
{
  std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
250
  if (!path.empty()) {
251
    path += "/";
252
  }
253
  std::string const& objectName = this->GeneratorTarget->GetObjectName(source);
254
  path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
255 256
  path += "/";
  path += objectName;
257 258 259
  return path;
}

260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
std::string cmNinjaTargetGenerator::GetPreprocessedFilePath(
  cmSourceFile const* source) const
{
  // Choose an extension to compile already-preprocessed source.
  std::string ppExt = source->GetExtension();
  if (cmHasLiteralPrefix(ppExt, "F")) {
    // Some Fortran compilers automatically enable preprocessing for
    // upper-case extensions.  Since the source is already preprocessed,
    // use a lower-case extension.
    ppExt = cmSystemTools::LowerCase(ppExt);
  }
  if (ppExt == "fpp") {
    // Some Fortran compilers automatically enable preprocessing for
    // the ".fpp" extension.  Since the source is already preprocessed,
    // use the ".f" extension.
    ppExt = "f";
  }

  // Take the object file name and replace the extension.
  std::string const& objName = this->GeneratorTarget->GetObjectName(source);
  std::string const& objExt =
    this->GetGlobalGenerator()->GetLanguageOutputExtension(*source);
  assert(objName.size() >= objExt.size());
  std::string const ppName =
    objName.substr(0, objName.size() - objExt.size()) + "-pp." + ppExt;

  std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
287
  if (!path.empty()) {
288
    path += "/";
289
  }
290 291 292 293 294 295
  path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
  path += "/";
  path += ppName;
  return path;
}

296 297 298 299
std::string cmNinjaTargetGenerator::GetDyndepFilePath(
  std::string const& lang) const
{
  std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
300
  if (!path.empty()) {
301
    path += "/";
302
  }
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
  path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
  path += "/";
  path += lang;
  path += ".dd";
  return path;
}

std::string cmNinjaTargetGenerator::GetTargetDependInfoPath(
  std::string const& lang) const
{
  std::string path = this->Makefile->GetCurrentBinaryDirectory();
  path += "/";
  path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
  path += "/" + lang + "DependInfo.json";
  return path;
}

320 321
std::string cmNinjaTargetGenerator::GetTargetOutputDir() const
{
322
  std::string dir = this->GeneratorTarget->GetDirectory(this->GetConfigName());
323
  return ConvertToNinjaPath(dir);
324 325
}

326 327
std::string cmNinjaTargetGenerator::GetTargetFilePath(
  const std::string& name) const
328 329
{
  std::string path = this->GetTargetOutputDir();
330
  if (path.empty() || path == ".") {
331
    return name;
332
  }
333 334 335 336 337 338 339
  path += "/";
  path += name;
  return path;
}

std::string cmNinjaTargetGenerator::GetTargetName() const
{
340
  return this->GeneratorTarget->GetName();
341 342
}

343
bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const
344
{
345 346
  cmMakefile* mf = this->GetMakefile();
  if (mf->GetDefinition("MSVC_C_ARCHITECTURE_ID") ||
347
      mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID")) {
348
    std::string pdbPath;
349
    std::string compilePdbPath;
350 351 352 353
    if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE ||
        this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY ||
        this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
        this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
354
      pdbPath = this->GeneratorTarget->GetPDBDirectory(this->GetConfigName());
355
      pdbPath += "/";
356
      pdbPath += this->GeneratorTarget->GetPDBName(this->GetConfigName());
357
    }
358
    if (this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
359
      compilePdbPath =
360 361
        this->GeneratorTarget->GetCompilePDBPath(this->GetConfigName());
      if (compilePdbPath.empty()) {
362
        compilePdbPath = this->GeneratorTarget->GetSupportDirectory() + "/";
363
      }
364
    }
365

366
    vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat(
367
      ConvertToNinjaPath(pdbPath), cmOutputConverter::SHELL);
368 369
    vars["TARGET_COMPILE_PDB"] =
      this->GetLocalGenerator()->ConvertToOutputFormat(
370
        ConvertToNinjaPath(compilePdbPath), cmOutputConverter::SHELL);
371

372
    EnsureParentDirectoryExists(pdbPath);
373
    EnsureParentDirectoryExists(compilePdbPath);
374
    return true;
375
  }
376
  return false;
377 378
}

379
void cmNinjaTargetGenerator::WriteLanguageRules(const std::string& language)
380
{
381
#ifdef NINJA_GEN_VERBOSE_FILES
382
  this->GetRulesFileStream() << "# Rules for language " << language << "\n\n";
383
#endif
384 385 386
  this->WriteCompileRule(language);
}

387
void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
388
{
389
  cmRulePlaceholderExpander::RuleVariables vars;
390 391 392
  vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
  vars.CMTargetType =
    cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType());
393
  vars.Language = lang.c_str();
394
  vars.Source = "$IN_ABS";
395 396
  vars.Object = "$out";
  vars.Defines = "$DEFINES";
397
  vars.Includes = "$INCLUDES";
398
  vars.TargetPDB = "$TARGET_PDB";
399
  vars.TargetCompilePDB = "$TARGET_COMPILE_PDB";
400
  vars.ObjectDir = "$OBJECT_DIR";
401
  vars.ObjectFileDir = "$OBJECT_FILE_DIR";
402

403 404
  // For some cases we do an explicit preprocessor invocation.
  bool const explicitPP = this->NeedExplicitPreprocessing(lang);
405
  bool const needDyndep = this->NeedDyndep(lang);
406

407
  cmMakefile* mf = this->GetMakefile();
408

409 410 411 412 413
  std::string flags = "$FLAGS";
  std::string rspfile;
  std::string rspcontent;
  std::string responseFlag;

414
  if (lang != "RC" && this->ForceResponseFile()) {
415 416 417 418 419 420
    rspfile = "$RSP_FILE";
    responseFlag = "@" + rspfile;
    rspcontent = " $DEFINES $INCLUDES $FLAGS";
    flags = responseFlag;
    vars.Defines = "";
    vars.Includes = "";
421
  }
422

423 424 425 426
  // Tell ninja dependency format so all deps can be loaded into a database
  std::string deptype;
  std::string depfile;
  std::string cldeps;
427 428 429
  if (explicitPP) {
    // The explicit preprocessing step will handle dependency scanning.
  } else if (this->NeedDepTypeMSVC(lang)) {
430 431 432
    deptype = "msvc";
    depfile = "";
    flags += " /showIncludes";
433
  } else if (mf->IsOn("CMAKE_NINJA_CMCLDEPS_" + lang)) {
434 435
    // For the MS resource compiler we need cmcldeps, but skip dependencies
    // for source-file try_compile cases because they are always fresh.
436
    if (!mf->GetIsSourceFileTryCompile()) {
437 438
      deptype = "gcc";
      depfile = "$DEP_FILE";
439 440 441 442
      const std::string cl = mf->GetDefinition("CMAKE_C_COMPILER")
        ? mf->GetSafeDefinition("CMAKE_C_COMPILER")
        : mf->GetSafeDefinition("CMAKE_CXX_COMPILER");
      cldeps = "\"";
443
      cldeps += cmSystemTools::GetCMClDepsCommand();
444
      cldeps += "\" " + lang + " " + vars.Source + " \"$DEP_FILE\" $out \"";
445 446
      cldeps += mf->GetSafeDefinition("CMAKE_CL_SHOWINCLUDES_PREFIX");
      cldeps += "\" \"" + cl + "\" ";
447
    }
448
  } else {
449
    deptype = "gcc";
450
    const char* langdeptype = mf->GetDefinition("CMAKE_NINJA_DEPTYPE_" + lang);
451
    if (langdeptype) {
452
      deptype = langdeptype;
453
    }
454
    depfile = "$DEP_FILE";
455
    const std::string flagsName = "CMAKE_DEPFILE_FLAGS_" + lang;
456
    std::string depfileFlags = mf->GetSafeDefinition(flagsName);
457
    if (!depfileFlags.empty()) {
458
      cmSystemTools::ReplaceString(depfileFlags, "<DEPFILE>", "$DEP_FILE");
459
      cmSystemTools::ReplaceString(depfileFlags, "<OBJECT>", "$out");
460 461 462
      cmSystemTools::ReplaceString(depfileFlags, "<CMAKE_C_COMPILER>",
                                   mf->GetDefinition("CMAKE_C_COMPILER"));
      flags += " " + depfileFlags;
463
    }
464
  }
465

466 467
  vars.Flags = flags.c_str();
  vars.DependencyFile = depfile.c_str();
468

469 470 471
  CM_AUTO_PTR<cmRulePlaceholderExpander> rulePlaceholderExpander(
    this->GetLocalGenerator()->CreateRulePlaceholderExpander());

472 473 474 475
  std::string const tdi = this->GetLocalGenerator()->ConvertToOutputFormat(
    ConvertToNinjaPath(this->GetTargetDependInfoPath(lang)),
    cmLocalGenerator::SHELL);

476 477 478 479 480 481 482 483
  std::string launcher;
  const char* val = this->GetLocalGenerator()->GetRuleLauncher(
    this->GetGeneratorTarget(), "RULE_LAUNCH_COMPILE");
  if (val && *val) {
    launcher = val;
    launcher += " ";
  }

484 485 486 487 488 489 490
  if (explicitPP) {
    // Lookup the explicit preprocessing rule.
    std::string const ppVar = "CMAKE_" + lang + "_PREPROCESS_SOURCE";
    std::string const ppCmd =
      this->GetMakefile()->GetRequiredDefinition(ppVar);

    // Explicit preprocessing always uses a depfile.
491
    std::string const ppDeptype = ""; // no deps= for multiple outputs
492 493
    std::string const ppDepfile = "$DEP_FILE";

494
    cmRulePlaceholderExpander::RuleVariables ppVars;
495 496
    ppVars.CMTargetName = vars.CMTargetName;
    ppVars.CMTargetType = vars.CMTargetType;
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
    ppVars.Language = vars.Language;
    ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
    ppVars.PreprocessedSource = "$out";
    ppVars.DependencyFile = ppDepfile.c_str();

    // Preprocessing uses the original source,
    // compilation uses preprocessed output.
    ppVars.Source = vars.Source;
    vars.Source = "$in";

    // Preprocessing and compilation use the same flags.
    ppVars.Flags = vars.Flags;

    // Move preprocessor definitions to the preprocessor rule.
    ppVars.Defines = vars.Defines;
    vars.Defines = "";

    // Copy include directories to the preprocessor rule.  The Fortran
    // compilation rule still needs them for the INCLUDE directive.
    ppVars.Includes = vars.Includes;

    // Rule for preprocessing source file.
    std::vector<std::string> ppCmds;
    cmSystemTools::ExpandListArgument(ppCmd, ppCmds);

    for (std::vector<std::string>::iterator i = ppCmds.begin();
         i != ppCmds.end(); ++i) {
524
      *i = launcher + *i;
525 526
      rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
                                                   *i, ppVars);
527 528
    }

529 530 531 532 533 534 535 536 537 538
    // Run CMake dependency scanner on preprocessed output.
    std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
      cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
    ppCmds.push_back(
      cmake + " -E cmake_ninja_depends"
              " --tdi=" +
      tdi + " --pp=$out"
            " --dep=$DEP_FILE" +
      (needDyndep ? " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE" : ""));

539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
    std::string const ppCmdLine =
      this->GetLocalGenerator()->BuildCommandLine(ppCmds);

    // Write the rule for preprocessing file of the given language.
    std::ostringstream ppComment;
    ppComment << "Rule for preprocessing " << lang << " files.";
    std::ostringstream ppDesc;
    ppDesc << "Building " << lang << " preprocessed $out";
    this->GetGlobalGenerator()->AddRule(this->LanguagePreprocessRule(lang),
                                        ppCmdLine, ppDesc.str(),
                                        ppComment.str(), ppDepfile, ppDeptype,
                                        /*rspfile*/ "",
                                        /*rspcontent*/ "",
                                        /*restat*/ "",
                                        /*generator*/ false);
  }

556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
  if (needDyndep) {
    // Write the rule for ninja dyndep file generation.
    std::vector<std::string> ddCmds;

    // Run CMake dependency scanner on preprocessed output.
    std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
      cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
    ddCmds.push_back(cmake + " -E cmake_ninja_dyndep"
                             " --tdi=" +
                     tdi + " --dd=$out"
                           " $in");

    std::string const ddCmdLine =
      this->GetLocalGenerator()->BuildCommandLine(ddCmds);

    std::ostringstream ddComment;
    ddComment << "Rule to generate ninja dyndep files for " << lang << ".";
    std::ostringstream ddDesc;
    ddDesc << "Generating " << lang << " dyndep file $out";
    this->GetGlobalGenerator()->AddRule(
      this->LanguageDyndepRule(lang), ddCmdLine, ddDesc.str(), ddComment.str(),
      /*depfile*/ "",
      /*deps*/ "",
      /*rspfile*/ "",
      /*rspcontent*/ "",
      /*restat*/ "",
      /*generator*/ false);
  }

585
  // Rule for compiling object file.
586
  const std::string cmdVar = std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
587
  std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
588 589
  std::vector<std::string> compileCmds;
  cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
590

591
  // Maybe insert an include-what-you-use runner.
592
  if (!compileCmds.empty() && (lang == "C" || lang == "CXX")) {
593
    std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE";
594
    const char* iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
595
    std::string const tidy_prop = lang + "_CLANG_TIDY";
596 597 598
    const char* tidy = this->GeneratorTarget->GetProperty(tidy_prop);
    if ((iwyu && *iwyu) || (tidy && *tidy)) {
      std::string run_iwyu = this->GetLocalGenerator()->ConvertToOutputFormat(
599
        cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
600
      run_iwyu += " -E __run_iwyu";
601
      if (iwyu && *iwyu) {
602 603
        run_iwyu += " --iwyu=";
        run_iwyu += this->GetLocalGenerator()->EscapeForShell(iwyu);
604 605
      }
      if (tidy && *tidy) {
606 607 608
        run_iwyu += " --tidy=";
        run_iwyu += this->GetLocalGenerator()->EscapeForShell(tidy);
        run_iwyu += " --source=$in";
609
      }
610 611 612
      run_iwyu += " -- ";
      compileCmds.front().insert(0, run_iwyu);
    }
613
  }
614

615
  // Maybe insert a compiler launcher like ccache or distcc
616
  if (!compileCmds.empty() && (lang == "C" || lang == "CXX")) {
617
    std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER";
618 619
    const char* clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
    if (clauncher && *clauncher) {
620 621 622
      std::vector<std::string> launcher_cmd;
      cmSystemTools::ExpandListArgument(clauncher, launcher_cmd, true);
      for (std::vector<std::string>::iterator i = launcher_cmd.begin(),
623 624
                                              e = launcher_cmd.end();
           i != e; ++i) {
625
        *i = this->LocalGenerator->EscapeForShell(*i);
626
      }
627 628 629
      std::string const& run_launcher = cmJoin(launcher_cmd, " ") + " ";
      compileCmds.front().insert(0, run_launcher);
    }
630
  }
631

632
  if (!compileCmds.empty()) {
633
    compileCmds.front().insert(0, cldeps);
634
  }
635

636
  for (std::vector<std::string>::iterator i = compileCmds.begin();
637
       i != compileCmds.end(); ++i) {
638
    *i = launcher + *i;
639 640
    rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), *i,
                                                 vars);
641
  }
642

643 644
  std::string cmdLine =
    this->GetLocalGenerator()->BuildCommandLine(compileCmds);
645

646
  // Write the rule for compiling file of the given language.
647
  std::ostringstream comment;
648
  comment << "Rule for compiling " << lang << " files.";
649
  std::ostringstream description;
650
  description << "Building " << lang << " object $out";
651 652 653 654 655
  this->GetGlobalGenerator()->AddRule(
    this->LanguageCompilerRule(lang), cmdLine, description.str(),
    comment.str(), depfile, deptype, rspfile, rspcontent,
    /*restat*/ "",
    /*generator*/ false);
656 657
}

658
void cmNinjaTargetGenerator::WriteObjectBuildStatements()
659 660 661 662 663
{
  // Write comments.
  cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
  this->GetBuildFileStream()
    << "# Object build statements for "
664
    << cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
665
    << " target " << this->GetTargetName() << "\n\n";
666

667
  std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
668
  std::vector<cmSourceFile const*> customCommands;
669
  this->GeneratorTarget->GetCustomCommands(customCommands, config);
670 671 672 673 674 675 676 677 678 679
  for (std::vector<cmSourceFile const*>::const_iterator si =
         customCommands.begin();
       si != customCommands.end(); ++si) {
    cmCustomCommand const* cc = (*si)->GetCustomCommand();
    this->GetLocalGenerator()->AddCustomCommandTarget(
      cc, this->GetGeneratorTarget());
    // Record the custom commands for this target. The container is used
    // in WriteObjectBuildStatement when called in a loop below.
    this->CustomCommands.push_back(cc);
  }
680
  std::vector<cmSourceFile const*> headerSources;
681
  this->GeneratorTarget->GetHeaderSources(headerSources, config);
682
  this->OSXBundleGenerator->GenerateMacOSXContentStatements(
683
    headerSources, this->MacOSXContentGenerator);
684
  std::vector<cmSourceFile const*> extraSources;
685
  this->GeneratorTarget->GetExtraSources(extraSources, config);
686
  this->OSXBundleGenerator->GenerateMacOSXContentStatements(
687
    extraSources, this->MacOSXContentGenerator);
688
  std::vector<cmSourceFile const*> externalObjects;
689
  this->GeneratorTarget->GetExternalObjects(externalObjects, config);
690 691 692
  for (std::vector<cmSourceFile const*>::const_iterator si =
         externalObjects.begin();
       si != externalObjects.end(); ++si) {
693
    this->Objects.push_back(this->GetSourceFilePath(*si));
694
  }
695 696

  cmNinjaDeps orderOnlyDeps;
697 698
  this->GetLocalGenerator()->AppendTargetDepends(this->GeneratorTarget,
                                                 orderOnlyDeps);
699

700 701 702 703
  // Add order-only dependencies on other files associated with the target.
  orderOnlyDeps.insert(orderOnlyDeps.end(), this->ExtraFiles.begin(),
                       this->ExtraFiles.end());

704
  // Add order-only dependencies on custom command outputs.
705 706 707
  for (std::vector<cmCustomCommand const*>::const_iterator cci =
         this->CustomCommands.begin();
       cci != this->CustomCommands.end(); ++cci) {
708 709
    cmCustomCommand const* cc = *cci;
    cmCustomCommandGenerator ccg(*cc, this->GetConfigName(),
710
                                 this->GetLocalGenerator());
711
    const std::vector<std::string>& ccoutputs = ccg.GetOutputs();
712
    const std::vector<std::string>& ccbyproducts = ccg.GetByproducts();
713 714
    std::transform(ccoutputs.begin(), ccoutputs.end(),
                   std::back_inserter(orderOnlyDeps), MapToNinjaPath());
715 716
    std::transform(ccbyproducts.begin(), ccbyproducts.end(),
                   std::back_inserter(orderOnlyDeps), MapToNinjaPath());
717
  }
718

719
  if (!orderOnlyDeps.empty()) {
720 721
    cmNinjaDeps orderOnlyTarget;
    orderOnlyTarget.push_back(this->OrderDependsTargetForTarget());
722 723 724 725 726
    this->GetGlobalGenerator()->WritePhonyBuild(
      this->GetBuildFileStream(),
      "Order-only phony target for " + this->GetTargetName(), orderOnlyTarget,
      cmNinjaDeps(), cmNinjaDeps(), orderOnlyDeps);
  }
727
  std::vector<cmSourceFile const*> objectSources;
728
  this->GeneratorTarget->GetObjectSources(objectSources, config);
729 730 731
  for (std::vector<cmSourceFile const*>::const_iterator si =
         objectSources.begin();
       si != objectSources.end(); ++si) {
732
    this->WriteObjectBuildStatement(*si, !orderOnlyDeps.empty());
733
  }
734

735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
  if (!this->DDIFiles.empty()) {
    std::string const ddComment;
    std::string const ddRule = this->LanguageDyndepRule("Fortran");
    cmNinjaDeps ddOutputs;
    cmNinjaDeps ddImplicitOuts;
    cmNinjaDeps const& ddExplicitDeps = this->DDIFiles;
    cmNinjaDeps ddImplicitDeps;
    cmNinjaDeps ddOrderOnlyDeps;
    cmNinjaVars ddVars;

    this->WriteTargetDependInfo("Fortran");

    ddOutputs.push_back(this->GetDyndepFilePath("Fortran"));

    this->GetGlobalGenerator()->WriteBuild(
      this->GetBuildFileStream(), ddComment, ddRule, ddOutputs, ddImplicitOuts,
      ddExplicitDeps, ddImplicitDeps, ddOrderOnlyDeps, ddVars);
  }

754 755 756
  this->GetBuildFileStream() << "\n";
}

757
void cmNinjaTargetGenerator::WriteObjectBuildStatement(
758
  cmSourceFile const* source, bool writeOrderDependsTargetForTarget)
759
{
760
  std::string const language = source->GetLanguage();
761
  std::string const sourceFileName = this->GetSourceFilePath(source);
762 763 764 765
  std::string const objectDir =
    this->ConvertToNinjaPath(this->GeneratorTarget->GetSupportDirectory());
  std::string const objectFileName =
    this->ConvertToNinjaPath(this->GetObjectFilePath(source));
766 767 768 769
  std::string const objectFileDir =
    cmSystemTools::GetFilenamePath(objectFileName);

  cmNinjaVars vars;
770 771
  vars["IN_ABS"] = this->GetLocalGenerator()->ConvertToOutputFormat(
    source->GetFullPath(), cmOutputConverter::SHELL);
772 773 774
  vars["FLAGS"] = this->ComputeFlagsForObject(source, language);
  vars["DEFINES"] = this->ComputeDefines(source, language);
  vars["INCLUDES"] = this->GetIncludes(language);
775
  if (!this->NeedDepTypeMSVC(language)) {
776 777
    vars["DEP_FILE"] =
      cmGlobalNinjaGenerator::EncodeDepfileSpace(objectFileName + ".d");
778
  }
779 780

  this->ExportObjectCompileCommand(
781 782
    language, sourceFileName, objectDir, objectFileName, objectFileDir,
    vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"]);
783

784 785 786 787 788 789 790 791 792 793 794
  std::string comment;
  std::string rule = this->LanguageCompilerRule(language);

  cmNinjaDeps outputs;
  outputs.push_back(objectFileName);
  // Add this object to the list of object files.
  this->Objects.push_back(objectFileName);

  cmNinjaDeps explicitDeps;
  explicitDeps.push_back(sourceFileName);

795
  cmNinjaDeps implicitDeps;
796
  if (const char* objectDeps = source->GetProperty("OBJECT_DEPENDS")) {
797 798
    std::vector<std::string> depList;
    cmSystemTools::ExpandListArgument(objectDeps, depList);
799 800 801
    for (std::vector<std::string>::iterator odi = depList.begin();
         odi != depList.end(); ++odi) {
      if (cmSystemTools::FileIsFullPath(*odi)) {
802 803
        *odi = cmSystemTools::CollapseFullPath(*odi);
      }
804
    }
805
    std::transform(depList.begin(), depList.end(),
806
                   std::back_inserter(implicitDeps), MapToNinjaPath());
807 808
  }

809
  cmNinjaDeps orderOnlyDeps;
810
  if (writeOrderDependsTargetForTarget) {
811
    orderOnlyDeps.push_back(this->OrderDependsTargetForTarget());
812
  }
813

814 815 816 817 818 819 820 821 822 823
  // If the source file is GENERATED and does not have a custom command
  // (either attached to this source file or another one), assume that one of
  // the target dependencies, OBJECT_DEPENDS or header file custom commands
  // will rebuild the file.
  if (source->GetPropertyAsBool("GENERATED") && !source->GetCustomCommand() &&
      !this->GetGlobalGenerator()->HasCustomCommandOutput(sourceFileName)) {
    this->GetGlobalGenerator()->AddAssumedSourceDependencies(sourceFileName,
                                                             orderOnlyDeps);
  }

824 825 826
  // For some cases we need to generate a ninja dyndep file.
  bool const needDyndep = this->NeedDyndep(language);

827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862
  // For some cases we do an explicit preprocessor invocation.
  bool const explicitPP = this->NeedExplicitPreprocessing(language);
  if (explicitPP) {
    std::string const ppComment;
    std::string const ppRule = this->LanguagePreprocessRule(language);
    cmNinjaDeps ppOutputs;
    cmNinjaDeps ppImplicitOuts;
    cmNinjaDeps ppExplicitDeps;
    cmNinjaDeps ppImplicitDeps;
    cmNinjaDeps ppOrderOnlyDeps;
    cmNinjaVars ppVars;

    std::string const ppFileName =
      this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source));
    ppOutputs.push_back(ppFileName);

    // Move compilation dependencies to the preprocessing build statement.
    std::swap(ppExplicitDeps, explicitDeps);
    std::swap(ppImplicitDeps, implicitDeps);
    std::swap(ppOrderOnlyDeps, orderOnlyDeps);
    std::swap(ppVars["IN_ABS"], vars["IN_ABS"]);

    // The actual compilation will now use the preprocessed source.
    explicitDeps.push_back(ppFileName);

    // Preprocessing and compilation use the same flags.
    ppVars["FLAGS"] = vars["FLAGS"];

    // Move preprocessor definitions to the preprocessor build statement.
    std::swap(ppVars["DEFINES"], vars["DEFINES"]);

    // Copy include directories to the preprocessor build statement.  The
    // Fortran compilation build statement still needs them for the INCLUDE
    // directive.
    ppVars["INCLUDES"] = vars["INCLUDES"];

863 864 865 866 867 868 869 870 871 872 873 874
    // Prepend source file's original directory as an include directory
    // so e.g. Fortran INCLUDE statements can look for files in it.
    std::vector<std::string> sourceDirectory;
    sourceDirectory.push_back(
      cmSystemTools::GetParentDirectory(source->GetFullPath()));

    std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
      sourceDirectory, this->GeneratorTarget, language, false, false,
      this->GetConfigName());

    vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"];

875 876 877 878 879 880 881
    // Explicit preprocessing always uses a depfile.
    ppVars["DEP_FILE"] =
      cmGlobalNinjaGenerator::EncodeDepfileSpace(ppFileName + ".d");
    // The actual compilation does not need a depfile because it
    // depends on the already-preprocessed source.
    vars.erase("DEP_FILE");

882 883 884 885 886 887 888 889 890 891 892 893
    if (needDyndep) {
      // Tell dependency scanner the object file that will result from
      // compiling the preprocessed source.
      ppVars["OBJ_FILE"] = objectFileName;

      // Tell dependency scanner where to store dyndep intermediate results.
      std::string const ddiFile = ppFileName + ".ddi";
      ppVars["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
      ppImplicitOuts.push_back(ddiFile);
      this->DDIFiles.push_back(ddiFile);
    }

894 895 896 897 898 899 900
    this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
                               ppVars);

    this->GetGlobalGenerator()->WriteBuild(
      this->GetBuildFileStream(), ppComment, ppRule, ppOutputs, ppImplicitOuts,
      ppExplicitDeps, ppImplicitDeps, ppOrderOnlyDeps, ppVars);
  }
901 902 903 904 905
  if (needDyndep) {
    std::string const dyndep = this->GetDyndepFilePath(language);
    orderOnlyDeps.push_back(dyndep);
    vars["dyndep"] = dyndep;
  }
906

907
  EnsureParentDirectoryExists(objectFileName);
908

909
  vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
910
    objectDir, cmOutputConverter::SHELL);
911
  vars["OBJECT_FILE_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
912
    objectFileDir, cmOutputConverter::SHELL);
913

914 915
  this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
                             vars);
916

917
  this->SetMsvcTargetPdbVariable(vars);
918

919 920 921
  bool const isRC = (language == "RC");
  int const commandLineLengthLimit =
    ((!isRC && this->ForceResponseFile())) ? -1 : 0;
922 923
  std::string const rspfile = objectFileName + ".rsp";

924
  this->GetGlobalGenerator()->WriteBuild(
925 926 927
    this->GetBuildFileStream(), comment, rule, outputs,
    /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps, orderOnlyDeps,
    vars, rspfile, commandLineLengthLimit);
928

929
  if (const char* objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) {
930 931 932 933
    std::vector<std::string> outputList;
    cmSystemTools::ExpandListArgument(objectOutputs, outputList);
    std::transform(outputList.begin(), outputList.end(), outputList.begin(),
                   MapToNinjaPath());
934 935
    this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(),
                                                "Additional output files.",
936
                                                outputList, outputs);
937
  }
938
}
939

940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang)
{
  Json::Value tdi(Json::objectValue);
  tdi["language"] = lang;
  tdi["compiler-id"] =
    this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_ID");

  if (lang == "Fortran") {
    std::string mod_dir = this->GeneratorTarget->GetFortranModuleDirectory(
      this->Makefile->GetHomeOutputDirectory());
    if (mod_dir.empty()) {
      mod_dir = this->Makefile->GetCurrentBinaryDirectory();
    }
    tdi["module-dir"] = mod_dir;
  }

  tdi["dir-cur-bld"] = this->Makefile->GetCurrentBinaryDirectory();
  tdi["dir-cur-src"] = this->Makefile->GetCurrentSourceDirectory();
  tdi["dir-top-bld"] = this->Makefile->GetHomeOutputDirectory();
  tdi["dir-top-src"] = this->Makefile->GetHomeDirectory();

  Json::Value& tdi_include_dirs = tdi["include-dirs"] = Json::arrayValue;
  std::vector<std::string> includes;
  this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
                                              lang, this->GetConfigName());
  for (std::vector<std::string>::iterator i = includes.begin();
       i != includes.end(); ++i) {
    tdi_include_dirs.append(*i);
  }

  Json::Value& tdi_linked_target_dirs = tdi["linked-target-dirs"] =
    Json::arrayValue;
  std::vector<std::string> linked = this->GetLinkedTargetDirectories();
  for (std::vector<std::string>::iterator i = linked.begin();
       i != linked.end(); ++i) {
    tdi_linked_target_dirs.append(*i);
  }

  std::string const tdin = this->GetTargetDependInfoPath(lang);
  cmGeneratedFileStream tdif(tdin.c_str());
  tdif << tdi;
}

983 984 985 986 987
void cmNinjaTargetGenerator::ExportObjectCompileCommand(
  std::string const& language, std::string const& sourceFileName,
  std::string const& objectDir, std::string const& objectFileName,
  std::string const& objectFileDir, std::string const& flags,
  std::string const& defines, std::string const& includes)
988
{
989
  if (!this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS")) {
990
    return;
991
  }
992

993
  cmRulePlaceholderExpander::RuleVariables compileObjectVars;
994 995 996 997
  compileObjectVars.Language = language.c_str();

  std::string escapedSourceFileName = sourceFileName;

998
  if (!cmSystemTools::FileIsFullPath(sourceFileName.c_str())) {
999
    escapedSourceFileName = cmSystemTools::CollapseFullPath(
1000 1001 1002 1003
      escapedSourceFileName, this->GetGlobalGenerator()
                               ->GetCMakeInstance()
                               ->GetHomeOutputDirectory());
  }
1004

1005
  escapedSourceFileName = this->LocalGenerator->ConvertToOutputFormat(
1006
    escapedSourceFileName, cmOutputConverter::SHELL);
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024

  compileObjectVars.Source = escapedSourceFileName.c_str();
  compileObjectVars.Object = objectFileName.c_str();
  compileObjectVars.ObjectDir = objectDir.c_str();
  compileObjectVars.ObjectFileDir = objectFileDir.c_str();
  compileObjectVars.Flags = flags.c_str();
  compileObjectVars.Defines = defines.c_str();
  compileObjectVars.Includes = includes.c_str();

  // Rule for compiling object file.
  std::string compileCmdVar = "CMAKE_";
  compileCmdVar += language;
  compileCmdVar += "_COMPILE_OBJECT";
  std::string compileCmd =
    this->GetMakefile()->GetRequiredDefinition(compileCmdVar);
  std::vector<std::string> compileCmds;
  cmSystemTools::ExpandListArgument(compileCmd, compileCmds);

1025 1026 1027
  CM_AUTO_PTR<cmRulePlaceholderExpander> rulePlaceholderExpander(
    this->GetLocalGenerator()->CreateRulePlaceholderExpander());

1028
  for (std::vector<std::string>::iterator i = compileCmds.begin();
1029
       i != compileCmds.end(); ++i) {
1030 1031
    rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), *i,
                                                 compileObjectVars);
1032
  }
1033 1034 1035 1036

  std::string cmdLine =
    this->GetLocalGenerator()->BuildCommandLine(compileCmds);

1037
  this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName);
1038 1039
}

1040 1041
void cmNinjaTargetGenerator::EnsureDirectoryExists(
  const std::string& path) const
1042
{
1043
  if (cmSystemTools::FileIsFullPath(path.c_str())) {
1044
    cmSystemTools::MakeDirectory(path.c_str());
1045
  } else {
1046 1047 1048 1049 1050 1051
    cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator();
    std::string fullPath =
      std::string(gg->GetCMakeInstance()->GetHomeOutputDirectory());
    // Also ensures their is a trailing slash.
    gg->StripNinjaOutputPathPrefixAsSuffix(fullPath);
    fullPath += path;
1052
    cmSystemTools::MakeDirectory(fullPath.c_str());
1053
  }
1054 1055
}

1056 1057
void cmNinjaTargetGenerator::EnsureParentDirectoryExists(
  const std::string& path) const
1058
{
1059
  EnsureDirectoryExists(cmSystemTools::GetParentDirectory(path));
1060
}
1061

1062
void cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()(
1063
  cmSourceFile const& source, const char* pkgloc)
1064 1065
{
  // Skip OS X content when not building a Framework or Bundle.
1066
  if (!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) {
1067
    return;
1068
  }
1069

1070
  std::string macdir =
1071
    this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc);
1072 1073 1074

  // Get the input file location.
  std::string input = source.GetFullPath();
1075
  input = this->Generator->GetGlobalGenerator()->ConvertToNinjaPath(input);
1076 1077 1078 1079 1080

  // Get the output file location.
  std::string output = macdir;
  output += "/";
  output += cmSystemTools::GetFilenameName(input);
1081
  output = this->Generator->GetGlobalGenerator()->ConvertToNinjaPath(output);
1082 1083

  // Write a build statement to copy the content into the bundle.
1084 1085
  this->Generator->GetGlobalGenerator()->WriteMacOSXContentBuild(input,
                                                                 output);
1086

1087 1088
  // Add as a dependency to the target so that it gets called.
  this->Generator->ExtraFiles.push_back(output);
1089
}
1090

1091
void cmNinjaTargetGenerator::addPoolNinjaVariable(
1092 1093
  const std::string& pool_property, cmGeneratorTarget* target,
  cmNinjaVars& vars)
1094
{
1095 1096 1097 1098
  const char* pool = target->GetProperty(pool_property);
  if (pool) {
    vars["pool"] = pool;
  }
1099
}
1100 1101 1102 1103 1104

bool cmNinjaTargetGenerator::ForceResponseFile()
{
  static std::string const forceRspFile = "CMAKE_NINJA_FORCE_RESPONSE_FILE";
  return (this->GetMakefile()->IsDefinitionSet(forceRspFile) ||
1105
          cmSystemTools::HasEnv(forceRspFile));
1106
}