cmNinjaTargetGenerator.cxx 46 KB

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