Imported Upstream version 3.11.2
[platform/upstream/cmake.git] / Source / cmNinjaTargetGenerator.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmNinjaTargetGenerator.h"
4
5 #include "cm_jsoncpp_value.h"
6 #include "cm_jsoncpp_writer.h"
7 #include <algorithm>
8 #include <assert.h>
9 #include <iterator>
10 #include <map>
11 #include <memory> // IWYU pragma: keep
12 #include <sstream>
13 #include <string.h>
14
15 #include "cmAlgorithms.h"
16 #include "cmComputeLinkInformation.h"
17 #include "cmCustomCommandGenerator.h"
18 #include "cmGeneratedFileStream.h"
19 #include "cmGeneratorExpression.h"
20 #include "cmGeneratorTarget.h"
21 #include "cmGlobalNinjaGenerator.h"
22 #include "cmLocalGenerator.h"
23 #include "cmLocalNinjaGenerator.h"
24 #include "cmMakefile.h"
25 #include "cmNinjaNormalTargetGenerator.h"
26 #include "cmNinjaUtilityTargetGenerator.h"
27 #include "cmOutputConverter.h"
28 #include "cmRulePlaceholderExpander.h"
29 #include "cmSourceFile.h"
30 #include "cmState.h"
31 #include "cmStateTypes.h"
32 #include "cmSystemTools.h"
33 #include "cmake.h"
34
35 cmNinjaTargetGenerator* cmNinjaTargetGenerator::New(cmGeneratorTarget* target)
36 {
37   switch (target->GetType()) {
38     case cmStateEnums::EXECUTABLE:
39     case cmStateEnums::SHARED_LIBRARY:
40     case cmStateEnums::STATIC_LIBRARY:
41     case cmStateEnums::MODULE_LIBRARY:
42     case cmStateEnums::OBJECT_LIBRARY:
43       return new cmNinjaNormalTargetGenerator(target);
44
45     case cmStateEnums::UTILITY:
46     case cmStateEnums::GLOBAL_TARGET:
47       return new cmNinjaUtilityTargetGenerator(target);
48
49     default:
50       return nullptr;
51   }
52 }
53
54 cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmGeneratorTarget* target)
55   : cmCommonTargetGenerator(target)
56   , MacOSXContentGenerator(nullptr)
57   , OSXBundleGenerator(nullptr)
58   , MacContentFolders()
59   , LocalGenerator(
60       static_cast<cmLocalNinjaGenerator*>(target->GetLocalGenerator()))
61   , Objects()
62 {
63   MacOSXContentGenerator = new MacOSXContentGeneratorType(this);
64 }
65
66 cmNinjaTargetGenerator::~cmNinjaTargetGenerator()
67 {
68   delete this->MacOSXContentGenerator;
69 }
70
71 cmGeneratedFileStream& cmNinjaTargetGenerator::GetBuildFileStream() const
72 {
73   return *this->GetGlobalGenerator()->GetBuildFileStream();
74 }
75
76 cmGeneratedFileStream& cmNinjaTargetGenerator::GetRulesFileStream() const
77 {
78   return *this->GetGlobalGenerator()->GetRulesFileStream();
79 }
80
81 cmGlobalNinjaGenerator* cmNinjaTargetGenerator::GetGlobalGenerator() const
82 {
83   return this->LocalGenerator->GetGlobalNinjaGenerator();
84 }
85
86 std::string cmNinjaTargetGenerator::LanguageCompilerRule(
87   const std::string& lang) const
88 {
89   return lang + "_COMPILER__" +
90     cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
91 }
92
93 std::string cmNinjaTargetGenerator::LanguagePreprocessRule(
94   std::string const& lang) const
95 {
96   return lang + "_PREPROCESS__" +
97     cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
98 }
99
100 bool cmNinjaTargetGenerator::NeedExplicitPreprocessing(
101   std::string const& lang) const
102 {
103   return lang == "Fortran";
104 }
105
106 std::string cmNinjaTargetGenerator::LanguageDyndepRule(
107   const std::string& lang) const
108 {
109   return lang + "_DYNDEP__" +
110     cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
111 }
112
113 bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang) const
114 {
115   return lang == "Fortran";
116 }
117
118 std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget()
119 {
120   return "cmake_object_order_depends_target_" + this->GetTargetName();
121 }
122
123 // TODO: Most of the code is picked up from
124 // void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink),
125 // void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
126 // Refactor it.
127 std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
128   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   cmGeneratorExpressionInterpreter genexInterpreter(
139     this->LocalGenerator, this->GeneratorTarget,
140     this->LocalGenerator->GetConfigName(), this->GeneratorTarget->GetName(),
141     language);
142
143   const std::string COMPILE_FLAGS("COMPILE_FLAGS");
144   if (const char* cflags = source->GetProperty(COMPILE_FLAGS)) {
145     this->LocalGenerator->AppendFlags(
146       flags, genexInterpreter.Evaluate(cflags, COMPILE_FLAGS));
147   }
148
149   const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
150   if (const char* coptions = source->GetProperty(COMPILE_OPTIONS)) {
151     this->LocalGenerator->AppendCompileOptions(
152       flags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS));
153   }
154
155   return flags;
156 }
157
158 void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags,
159                                              std::string const& language)
160 {
161   std::vector<std::string> includes;
162   this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
163                                               language, this->GetConfigName());
164   // Add include directory flags.
165   std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
166     includes, this->GeneratorTarget, language,
167     language == "RC", // full include paths for RC needed by cmcldeps
168     false, this->GetConfigName());
169   if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
170     std::replace(includeFlags.begin(), includeFlags.end(), '\\', '/');
171   }
172
173   this->LocalGenerator->AppendFlags(languageFlags, includeFlags);
174 }
175
176 bool cmNinjaTargetGenerator::NeedDepTypeMSVC(const std::string& lang) const
177 {
178   return strcmp(this->GetMakefile()->GetSafeDefinition("CMAKE_NINJA_DEPTYPE_" +
179                                                        lang),
180                 "msvc") == 0;
181 }
182
183 // TODO: Refactor with
184 // void cmMakefileTargetGenerator::WriteTargetLanguageFlags().
185 std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source,
186                                                    const std::string& language)
187 {
188   std::set<std::string> defines;
189   const std::string config = this->LocalGenerator->GetConfigName();
190   cmGeneratorExpressionInterpreter genexInterpreter(
191     this->LocalGenerator, this->GeneratorTarget, config,
192     this->GeneratorTarget->GetName(), language);
193
194   const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
195   if (const char* compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) {
196     this->LocalGenerator->AppendDefines(
197       defines, genexInterpreter.Evaluate(compile_defs, COMPILE_DEFINITIONS));
198   }
199
200   std::string defPropName = "COMPILE_DEFINITIONS_";
201   defPropName += cmSystemTools::UpperCase(config);
202   if (const char* config_compile_defs = source->GetProperty(defPropName)) {
203     this->LocalGenerator->AppendDefines(
204       defines,
205       genexInterpreter.Evaluate(config_compile_defs, COMPILE_DEFINITIONS));
206   }
207
208   std::string definesString = this->GetDefines(language);
209   this->LocalGenerator->JoinDefines(defines, definesString, language);
210
211   return definesString;
212 }
213
214 std::string cmNinjaTargetGenerator::ComputeIncludes(
215   cmSourceFile const* source, const std::string& language)
216 {
217   std::vector<std::string> includes;
218   const std::string config = this->LocalGenerator->GetConfigName();
219   cmGeneratorExpressionInterpreter genexInterpreter(
220     this->LocalGenerator, this->GeneratorTarget, config,
221     this->GeneratorTarget->GetName(), language);
222
223   const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
224   if (const char* cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) {
225     this->LocalGenerator->AppendIncludeDirectories(
226       includes, genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES),
227       *source);
228   }
229
230   std::string includesString = this->LocalGenerator->GetIncludeFlags(
231     includes, this->GeneratorTarget, language, true, false, config);
232   this->LocalGenerator->AppendFlags(includesString,
233                                     this->GetIncludes(language));
234
235   return includesString;
236 }
237
238 cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const
239 {
240   // Static libraries never depend on other targets for linking.
241   if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY ||
242       this->GeneratorTarget->GetType() == cmStateEnums::OBJECT_LIBRARY) {
243     return cmNinjaDeps();
244   }
245
246   cmComputeLinkInformation* cli =
247     this->GeneratorTarget->GetLinkInformation(this->GetConfigName());
248   if (!cli) {
249     return cmNinjaDeps();
250   }
251
252   const std::vector<std::string>& deps = cli->GetDepends();
253   cmNinjaDeps result(deps.size());
254   std::transform(deps.begin(), deps.end(), result.begin(), MapToNinjaPath());
255
256   // Add a dependency on the link definitions file, if any.
257   if (cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
258         this->GeneratorTarget->GetModuleDefinitionInfo(
259           this->GetConfigName())) {
260     for (cmSourceFile const* src : mdi->Sources) {
261       result.push_back(this->ConvertToNinjaPath(src->GetFullPath()));
262     }
263   }
264
265   // Add a dependency on user-specified manifest files, if any.
266   std::vector<cmSourceFile const*> manifest_srcs;
267   this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName);
268   for (cmSourceFile const* manifest_src : manifest_srcs) {
269     result.push_back(this->ConvertToNinjaPath(manifest_src->GetFullPath()));
270   }
271
272   // Add user-specified dependencies.
273   if (const char* linkDepends =
274         this->GeneratorTarget->GetProperty("LINK_DEPENDS")) {
275     std::vector<std::string> linkDeps;
276     cmSystemTools::ExpandListArgument(linkDepends, linkDeps);
277     std::transform(linkDeps.begin(), linkDeps.end(),
278                    std::back_inserter(result), MapToNinjaPath());
279   }
280
281   return result;
282 }
283
284 std::string cmNinjaTargetGenerator::GetSourceFilePath(
285   cmSourceFile const* source) const
286 {
287   return ConvertToNinjaPath(source->GetFullPath());
288 }
289
290 std::string cmNinjaTargetGenerator::GetObjectFilePath(
291   cmSourceFile const* source) const
292 {
293   std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
294   if (!path.empty()) {
295     path += "/";
296   }
297   std::string const& objectName = this->GeneratorTarget->GetObjectName(source);
298   path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
299   path += "/";
300   path += objectName;
301   return path;
302 }
303
304 std::string cmNinjaTargetGenerator::GetPreprocessedFilePath(
305   cmSourceFile const* source) const
306 {
307   // Choose an extension to compile already-preprocessed source.
308   std::string ppExt = source->GetExtension();
309   if (cmHasLiteralPrefix(ppExt, "F")) {
310     // Some Fortran compilers automatically enable preprocessing for
311     // upper-case extensions.  Since the source is already preprocessed,
312     // use a lower-case extension.
313     ppExt = cmSystemTools::LowerCase(ppExt);
314   }
315   if (ppExt == "fpp") {
316     // Some Fortran compilers automatically enable preprocessing for
317     // the ".fpp" extension.  Since the source is already preprocessed,
318     // use the ".f" extension.
319     ppExt = "f";
320   }
321
322   // Take the object file name and replace the extension.
323   std::string const& objName = this->GeneratorTarget->GetObjectName(source);
324   std::string const& objExt =
325     this->GetGlobalGenerator()->GetLanguageOutputExtension(*source);
326   assert(objName.size() >= objExt.size());
327   std::string const ppName =
328     objName.substr(0, objName.size() - objExt.size()) + "-pp." + ppExt;
329
330   std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
331   if (!path.empty()) {
332     path += "/";
333   }
334   path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
335   path += "/";
336   path += ppName;
337   return path;
338 }
339
340 std::string cmNinjaTargetGenerator::GetDyndepFilePath(
341   std::string const& lang) const
342 {
343   std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
344   if (!path.empty()) {
345     path += "/";
346   }
347   path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
348   path += "/";
349   path += lang;
350   path += ".dd";
351   return path;
352 }
353
354 std::string cmNinjaTargetGenerator::GetTargetDependInfoPath(
355   std::string const& lang) const
356 {
357   std::string path = this->Makefile->GetCurrentBinaryDirectory();
358   path += "/";
359   path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
360   path += "/" + lang + "DependInfo.json";
361   return path;
362 }
363
364 std::string cmNinjaTargetGenerator::GetTargetOutputDir() const
365 {
366   std::string dir = this->GeneratorTarget->GetDirectory(this->GetConfigName());
367   return ConvertToNinjaPath(dir);
368 }
369
370 std::string cmNinjaTargetGenerator::GetTargetFilePath(
371   const std::string& name) const
372 {
373   std::string path = this->GetTargetOutputDir();
374   if (path.empty() || path == ".") {
375     return name;
376   }
377   path += "/";
378   path += name;
379   return path;
380 }
381
382 std::string cmNinjaTargetGenerator::GetTargetName() const
383 {
384   return this->GeneratorTarget->GetName();
385 }
386
387 bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const
388 {
389   cmMakefile* mf = this->GetMakefile();
390   if (mf->GetDefinition("MSVC_C_ARCHITECTURE_ID") ||
391       mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID") ||
392       mf->GetDefinition("MSVC_CUDA_ARCHITECTURE_ID")) {
393     std::string pdbPath;
394     std::string compilePdbPath = this->ComputeTargetCompilePDB();
395     if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE ||
396         this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY ||
397         this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
398         this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
399       pdbPath = this->GeneratorTarget->GetPDBDirectory(this->GetConfigName());
400       pdbPath += "/";
401       pdbPath += this->GeneratorTarget->GetPDBName(this->GetConfigName());
402     }
403
404     vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat(
405       ConvertToNinjaPath(pdbPath), cmOutputConverter::SHELL);
406     vars["TARGET_COMPILE_PDB"] =
407       this->GetLocalGenerator()->ConvertToOutputFormat(
408         ConvertToNinjaPath(compilePdbPath), cmOutputConverter::SHELL);
409
410     EnsureParentDirectoryExists(pdbPath);
411     EnsureParentDirectoryExists(compilePdbPath);
412     return true;
413   }
414   return false;
415 }
416
417 void cmNinjaTargetGenerator::WriteLanguageRules(const std::string& language)
418 {
419 #ifdef NINJA_GEN_VERBOSE_FILES
420   this->GetRulesFileStream() << "# Rules for language " << language << "\n\n";
421 #endif
422   this->WriteCompileRule(language);
423 }
424
425 void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
426 {
427   cmRulePlaceholderExpander::RuleVariables vars;
428   vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
429   vars.CMTargetType =
430     cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType());
431   vars.Language = lang.c_str();
432   vars.Source = "$in";
433   vars.Object = "$out";
434   vars.Defines = "$DEFINES";
435   vars.Includes = "$INCLUDES";
436   vars.TargetPDB = "$TARGET_PDB";
437   vars.TargetCompilePDB = "$TARGET_COMPILE_PDB";
438   vars.ObjectDir = "$OBJECT_DIR";
439   vars.ObjectFileDir = "$OBJECT_FILE_DIR";
440
441   // For some cases we do an explicit preprocessor invocation.
442   bool const explicitPP = this->NeedExplicitPreprocessing(lang);
443   bool const needDyndep = this->NeedDyndep(lang);
444
445   cmMakefile* mf = this->GetMakefile();
446
447   std::string flags = "$FLAGS";
448   std::string rspfile;
449   std::string rspcontent;
450
451   bool const lang_supports_response = !(lang == "RC" || lang == "CUDA");
452   if (lang_supports_response && this->ForceResponseFile()) {
453     std::string const responseFlagVar =
454       "CMAKE_" + lang + "_RESPONSE_FILE_FLAG";
455     std::string responseFlag =
456       this->Makefile->GetSafeDefinition(responseFlagVar);
457     if (responseFlag.empty()) {
458       responseFlag = "@";
459     }
460     rspfile = "$RSP_FILE";
461     responseFlag += rspfile;
462     rspcontent = " $DEFINES $INCLUDES $FLAGS";
463     flags = std::move(responseFlag);
464     vars.Defines = "";
465     vars.Includes = "";
466   }
467
468   // Tell ninja dependency format so all deps can be loaded into a database
469   std::string deptype;
470   std::string depfile;
471   std::string cldeps;
472   if (explicitPP) {
473     // The explicit preprocessing step will handle dependency scanning.
474   } else if (this->NeedDepTypeMSVC(lang)) {
475     deptype = "msvc";
476     depfile.clear();
477     flags += " /showIncludes";
478   } else if (mf->IsOn("CMAKE_NINJA_CMCLDEPS_" + lang)) {
479     // For the MS resource compiler we need cmcldeps, but skip dependencies
480     // for source-file try_compile cases because they are always fresh.
481     if (!mf->GetIsSourceFileTryCompile()) {
482       deptype = "gcc";
483       depfile = "$DEP_FILE";
484       const std::string cl = mf->GetDefinition("CMAKE_C_COMPILER")
485         ? mf->GetSafeDefinition("CMAKE_C_COMPILER")
486         : mf->GetSafeDefinition("CMAKE_CXX_COMPILER");
487       cldeps = "\"";
488       cldeps += cmSystemTools::GetCMClDepsCommand();
489       cldeps += "\" " + lang + " " + vars.Source + " $DEP_FILE $out \"";
490       cldeps += mf->GetSafeDefinition("CMAKE_CL_SHOWINCLUDES_PREFIX");
491       cldeps += "\" \"" + cl + "\" ";
492     }
493   } else {
494     deptype = "gcc";
495     const char* langdeptype = mf->GetDefinition("CMAKE_NINJA_DEPTYPE_" + lang);
496     if (langdeptype) {
497       deptype = langdeptype;
498     }
499     depfile = "$DEP_FILE";
500     const std::string flagsName = "CMAKE_DEPFILE_FLAGS_" + lang;
501     std::string depfileFlags = mf->GetSafeDefinition(flagsName);
502     if (!depfileFlags.empty()) {
503       cmSystemTools::ReplaceString(depfileFlags, "<DEPFILE>", "$DEP_FILE");
504       cmSystemTools::ReplaceString(depfileFlags, "<OBJECT>", "$out");
505       cmSystemTools::ReplaceString(depfileFlags, "<CMAKE_C_COMPILER>",
506                                    mf->GetDefinition("CMAKE_C_COMPILER"));
507       flags += " " + depfileFlags;
508     }
509   }
510
511   vars.Flags = flags.c_str();
512   vars.DependencyFile = depfile.c_str();
513
514   std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
515     this->GetLocalGenerator()->CreateRulePlaceholderExpander());
516
517   std::string const tdi = this->GetLocalGenerator()->ConvertToOutputFormat(
518     ConvertToNinjaPath(this->GetTargetDependInfoPath(lang)),
519     cmLocalGenerator::SHELL);
520
521   std::string launcher;
522   const char* val = this->GetLocalGenerator()->GetRuleLauncher(
523     this->GetGeneratorTarget(), "RULE_LAUNCH_COMPILE");
524   if (val && *val) {
525     launcher = val;
526     launcher += " ";
527   }
528
529   if (explicitPP) {
530     // Lookup the explicit preprocessing rule.
531     std::string const ppVar = "CMAKE_" + lang + "_PREPROCESS_SOURCE";
532     std::string const ppCmd =
533       this->GetMakefile()->GetRequiredDefinition(ppVar);
534
535     // Explicit preprocessing always uses a depfile.
536     std::string const ppDeptype; // no deps= for multiple outputs
537     std::string const ppDepfile = "$DEP_FILE";
538
539     cmRulePlaceholderExpander::RuleVariables ppVars;
540     ppVars.CMTargetName = vars.CMTargetName;
541     ppVars.CMTargetType = vars.CMTargetType;
542     ppVars.Language = vars.Language;
543     ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
544     ppVars.PreprocessedSource = "$out";
545     ppVars.DependencyFile = ppDepfile.c_str();
546
547     // Preprocessing uses the original source,
548     // compilation uses preprocessed output.
549     ppVars.Source = vars.Source;
550     vars.Source = "$in";
551
552     // Preprocessing and compilation use the same flags.
553     ppVars.Flags = vars.Flags;
554
555     // Move preprocessor definitions to the preprocessor rule.
556     ppVars.Defines = vars.Defines;
557     vars.Defines = "";
558
559     // Copy include directories to the preprocessor rule.  The Fortran
560     // compilation rule still needs them for the INCLUDE directive.
561     ppVars.Includes = vars.Includes;
562
563     // Rule for preprocessing source file.
564     std::vector<std::string> ppCmds;
565     cmSystemTools::ExpandListArgument(ppCmd, ppCmds);
566
567     for (std::string& i : ppCmds) {
568       i = launcher + i;
569       rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
570                                                    i, ppVars);
571     }
572
573     // Run CMake dependency scanner on preprocessed output.
574     std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
575       cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
576     ppCmds.push_back(
577       cmake + " -E cmake_ninja_depends"
578               " --tdi=" +
579       tdi + " --pp=$out"
580             " --dep=$DEP_FILE" +
581       (needDyndep ? " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE" : ""));
582
583     std::string const ppCmdLine =
584       this->GetLocalGenerator()->BuildCommandLine(ppCmds);
585
586     // Write the rule for preprocessing file of the given language.
587     std::ostringstream ppComment;
588     ppComment << "Rule for preprocessing " << lang << " files.";
589     std::ostringstream ppDesc;
590     ppDesc << "Building " << lang << " preprocessed $out";
591     this->GetGlobalGenerator()->AddRule(this->LanguagePreprocessRule(lang),
592                                         ppCmdLine, ppDesc.str(),
593                                         ppComment.str(), ppDepfile, ppDeptype,
594                                         /*rspfile*/ "",
595                                         /*rspcontent*/ "",
596                                         /*restat*/ "",
597                                         /*generator*/ false);
598   }
599
600   if (needDyndep) {
601     // Write the rule for ninja dyndep file generation.
602     std::vector<std::string> ddCmds;
603
604     // Command line length is almost always limited -> use response file for
605     // dyndep rules
606     std::string ddRspFile = "$out.rsp";
607     std::string ddRspContent = "$in";
608     std::string ddInput = "@" + ddRspFile;
609
610     // Run CMake dependency scanner on preprocessed output.
611     std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
612       cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
613     ddCmds.push_back(cmake + " -E cmake_ninja_dyndep"
614                              " --tdi=" +
615                      tdi + " --dd=$out"
616                            " " +
617                      ddInput);
618
619     std::string const ddCmdLine =
620       this->GetLocalGenerator()->BuildCommandLine(ddCmds);
621
622     std::ostringstream ddComment;
623     ddComment << "Rule to generate ninja dyndep files for " << lang << ".";
624     std::ostringstream ddDesc;
625     ddDesc << "Generating " << lang << " dyndep file $out";
626     this->GetGlobalGenerator()->AddRule(
627       this->LanguageDyndepRule(lang), ddCmdLine, ddDesc.str(), ddComment.str(),
628       /*depfile*/ "",
629       /*deps*/ "", ddRspFile, ddRspContent,
630       /*restat*/ "",
631       /*generator*/ false);
632   }
633
634   // Rule for compiling object file.
635   std::vector<std::string> compileCmds;
636   if (lang == "CUDA") {
637     std::string cmdVar;
638     if (this->GeneratorTarget->GetPropertyAsBool(
639           "CUDA_SEPARABLE_COMPILATION")) {
640       cmdVar = std::string("CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION");
641     } else if (this->GeneratorTarget->GetPropertyAsBool(
642                  "CUDA_PTX_COMPILATION")) {
643       cmdVar = std::string("CMAKE_CUDA_COMPILE_PTX_COMPILATION");
644     } else {
645       cmdVar = std::string("CMAKE_CUDA_COMPILE_WHOLE_COMPILATION");
646     }
647     std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
648     cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
649   } else {
650     const std::string cmdVar =
651       std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
652     std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
653     cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
654   }
655
656   // Maybe insert an include-what-you-use runner.
657   if (!compileCmds.empty() && (lang == "C" || lang == "CXX")) {
658     std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE";
659     const char* iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
660     std::string const tidy_prop = lang + "_CLANG_TIDY";
661     const char* tidy = this->GeneratorTarget->GetProperty(tidy_prop);
662     std::string const cpplint_prop = lang + "_CPPLINT";
663     const char* cpplint = this->GeneratorTarget->GetProperty(cpplint_prop);
664     std::string const cppcheck_prop = lang + "_CPPCHECK";
665     const char* cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
666     if ((iwyu && *iwyu) || (tidy && *tidy) || (cpplint && *cpplint) ||
667         (cppcheck && *cppcheck)) {
668       std::string run_iwyu = this->GetLocalGenerator()->ConvertToOutputFormat(
669         cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
670       run_iwyu += " -E __run_co_compile";
671       if (iwyu && *iwyu) {
672         run_iwyu += " --iwyu=";
673         run_iwyu += this->GetLocalGenerator()->EscapeForShell(iwyu);
674       }
675       if (tidy && *tidy) {
676         run_iwyu += " --tidy=";
677         run_iwyu += this->GetLocalGenerator()->EscapeForShell(tidy);
678       }
679       if (cpplint && *cpplint) {
680         run_iwyu += " --cpplint=";
681         run_iwyu += this->GetLocalGenerator()->EscapeForShell(cpplint);
682       }
683       if (cppcheck && *cppcheck) {
684         run_iwyu += " --cppcheck=";
685         run_iwyu += this->GetLocalGenerator()->EscapeForShell(cppcheck);
686       }
687       if ((tidy && *tidy) || (cpplint && *cpplint) ||
688           (cppcheck && *cppcheck)) {
689         run_iwyu += " --source=$in";
690       }
691       run_iwyu += " -- ";
692       compileCmds.front().insert(0, run_iwyu);
693     }
694   }
695
696   // Maybe insert a compiler launcher like ccache or distcc
697   if (!compileCmds.empty() &&
698       (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA")) {
699     std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER";
700     const char* clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
701     if (clauncher && *clauncher) {
702       std::vector<std::string> launcher_cmd;
703       cmSystemTools::ExpandListArgument(clauncher, launcher_cmd, true);
704       for (std::string& i : launcher_cmd) {
705         i = this->LocalGenerator->EscapeForShell(i);
706       }
707       std::string const& run_launcher = cmJoin(launcher_cmd, " ") + " ";
708       compileCmds.front().insert(0, run_launcher);
709     }
710   }
711
712   if (!compileCmds.empty()) {
713     compileCmds.front().insert(0, cldeps);
714   }
715
716   for (std::string& i : compileCmds) {
717     i = launcher + i;
718     rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), i,
719                                                  vars);
720   }
721
722   std::string cmdLine =
723     this->GetLocalGenerator()->BuildCommandLine(compileCmds);
724
725   // Write the rule for compiling file of the given language.
726   std::ostringstream comment;
727   comment << "Rule for compiling " << lang << " files.";
728   std::ostringstream description;
729   description << "Building " << lang << " object $out";
730   this->GetGlobalGenerator()->AddRule(
731     this->LanguageCompilerRule(lang), cmdLine, description.str(),
732     comment.str(), depfile, deptype, rspfile, rspcontent,
733     /*restat*/ "",
734     /*generator*/ false);
735 }
736
737 void cmNinjaTargetGenerator::WriteObjectBuildStatements()
738 {
739   // Write comments.
740   cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
741   this->GetBuildFileStream()
742     << "# Object build statements for "
743     << cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
744     << " target " << this->GetTargetName() << "\n\n";
745
746   std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
747   std::vector<cmSourceFile const*> customCommands;
748   this->GeneratorTarget->GetCustomCommands(customCommands, config);
749   for (cmSourceFile const* sf : customCommands) {
750     cmCustomCommand const* cc = sf->GetCustomCommand();
751     this->GetLocalGenerator()->AddCustomCommandTarget(
752       cc, this->GetGeneratorTarget());
753     // Record the custom commands for this target. The container is used
754     // in WriteObjectBuildStatement when called in a loop below.
755     this->CustomCommands.push_back(cc);
756   }
757   std::vector<cmSourceFile const*> headerSources;
758   this->GeneratorTarget->GetHeaderSources(headerSources, config);
759   this->OSXBundleGenerator->GenerateMacOSXContentStatements(
760     headerSources, this->MacOSXContentGenerator);
761   std::vector<cmSourceFile const*> extraSources;
762   this->GeneratorTarget->GetExtraSources(extraSources, config);
763   this->OSXBundleGenerator->GenerateMacOSXContentStatements(
764     extraSources, this->MacOSXContentGenerator);
765   std::vector<cmSourceFile const*> externalObjects;
766   this->GeneratorTarget->GetExternalObjects(externalObjects, config);
767   for (cmSourceFile const* sf : externalObjects) {
768     this->Objects.push_back(this->GetSourceFilePath(sf));
769   }
770
771   cmNinjaDeps orderOnlyDeps;
772   this->GetLocalGenerator()->AppendTargetDepends(
773     this->GeneratorTarget, orderOnlyDeps, DependOnTargetOrdering);
774
775   // Add order-only dependencies on other files associated with the target.
776   orderOnlyDeps.insert(orderOnlyDeps.end(), this->ExtraFiles.begin(),
777                        this->ExtraFiles.end());
778
779   // Add order-only dependencies on custom command outputs.
780   for (cmCustomCommand const* cc : this->CustomCommands) {
781     cmCustomCommandGenerator ccg(*cc, this->GetConfigName(),
782                                  this->GetLocalGenerator());
783     const std::vector<std::string>& ccoutputs = ccg.GetOutputs();
784     const std::vector<std::string>& ccbyproducts = ccg.GetByproducts();
785     std::transform(ccoutputs.begin(), ccoutputs.end(),
786                    std::back_inserter(orderOnlyDeps), MapToNinjaPath());
787     std::transform(ccbyproducts.begin(), ccbyproducts.end(),
788                    std::back_inserter(orderOnlyDeps), MapToNinjaPath());
789   }
790
791   std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end());
792   orderOnlyDeps.erase(std::unique(orderOnlyDeps.begin(), orderOnlyDeps.end()),
793                       orderOnlyDeps.end());
794
795   {
796     cmNinjaDeps orderOnlyTarget;
797     orderOnlyTarget.push_back(this->OrderDependsTargetForTarget());
798     this->GetGlobalGenerator()->WritePhonyBuild(
799       this->GetBuildFileStream(),
800       "Order-only phony target for " + this->GetTargetName(), orderOnlyTarget,
801       cmNinjaDeps(), cmNinjaDeps(), orderOnlyDeps);
802   }
803   std::vector<cmSourceFile const*> objectSources;
804   this->GeneratorTarget->GetObjectSources(objectSources, config);
805   for (cmSourceFile const* sf : objectSources) {
806     this->WriteObjectBuildStatement(sf);
807   }
808
809   if (!this->DDIFiles.empty()) {
810     std::string const ddComment;
811     std::string const ddRule = this->LanguageDyndepRule("Fortran");
812     cmNinjaDeps ddOutputs;
813     cmNinjaDeps ddImplicitOuts;
814     cmNinjaDeps const& ddExplicitDeps = this->DDIFiles;
815     cmNinjaDeps ddImplicitDeps;
816     cmNinjaDeps ddOrderOnlyDeps;
817     cmNinjaVars ddVars;
818
819     this->WriteTargetDependInfo("Fortran");
820
821     ddOutputs.push_back(this->GetDyndepFilePath("Fortran"));
822
823     // Make sure dyndep files for all our dependencies have already
824     // been generated so that the 'FortranModules.json' files they
825     // produced as side-effects are available for us to read.
826     // Ideally we should depend on the 'FortranModules.json' files
827     // from our dependencies directly, but we don't know which of
828     // our dependencies produces them.  Fixing this will require
829     // refactoring the Ninja generator to generate targets in
830     // dependency order so that we can collect the needed information.
831     this->GetLocalGenerator()->AppendTargetDepends(
832       this->GeneratorTarget, ddOrderOnlyDeps, DependOnTargetArtifact);
833
834     this->GetGlobalGenerator()->WriteBuild(
835       this->GetBuildFileStream(), ddComment, ddRule, ddOutputs, ddImplicitOuts,
836       ddExplicitDeps, ddImplicitDeps, ddOrderOnlyDeps, ddVars);
837   }
838
839   this->GetBuildFileStream() << "\n";
840 }
841
842 void cmNinjaTargetGenerator::WriteObjectBuildStatement(
843   cmSourceFile const* source)
844 {
845   std::string const language = source->GetLanguage();
846   std::string const sourceFileName =
847     language == "RC" ? source->GetFullPath() : this->GetSourceFilePath(source);
848   std::string const objectDir =
849     this->ConvertToNinjaPath(this->GeneratorTarget->GetSupportDirectory());
850   std::string const objectFileName =
851     this->ConvertToNinjaPath(this->GetObjectFilePath(source));
852   std::string const objectFileDir =
853     cmSystemTools::GetFilenamePath(objectFileName);
854
855   cmNinjaVars vars;
856   vars["FLAGS"] = this->ComputeFlagsForObject(source, language);
857   vars["DEFINES"] = this->ComputeDefines(source, language);
858   vars["INCLUDES"] = this->ComputeIncludes(source, language);
859   if (!this->NeedDepTypeMSVC(language)) {
860     vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
861       objectFileName + ".d", cmOutputConverter::SHELL);
862   }
863
864   this->ExportObjectCompileCommand(
865     language, sourceFileName, objectDir, objectFileName, objectFileDir,
866     vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"]);
867
868   std::string comment;
869   std::string rule = this->LanguageCompilerRule(language);
870
871   cmNinjaDeps outputs;
872   outputs.push_back(objectFileName);
873   // Add this object to the list of object files.
874   this->Objects.push_back(objectFileName);
875
876   cmNinjaDeps explicitDeps;
877   explicitDeps.push_back(sourceFileName);
878
879   cmNinjaDeps implicitDeps;
880   if (const char* objectDeps = source->GetProperty("OBJECT_DEPENDS")) {
881     std::vector<std::string> depList;
882     cmSystemTools::ExpandListArgument(objectDeps, depList);
883     for (std::string& odi : depList) {
884       if (cmSystemTools::FileIsFullPath(odi)) {
885         odi = cmSystemTools::CollapseFullPath(odi);
886       }
887     }
888     std::transform(depList.begin(), depList.end(),
889                    std::back_inserter(implicitDeps), MapToNinjaPath());
890   }
891
892   cmNinjaDeps orderOnlyDeps;
893   orderOnlyDeps.push_back(this->OrderDependsTargetForTarget());
894
895   // If the source file is GENERATED and does not have a custom command
896   // (either attached to this source file or another one), assume that one of
897   // the target dependencies, OBJECT_DEPENDS or header file custom commands
898   // will rebuild the file.
899   if (source->GetPropertyAsBool("GENERATED") &&
900       !source->GetPropertyAsBool("__CMAKE_GENERATED_BY_CMAKE") &&
901       !source->GetCustomCommand() &&
902       !this->GetGlobalGenerator()->HasCustomCommandOutput(sourceFileName)) {
903     this->GetGlobalGenerator()->AddAssumedSourceDependencies(sourceFileName,
904                                                              orderOnlyDeps);
905   }
906
907   // For some cases we need to generate a ninja dyndep file.
908   bool const needDyndep = this->NeedDyndep(language);
909
910   // For some cases we do an explicit preprocessor invocation.
911   bool const explicitPP = this->NeedExplicitPreprocessing(language);
912   if (explicitPP) {
913     std::string const ppComment;
914     std::string const ppRule = this->LanguagePreprocessRule(language);
915     cmNinjaDeps ppOutputs;
916     cmNinjaDeps ppImplicitOuts;
917     cmNinjaDeps ppExplicitDeps;
918     cmNinjaDeps ppImplicitDeps;
919     cmNinjaDeps ppOrderOnlyDeps;
920     cmNinjaVars ppVars;
921
922     std::string const ppFileName =
923       this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source));
924     ppOutputs.push_back(ppFileName);
925
926     // Move compilation dependencies to the preprocessing build statement.
927     std::swap(ppExplicitDeps, explicitDeps);
928     std::swap(ppImplicitDeps, implicitDeps);
929     std::swap(ppOrderOnlyDeps, orderOnlyDeps);
930     std::swap(ppVars["IN_ABS"], vars["IN_ABS"]);
931
932     // The actual compilation will now use the preprocessed source.
933     explicitDeps.push_back(ppFileName);
934
935     // Preprocessing and compilation generally use the same flags.
936     ppVars["FLAGS"] = vars["FLAGS"];
937
938     // In case compilation requires flags that are incompatible with
939     // preprocessing, include them here.
940     std::string const postFlag =
941       this->Makefile->GetSafeDefinition("CMAKE_Fortran_POSTPROCESS_FLAG");
942     this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag);
943
944     // Move preprocessor definitions to the preprocessor build statement.
945     std::swap(ppVars["DEFINES"], vars["DEFINES"]);
946
947     // Copy include directories to the preprocessor build statement.  The
948     // Fortran compilation build statement still needs them for the INCLUDE
949     // directive.
950     ppVars["INCLUDES"] = vars["INCLUDES"];
951
952     // Prepend source file's original directory as an include directory
953     // so e.g. Fortran INCLUDE statements can look for files in it.
954     std::vector<std::string> sourceDirectory;
955     sourceDirectory.push_back(
956       cmSystemTools::GetParentDirectory(source->GetFullPath()));
957
958     std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
959       sourceDirectory, this->GeneratorTarget, language, false, false,
960       this->GetConfigName());
961
962     vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"];
963
964     // Explicit preprocessing always uses a depfile.
965     ppVars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
966       ppFileName + ".d", cmOutputConverter::SHELL);
967     // The actual compilation does not need a depfile because it
968     // depends on the already-preprocessed source.
969     vars.erase("DEP_FILE");
970
971     if (needDyndep) {
972       // Tell dependency scanner the object file that will result from
973       // compiling the preprocessed source.
974       ppVars["OBJ_FILE"] = objectFileName;
975
976       // Tell dependency scanner where to store dyndep intermediate results.
977       std::string const ddiFile = ppFileName + ".ddi";
978       ppVars["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
979       ppImplicitOuts.push_back(ddiFile);
980       this->DDIFiles.push_back(ddiFile);
981     }
982
983     this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
984                                ppVars);
985
986     this->GetGlobalGenerator()->WriteBuild(
987       this->GetBuildFileStream(), ppComment, ppRule, ppOutputs, ppImplicitOuts,
988       ppExplicitDeps, ppImplicitDeps, ppOrderOnlyDeps, ppVars);
989   }
990   if (needDyndep) {
991     std::string const dyndep = this->GetDyndepFilePath(language);
992     orderOnlyDeps.push_back(dyndep);
993     vars["dyndep"] = dyndep;
994   }
995
996   EnsureParentDirectoryExists(objectFileName);
997
998   vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
999     objectDir, cmOutputConverter::SHELL);
1000   vars["OBJECT_FILE_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
1001     objectFileDir, cmOutputConverter::SHELL);
1002
1003   this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
1004                              vars);
1005
1006   this->SetMsvcTargetPdbVariable(vars);
1007
1008   bool const lang_supports_response =
1009     !(language == "RC" || language == "CUDA");
1010   int const commandLineLengthLimit =
1011     ((lang_supports_response && this->ForceResponseFile())) ? -1 : 0;
1012   std::string const rspfile = objectFileName + ".rsp";
1013
1014   this->GetGlobalGenerator()->WriteBuild(
1015     this->GetBuildFileStream(), comment, rule, outputs,
1016     /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps, orderOnlyDeps,
1017     vars, rspfile, commandLineLengthLimit);
1018
1019   if (const char* objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) {
1020     std::vector<std::string> outputList;
1021     cmSystemTools::ExpandListArgument(objectOutputs, outputList);
1022     std::transform(outputList.begin(), outputList.end(), outputList.begin(),
1023                    MapToNinjaPath());
1024     this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(),
1025                                                 "Additional output files.",
1026                                                 outputList, outputs);
1027   }
1028 }
1029
1030 void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang)
1031 {
1032   Json::Value tdi(Json::objectValue);
1033   tdi["language"] = lang;
1034   tdi["compiler-id"] =
1035     this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_ID");
1036
1037   if (lang == "Fortran") {
1038     std::string mod_dir = this->GeneratorTarget->GetFortranModuleDirectory(
1039       this->Makefile->GetHomeOutputDirectory());
1040     if (mod_dir.empty()) {
1041       mod_dir = this->Makefile->GetCurrentBinaryDirectory();
1042     }
1043     tdi["module-dir"] = mod_dir;
1044   }
1045
1046   tdi["dir-cur-bld"] = this->Makefile->GetCurrentBinaryDirectory();
1047   tdi["dir-cur-src"] = this->Makefile->GetCurrentSourceDirectory();
1048   tdi["dir-top-bld"] = this->Makefile->GetHomeOutputDirectory();
1049   tdi["dir-top-src"] = this->Makefile->GetHomeDirectory();
1050
1051   Json::Value& tdi_include_dirs = tdi["include-dirs"] = Json::arrayValue;
1052   std::vector<std::string> includes;
1053   this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
1054                                               lang, this->GetConfigName());
1055   for (std::string const& i : includes) {
1056     // Convert the include directories the same way we do for -I flags.
1057     // See upstream ninja issue 1251.
1058     tdi_include_dirs.append(this->ConvertToNinjaPath(i));
1059   }
1060
1061   Json::Value& tdi_linked_target_dirs = tdi["linked-target-dirs"] =
1062     Json::arrayValue;
1063   std::vector<std::string> linked = this->GetLinkedTargetDirectories();
1064   for (std::string const& l : linked) {
1065     tdi_linked_target_dirs.append(l);
1066   }
1067
1068   std::string const tdin = this->GetTargetDependInfoPath(lang);
1069   cmGeneratedFileStream tdif(tdin.c_str());
1070   tdif << tdi;
1071 }
1072
1073 void cmNinjaTargetGenerator::ExportObjectCompileCommand(
1074   std::string const& language, std::string const& sourceFileName,
1075   std::string const& objectDir, std::string const& objectFileName,
1076   std::string const& objectFileDir, std::string const& flags,
1077   std::string const& defines, std::string const& includes)
1078 {
1079   if (!this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS")) {
1080     return;
1081   }
1082
1083   cmRulePlaceholderExpander::RuleVariables compileObjectVars;
1084   compileObjectVars.Language = language.c_str();
1085
1086   std::string escapedSourceFileName = sourceFileName;
1087
1088   if (!cmSystemTools::FileIsFullPath(sourceFileName)) {
1089     escapedSourceFileName = cmSystemTools::CollapseFullPath(
1090       escapedSourceFileName, this->GetGlobalGenerator()
1091                                ->GetCMakeInstance()
1092                                ->GetHomeOutputDirectory());
1093   }
1094
1095   escapedSourceFileName = this->LocalGenerator->ConvertToOutputFormat(
1096     escapedSourceFileName, cmOutputConverter::SHELL);
1097
1098   compileObjectVars.Source = escapedSourceFileName.c_str();
1099   compileObjectVars.Object = objectFileName.c_str();
1100   compileObjectVars.ObjectDir = objectDir.c_str();
1101   compileObjectVars.ObjectFileDir = objectFileDir.c_str();
1102   compileObjectVars.Flags = flags.c_str();
1103   compileObjectVars.Defines = defines.c_str();
1104   compileObjectVars.Includes = includes.c_str();
1105
1106   // Rule for compiling object file.
1107   std::vector<std::string> compileCmds;
1108   if (language == "CUDA") {
1109     std::string cmdVar;
1110     if (this->GeneratorTarget->GetPropertyAsBool(
1111           "CUDA_SEPARABLE_COMPILATION")) {
1112       cmdVar = std::string("CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION");
1113     } else if (this->GeneratorTarget->GetPropertyAsBool(
1114                  "CUDA_PTX_COMPILATION")) {
1115       cmdVar = std::string("CMAKE_CUDA_COMPILE_PTX_COMPILATION");
1116     } else {
1117       cmdVar = std::string("CMAKE_CUDA_COMPILE_WHOLE_COMPILATION");
1118     }
1119     std::string compileCmd =
1120       this->GetMakefile()->GetRequiredDefinition(cmdVar);
1121     cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
1122   } else {
1123     const std::string cmdVar =
1124       std::string("CMAKE_") + language + "_COMPILE_OBJECT";
1125     std::string compileCmd =
1126       this->GetMakefile()->GetRequiredDefinition(cmdVar);
1127     cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
1128   }
1129
1130   std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
1131     this->GetLocalGenerator()->CreateRulePlaceholderExpander());
1132
1133   for (std::string& i : compileCmds) {
1134     // no launcher for CMAKE_EXPORT_COMPILE_COMMANDS
1135     rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), i,
1136                                                  compileObjectVars);
1137   }
1138
1139   std::string cmdLine =
1140     this->GetLocalGenerator()->BuildCommandLine(compileCmds);
1141
1142   this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName);
1143 }
1144
1145 void cmNinjaTargetGenerator::EnsureDirectoryExists(
1146   const std::string& path) const
1147 {
1148   if (cmSystemTools::FileIsFullPath(path)) {
1149     cmSystemTools::MakeDirectory(path);
1150   } else {
1151     cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator();
1152     std::string fullPath =
1153       std::string(gg->GetCMakeInstance()->GetHomeOutputDirectory());
1154     // Also ensures their is a trailing slash.
1155     gg->StripNinjaOutputPathPrefixAsSuffix(fullPath);
1156     fullPath += path;
1157     cmSystemTools::MakeDirectory(fullPath);
1158   }
1159 }
1160
1161 void cmNinjaTargetGenerator::EnsureParentDirectoryExists(
1162   const std::string& path) const
1163 {
1164   EnsureDirectoryExists(cmSystemTools::GetParentDirectory(path));
1165 }
1166
1167 void cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()(
1168   cmSourceFile const& source, const char* pkgloc)
1169 {
1170   // Skip OS X content when not building a Framework or Bundle.
1171   if (!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) {
1172     return;
1173   }
1174
1175   std::string macdir =
1176     this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc);
1177
1178   // Get the input file location.
1179   std::string input = source.GetFullPath();
1180   input = this->Generator->GetGlobalGenerator()->ConvertToNinjaPath(input);
1181
1182   // Get the output file location.
1183   std::string output = macdir;
1184   output += "/";
1185   output += cmSystemTools::GetFilenameName(input);
1186   output = this->Generator->GetGlobalGenerator()->ConvertToNinjaPath(output);
1187
1188   // Write a build statement to copy the content into the bundle.
1189   this->Generator->GetGlobalGenerator()->WriteMacOSXContentBuild(input,
1190                                                                  output);
1191
1192   // Add as a dependency to the target so that it gets called.
1193   this->Generator->ExtraFiles.push_back(std::move(output));
1194 }
1195
1196 void cmNinjaTargetGenerator::addPoolNinjaVariable(
1197   const std::string& pool_property, cmGeneratorTarget* target,
1198   cmNinjaVars& vars)
1199 {
1200   const char* pool = target->GetProperty(pool_property);
1201   if (pool) {
1202     vars["pool"] = pool;
1203   }
1204 }
1205
1206 bool cmNinjaTargetGenerator::ForceResponseFile()
1207 {
1208   static std::string const forceRspFile = "CMAKE_NINJA_FORCE_RESPONSE_FILE";
1209   return (this->GetMakefile()->IsDefinitionSet(forceRspFile) ||
1210           cmSystemTools::HasEnv(forceRspFile));
1211 }