cmFileAPICodemodel.cxx 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554
  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 "cmFileAPICodemodel.h"
  4. #include <algorithm>
  5. #include <cassert>
  6. #include <cstddef>
  7. #include <functional>
  8. #include <limits>
  9. #include <map>
  10. #include <memory>
  11. #include <set>
  12. #include <string>
  13. #include <unordered_map>
  14. #include <utility>
  15. #include <vector>
  16. #include <cmext/algorithm>
  17. #include <cm3p/json/value.h>
  18. #include "cmCryptoHash.h"
  19. #include "cmFileAPI.h"
  20. #include "cmGeneratorExpression.h"
  21. #include "cmGeneratorTarget.h"
  22. #include "cmGlobalGenerator.h"
  23. #include "cmInstallGenerator.h"
  24. #include "cmInstallSubdirectoryGenerator.h"
  25. #include "cmInstallTargetGenerator.h"
  26. #include "cmLinkLineComputer.h"
  27. #include "cmListFileCache.h"
  28. #include "cmLocalGenerator.h"
  29. #include "cmMakefile.h"
  30. #include "cmProperty.h"
  31. #include "cmSourceFile.h"
  32. #include "cmSourceGroup.h"
  33. #include "cmState.h"
  34. #include "cmStateDirectory.h"
  35. #include "cmStateSnapshot.h"
  36. #include "cmStateTypes.h"
  37. #include "cmStringAlgorithms.h"
  38. #include "cmSystemTools.h"
  39. #include "cmTarget.h"
  40. #include "cmTargetDepend.h"
  41. #include "cmake.h"
  42. namespace {
  43. using TargetIndexMapType =
  44. std::unordered_map<cmGeneratorTarget const*, Json::ArrayIndex>;
  45. std::string RelativeIfUnder(std::string const& top, std::string const& in)
  46. {
  47. std::string out;
  48. if (in == top) {
  49. out = ".";
  50. } else if (cmSystemTools::IsSubDirectory(in, top)) {
  51. out = in.substr(top.size() + 1);
  52. } else {
  53. out = in;
  54. }
  55. return out;
  56. }
  57. class JBTIndex
  58. {
  59. public:
  60. JBTIndex() = default;
  61. explicit operator bool() const { return this->Index != None; }
  62. Json::ArrayIndex Index = None;
  63. static Json::ArrayIndex const None = static_cast<Json::ArrayIndex>(-1);
  64. };
  65. template <typename T>
  66. class JBT
  67. {
  68. public:
  69. JBT(T v = T(), JBTIndex bt = JBTIndex())
  70. : Value(std::move(v))
  71. , Backtrace(bt)
  72. {
  73. }
  74. T Value;
  75. JBTIndex Backtrace;
  76. friend bool operator==(JBT<T> const& l, JBT<T> const& r)
  77. {
  78. return l.Value == r.Value && l.Backtrace.Index == r.Backtrace.Index;
  79. }
  80. static bool ValueEq(JBT<T> const& l, JBT<T> const& r)
  81. {
  82. return l.Value == r.Value;
  83. }
  84. static bool ValueLess(JBT<T> const& l, JBT<T> const& r)
  85. {
  86. return l.Value < r.Value;
  87. }
  88. };
  89. template <typename T>
  90. class JBTs
  91. {
  92. public:
  93. JBTs(T v = T(), std::vector<JBTIndex> ids = std::vector<JBTIndex>())
  94. : Value(std::move(v))
  95. , Backtraces(std::move(ids))
  96. {
  97. }
  98. T Value;
  99. std::vector<JBTIndex> Backtraces;
  100. friend bool operator==(JBTs<T> const& l, JBTs<T> const& r)
  101. {
  102. if ((l.Value == r.Value) && (l.Backtraces.size() == r.Backtraces.size())) {
  103. for (size_t i = 0; i < l.Backtraces.size(); i++) {
  104. if (l.Backtraces[i].Index != r.Backtraces[i].Index) {
  105. return false;
  106. }
  107. }
  108. }
  109. return true;
  110. }
  111. static bool ValueEq(JBTs<T> const& l, JBTs<T> const& r)
  112. {
  113. return l.Value == r.Value;
  114. }
  115. static bool ValueLess(JBTs<T> const& l, JBTs<T> const& r)
  116. {
  117. return l.Value < r.Value;
  118. }
  119. };
  120. class BacktraceData
  121. {
  122. std::string TopSource;
  123. std::unordered_map<std::string, Json::ArrayIndex> CommandMap;
  124. std::unordered_map<std::string, Json::ArrayIndex> FileMap;
  125. std::unordered_map<cmListFileContext const*, Json::ArrayIndex> NodeMap;
  126. Json::Value Commands = Json::arrayValue;
  127. Json::Value Files = Json::arrayValue;
  128. Json::Value Nodes = Json::arrayValue;
  129. Json::ArrayIndex AddCommand(std::string const& command)
  130. {
  131. auto i = this->CommandMap.find(command);
  132. if (i == this->CommandMap.end()) {
  133. auto cmdIndex = static_cast<Json::ArrayIndex>(this->Commands.size());
  134. i = this->CommandMap.emplace(command, cmdIndex).first;
  135. this->Commands.append(command);
  136. }
  137. return i->second;
  138. }
  139. Json::ArrayIndex AddFile(std::string const& file)
  140. {
  141. auto i = this->FileMap.find(file);
  142. if (i == this->FileMap.end()) {
  143. auto fileIndex = static_cast<Json::ArrayIndex>(this->Files.size());
  144. i = this->FileMap.emplace(file, fileIndex).first;
  145. this->Files.append(RelativeIfUnder(this->TopSource, file));
  146. }
  147. return i->second;
  148. }
  149. public:
  150. BacktraceData(std::string topSource);
  151. JBTIndex Add(cmListFileBacktrace const& bt);
  152. Json::Value Dump();
  153. };
  154. BacktraceData::BacktraceData(std::string topSource)
  155. : TopSource(std::move(topSource))
  156. {
  157. }
  158. JBTIndex BacktraceData::Add(cmListFileBacktrace const& bt)
  159. {
  160. JBTIndex index;
  161. if (bt.Empty()) {
  162. return index;
  163. }
  164. cmListFileContext const* top = &bt.Top();
  165. auto found = this->NodeMap.find(top);
  166. if (found != this->NodeMap.end()) {
  167. index.Index = found->second;
  168. return index;
  169. }
  170. Json::Value entry = Json::objectValue;
  171. entry["file"] = this->AddFile(top->FilePath);
  172. if (top->Line) {
  173. entry["line"] = static_cast<int>(top->Line);
  174. }
  175. if (!top->Name.empty()) {
  176. entry["command"] = this->AddCommand(top->Name);
  177. }
  178. if (JBTIndex parent = this->Add(bt.Pop())) {
  179. entry["parent"] = parent.Index;
  180. }
  181. index.Index = this->NodeMap[top] = this->Nodes.size();
  182. this->Nodes.append(std::move(entry)); // NOLINT(*)
  183. return index;
  184. }
  185. Json::Value BacktraceData::Dump()
  186. {
  187. Json::Value backtraceGraph;
  188. this->CommandMap.clear();
  189. this->FileMap.clear();
  190. this->NodeMap.clear();
  191. backtraceGraph["commands"] = std::move(this->Commands);
  192. backtraceGraph["files"] = std::move(this->Files);
  193. backtraceGraph["nodes"] = std::move(this->Nodes);
  194. return backtraceGraph;
  195. }
  196. class Codemodel
  197. {
  198. cmFileAPI& FileAPI;
  199. unsigned long Version;
  200. Json::Value DumpPaths();
  201. Json::Value DumpConfigurations();
  202. Json::Value DumpConfiguration(std::string const& config);
  203. public:
  204. Codemodel(cmFileAPI& fileAPI, unsigned long version);
  205. Json::Value Dump();
  206. };
  207. class CodemodelConfig
  208. {
  209. cmFileAPI& FileAPI;
  210. unsigned long Version;
  211. std::string const& Config;
  212. std::string TopSource;
  213. std::string TopBuild;
  214. struct Directory
  215. {
  216. cmStateSnapshot Snapshot;
  217. cmLocalGenerator const* LocalGenerator = nullptr;
  218. Json::Value TargetIndexes = Json::arrayValue;
  219. Json::ArrayIndex ProjectIndex;
  220. bool HasInstallRule = false;
  221. };
  222. std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
  223. DirectoryMap;
  224. std::vector<Directory> Directories;
  225. struct Project
  226. {
  227. cmStateSnapshot Snapshot;
  228. static const Json::ArrayIndex NoParentIndex =
  229. static_cast<Json::ArrayIndex>(-1);
  230. Json::ArrayIndex ParentIndex = NoParentIndex;
  231. Json::Value ChildIndexes = Json::arrayValue;
  232. Json::Value DirectoryIndexes = Json::arrayValue;
  233. Json::Value TargetIndexes = Json::arrayValue;
  234. };
  235. std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
  236. ProjectMap;
  237. std::vector<Project> Projects;
  238. TargetIndexMapType TargetIndexMap;
  239. void ProcessDirectories();
  240. Json::ArrayIndex GetDirectoryIndex(cmLocalGenerator const* lg);
  241. Json::ArrayIndex GetDirectoryIndex(cmStateSnapshot s);
  242. Json::ArrayIndex AddProject(cmStateSnapshot s);
  243. Json::Value DumpTargets();
  244. Json::Value DumpTarget(cmGeneratorTarget* gt, Json::ArrayIndex ti);
  245. Json::Value DumpDirectories();
  246. Json::Value DumpDirectory(Directory& d);
  247. Json::Value DumpProjects();
  248. Json::Value DumpProject(Project& p);
  249. Json::Value DumpMinimumCMakeVersion(cmStateSnapshot s);
  250. public:
  251. CodemodelConfig(cmFileAPI& fileAPI, unsigned long version,
  252. std::string const& config);
  253. Json::Value Dump();
  254. };
  255. std::string TargetId(cmGeneratorTarget const* gt, std::string const& topBuild)
  256. {
  257. cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_256);
  258. std::string path = RelativeIfUnder(
  259. topBuild, gt->GetLocalGenerator()->GetCurrentBinaryDirectory());
  260. std::string hash = hasher.HashString(path);
  261. hash.resize(20, '0');
  262. return gt->GetName() + CMAKE_DIRECTORY_ID_SEP + hash;
  263. }
  264. struct CompileData
  265. {
  266. struct IncludeEntry
  267. {
  268. JBT<std::string> Path;
  269. bool IsSystem = false;
  270. IncludeEntry(JBT<std::string> path, bool isSystem)
  271. : Path(std::move(path))
  272. , IsSystem(isSystem)
  273. {
  274. }
  275. friend bool operator==(IncludeEntry const& l, IncludeEntry const& r)
  276. {
  277. return l.Path == r.Path && l.IsSystem == r.IsSystem;
  278. }
  279. };
  280. std::string Language;
  281. std::string Sysroot;
  282. JBTs<std::string> LanguageStandard;
  283. std::vector<JBT<std::string>> Flags;
  284. std::vector<JBT<std::string>> Defines;
  285. std::vector<JBT<std::string>> PrecompileHeaders;
  286. std::vector<IncludeEntry> Includes;
  287. friend bool operator==(CompileData const& l, CompileData const& r)
  288. {
  289. return (l.Language == r.Language && l.Sysroot == r.Sysroot &&
  290. l.Flags == r.Flags && l.Defines == r.Defines &&
  291. l.PrecompileHeaders == r.PrecompileHeaders &&
  292. l.LanguageStandard == r.LanguageStandard &&
  293. l.Includes == r.Includes);
  294. }
  295. };
  296. }
  297. namespace std {
  298. template <>
  299. struct hash<CompileData>
  300. {
  301. std::size_t operator()(CompileData const& in) const
  302. {
  303. using std::hash;
  304. size_t result =
  305. hash<std::string>()(in.Language) ^ hash<std::string>()(in.Sysroot);
  306. for (auto const& i : in.Includes) {
  307. result = result ^
  308. (hash<std::string>()(i.Path.Value) ^
  309. hash<Json::ArrayIndex>()(i.Path.Backtrace.Index) ^
  310. (i.IsSystem ? std::numeric_limits<size_t>::max() : 0));
  311. }
  312. for (auto const& i : in.Flags) {
  313. result = result ^ hash<std::string>()(i.Value) ^
  314. hash<Json::ArrayIndex>()(i.Backtrace.Index);
  315. }
  316. for (auto const& i : in.Defines) {
  317. result = result ^ hash<std::string>()(i.Value) ^
  318. hash<Json::ArrayIndex>()(i.Backtrace.Index);
  319. }
  320. for (auto const& i : in.PrecompileHeaders) {
  321. result = result ^ hash<std::string>()(i.Value) ^
  322. hash<Json::ArrayIndex>()(i.Backtrace.Index);
  323. }
  324. if (!in.LanguageStandard.Value.empty()) {
  325. result = result ^ hash<std::string>()(in.LanguageStandard.Value);
  326. for (JBTIndex backtrace : in.LanguageStandard.Backtraces) {
  327. result = result ^ hash<Json::ArrayIndex>()(backtrace.Index);
  328. }
  329. }
  330. return result;
  331. }
  332. };
  333. } // namespace std
  334. namespace {
  335. class Target
  336. {
  337. cmGeneratorTarget* GT;
  338. std::string const& Config;
  339. std::string TopSource;
  340. std::string TopBuild;
  341. std::vector<cmSourceGroup> SourceGroupsLocal;
  342. BacktraceData Backtraces;
  343. std::map<std::string, CompileData> CompileDataMap;
  344. std::unordered_map<cmSourceFile const*, Json::ArrayIndex> SourceMap;
  345. Json::Value Sources = Json::arrayValue;
  346. struct SourceGroup
  347. {
  348. std::string Name;
  349. Json::Value SourceIndexes = Json::arrayValue;
  350. };
  351. std::unordered_map<cmSourceGroup const*, Json::ArrayIndex> SourceGroupsMap;
  352. std::vector<SourceGroup> SourceGroups;
  353. struct CompileGroup
  354. {
  355. std::unordered_map<CompileData, Json::ArrayIndex>::iterator Entry;
  356. Json::Value SourceIndexes = Json::arrayValue;
  357. };
  358. std::unordered_map<CompileData, Json::ArrayIndex> CompileGroupMap;
  359. std::vector<CompileGroup> CompileGroups;
  360. template <typename T>
  361. JBT<T> ToJBT(BT<T> const& bt)
  362. {
  363. return JBT<T>(bt.Value, this->Backtraces.Add(bt.Backtrace));
  364. }
  365. template <typename T>
  366. JBTs<T> ToJBTs(BTs<T> const& bts)
  367. {
  368. std::vector<JBTIndex> ids;
  369. for (cmListFileBacktrace const& backtrace : bts.Backtraces) {
  370. ids.emplace_back(this->Backtraces.Add(backtrace));
  371. }
  372. return JBTs<T>(bts.Value, ids);
  373. }
  374. void ProcessLanguages();
  375. void ProcessLanguage(std::string const& lang);
  376. Json::ArrayIndex AddSourceGroup(cmSourceGroup* sg, Json::ArrayIndex si);
  377. CompileData BuildCompileData(cmSourceFile* sf);
  378. CompileData MergeCompileData(CompileData const& fd);
  379. Json::ArrayIndex AddSourceCompileGroup(cmSourceFile* sf,
  380. Json::ArrayIndex si);
  381. void AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt);
  382. void AddBacktrace(Json::Value& object, JBTIndex bt);
  383. Json::Value DumpPaths();
  384. Json::Value DumpCompileData(CompileData const& cd);
  385. Json::Value DumpInclude(CompileData::IncludeEntry const& inc);
  386. Json::Value DumpPrecompileHeader(JBT<std::string> const& header);
  387. Json::Value DumpLanguageStandard(JBTs<std::string> const& standard);
  388. Json::Value DumpDefine(JBT<std::string> const& def);
  389. Json::Value DumpSources();
  390. Json::Value DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
  391. Json::ArrayIndex si);
  392. Json::Value DumpSourceGroups();
  393. Json::Value DumpSourceGroup(SourceGroup& sg);
  394. Json::Value DumpCompileGroups();
  395. Json::Value DumpCompileGroup(CompileGroup& cg);
  396. Json::Value DumpSysroot(std::string const& path);
  397. Json::Value DumpInstall();
  398. Json::Value DumpInstallPrefix();
  399. Json::Value DumpInstallDestinations();
  400. Json::Value DumpInstallDestination(cmInstallTargetGenerator* itGen);
  401. Json::Value DumpArtifacts();
  402. Json::Value DumpLink();
  403. Json::Value DumpArchive();
  404. Json::Value DumpLinkCommandFragments();
  405. Json::Value DumpCommandFragments(std::vector<JBT<std::string>> const& frags);
  406. Json::Value DumpCommandFragment(JBT<std::string> const& frag,
  407. std::string const& role = std::string());
  408. Json::Value DumpDependencies();
  409. Json::Value DumpDependency(cmTargetDepend const& td);
  410. Json::Value DumpFolder();
  411. public:
  412. Target(cmGeneratorTarget* gt, std::string const& config);
  413. Json::Value Dump();
  414. };
  415. Codemodel::Codemodel(cmFileAPI& fileAPI, unsigned long version)
  416. : FileAPI(fileAPI)
  417. , Version(version)
  418. {
  419. }
  420. Json::Value Codemodel::Dump()
  421. {
  422. Json::Value codemodel = Json::objectValue;
  423. codemodel["paths"] = this->DumpPaths();
  424. codemodel["configurations"] = this->DumpConfigurations();
  425. return codemodel;
  426. }
  427. Json::Value Codemodel::DumpPaths()
  428. {
  429. Json::Value paths = Json::objectValue;
  430. paths["source"] = this->FileAPI.GetCMakeInstance()->GetHomeDirectory();
  431. paths["build"] = this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory();
  432. return paths;
  433. }
  434. Json::Value Codemodel::DumpConfigurations()
  435. {
  436. Json::Value configurations = Json::arrayValue;
  437. cmGlobalGenerator* gg =
  438. this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
  439. const auto& makefiles = gg->GetMakefiles();
  440. if (!makefiles.empty()) {
  441. std::vector<std::string> const& configs =
  442. makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
  443. for (std::string const& config : configs) {
  444. configurations.append(this->DumpConfiguration(config));
  445. }
  446. }
  447. return configurations;
  448. }
  449. Json::Value Codemodel::DumpConfiguration(std::string const& config)
  450. {
  451. CodemodelConfig configuration(this->FileAPI, this->Version, config);
  452. return configuration.Dump();
  453. }
  454. CodemodelConfig::CodemodelConfig(cmFileAPI& fileAPI, unsigned long version,
  455. std::string const& config)
  456. : FileAPI(fileAPI)
  457. , Version(version)
  458. , Config(config)
  459. , TopSource(this->FileAPI.GetCMakeInstance()->GetHomeDirectory())
  460. , TopBuild(this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory())
  461. {
  462. static_cast<void>(this->Version);
  463. }
  464. Json::Value CodemodelConfig::Dump()
  465. {
  466. Json::Value configuration = Json::objectValue;
  467. configuration["name"] = this->Config;
  468. this->ProcessDirectories();
  469. configuration["targets"] = this->DumpTargets();
  470. configuration["directories"] = this->DumpDirectories();
  471. configuration["projects"] = this->DumpProjects();
  472. return configuration;
  473. }
  474. void CodemodelConfig::ProcessDirectories()
  475. {
  476. cmGlobalGenerator* gg =
  477. this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
  478. auto const& localGens = gg->GetLocalGenerators();
  479. // Add directories in forward order to process parents before children.
  480. this->Directories.reserve(localGens.size());
  481. for (const auto& lg : localGens) {
  482. auto directoryIndex =
  483. static_cast<Json::ArrayIndex>(this->Directories.size());
  484. this->Directories.emplace_back();
  485. Directory& d = this->Directories[directoryIndex];
  486. d.Snapshot = lg->GetStateSnapshot().GetBuildsystemDirectory();
  487. d.LocalGenerator = lg.get();
  488. this->DirectoryMap[d.Snapshot] = directoryIndex;
  489. d.ProjectIndex = this->AddProject(d.Snapshot);
  490. this->Projects[d.ProjectIndex].DirectoryIndexes.append(directoryIndex);
  491. }
  492. // Update directories in reverse order to process children before parents.
  493. for (auto di = this->Directories.rbegin(); di != this->Directories.rend();
  494. ++di) {
  495. Directory& d = *di;
  496. // Accumulate the presence of install rules on the way up.
  497. for (const auto& gen :
  498. d.LocalGenerator->GetMakefile()->GetInstallGenerators()) {
  499. if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(gen.get())) {
  500. d.HasInstallRule = true;
  501. break;
  502. }
  503. }
  504. if (!d.HasInstallRule) {
  505. for (cmStateSnapshot const& child : d.Snapshot.GetChildren()) {
  506. cmStateSnapshot childDir = child.GetBuildsystemDirectory();
  507. Json::ArrayIndex const childIndex = this->GetDirectoryIndex(childDir);
  508. if (this->Directories[childIndex].HasInstallRule) {
  509. d.HasInstallRule = true;
  510. break;
  511. }
  512. }
  513. }
  514. }
  515. }
  516. Json::ArrayIndex CodemodelConfig::GetDirectoryIndex(cmLocalGenerator const* lg)
  517. {
  518. return this->GetDirectoryIndex(
  519. lg->GetStateSnapshot().GetBuildsystemDirectory());
  520. }
  521. Json::ArrayIndex CodemodelConfig::GetDirectoryIndex(cmStateSnapshot s)
  522. {
  523. auto i = this->DirectoryMap.find(s);
  524. assert(i != this->DirectoryMap.end());
  525. return i->second;
  526. }
  527. Json::ArrayIndex CodemodelConfig::AddProject(cmStateSnapshot s)
  528. {
  529. cmStateSnapshot ps = s.GetBuildsystemDirectoryParent();
  530. if (ps.IsValid() && ps.GetProjectName() == s.GetProjectName()) {
  531. // This directory is part of its parent directory project.
  532. Json::ArrayIndex const parentDirIndex = this->GetDirectoryIndex(ps);
  533. return this->Directories[parentDirIndex].ProjectIndex;
  534. }
  535. // This directory starts a new project.
  536. auto projectIndex = static_cast<Json::ArrayIndex>(this->Projects.size());
  537. this->Projects.emplace_back();
  538. Project& p = this->Projects[projectIndex];
  539. p.Snapshot = s;
  540. this->ProjectMap[s] = projectIndex;
  541. if (ps.IsValid()) {
  542. Json::ArrayIndex const parentDirIndex = this->GetDirectoryIndex(ps);
  543. p.ParentIndex = this->Directories[parentDirIndex].ProjectIndex;
  544. this->Projects[p.ParentIndex].ChildIndexes.append(projectIndex);
  545. }
  546. return projectIndex;
  547. }
  548. Json::Value CodemodelConfig::DumpTargets()
  549. {
  550. Json::Value targets = Json::arrayValue;
  551. std::vector<cmGeneratorTarget*> targetList;
  552. cmGlobalGenerator* gg =
  553. this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
  554. for (const auto& lg : gg->GetLocalGenerators()) {
  555. cm::append(targetList, lg->GetGeneratorTargets());
  556. }
  557. std::sort(targetList.begin(), targetList.end(),
  558. [](cmGeneratorTarget* l, cmGeneratorTarget* r) {
  559. return l->GetName() < r->GetName();
  560. });
  561. for (cmGeneratorTarget* gt : targetList) {
  562. if (gt->GetType() == cmStateEnums::GLOBAL_TARGET ||
  563. !gt->IsInBuildSystem()) {
  564. continue;
  565. }
  566. targets.append(this->DumpTarget(gt, targets.size()));
  567. }
  568. return targets;
  569. }
  570. Json::Value CodemodelConfig::DumpTarget(cmGeneratorTarget* gt,
  571. Json::ArrayIndex ti)
  572. {
  573. Target t(gt, this->Config);
  574. std::string prefix = "target-" + gt->GetName();
  575. for (char& c : prefix) {
  576. // CMP0037 OLD behavior allows slashes in target names. Remove them.
  577. if (c == '/' || c == '\\') {
  578. c = '_';
  579. }
  580. }
  581. if (!this->Config.empty()) {
  582. prefix += "-" + this->Config;
  583. }
  584. Json::Value target = this->FileAPI.MaybeJsonFile(t.Dump(), prefix);
  585. target["name"] = gt->GetName();
  586. target["id"] = TargetId(gt, this->TopBuild);
  587. // Cross-reference directory containing target.
  588. Json::ArrayIndex di = this->GetDirectoryIndex(gt->GetLocalGenerator());
  589. target["directoryIndex"] = di;
  590. this->Directories[di].TargetIndexes.append(ti);
  591. // Cross-reference project containing target.
  592. Json::ArrayIndex pi = this->Directories[di].ProjectIndex;
  593. target["projectIndex"] = pi;
  594. this->Projects[pi].TargetIndexes.append(ti);
  595. this->TargetIndexMap[gt] = ti;
  596. return target;
  597. }
  598. Json::Value CodemodelConfig::DumpDirectories()
  599. {
  600. Json::Value directories = Json::arrayValue;
  601. for (Directory& d : this->Directories) {
  602. directories.append(this->DumpDirectory(d));
  603. }
  604. return directories;
  605. }
  606. Json::Value CodemodelConfig::DumpDirectory(Directory& d)
  607. {
  608. Json::Value directory = Json::objectValue;
  609. std::string sourceDir = d.Snapshot.GetDirectory().GetCurrentSource();
  610. directory["source"] = RelativeIfUnder(this->TopSource, sourceDir);
  611. std::string buildDir = d.Snapshot.GetDirectory().GetCurrentBinary();
  612. directory["build"] = RelativeIfUnder(this->TopBuild, buildDir);
  613. cmStateSnapshot parentDir = d.Snapshot.GetBuildsystemDirectoryParent();
  614. if (parentDir.IsValid()) {
  615. directory["parentIndex"] = this->GetDirectoryIndex(parentDir);
  616. }
  617. Json::Value childIndexes = Json::arrayValue;
  618. for (cmStateSnapshot const& child : d.Snapshot.GetChildren()) {
  619. childIndexes.append(
  620. this->GetDirectoryIndex(child.GetBuildsystemDirectory()));
  621. }
  622. if (!childIndexes.empty()) {
  623. directory["childIndexes"] = std::move(childIndexes);
  624. }
  625. directory["projectIndex"] = d.ProjectIndex;
  626. if (!d.TargetIndexes.empty()) {
  627. directory["targetIndexes"] = std::move(d.TargetIndexes);
  628. }
  629. Json::Value minimumCMakeVersion = this->DumpMinimumCMakeVersion(d.Snapshot);
  630. if (!minimumCMakeVersion.isNull()) {
  631. directory["minimumCMakeVersion"] = std::move(minimumCMakeVersion);
  632. }
  633. if (d.HasInstallRule) {
  634. directory["hasInstallRule"] = true;
  635. }
  636. return directory;
  637. }
  638. Json::Value CodemodelConfig::DumpProjects()
  639. {
  640. Json::Value projects = Json::arrayValue;
  641. for (Project& p : this->Projects) {
  642. projects.append(this->DumpProject(p));
  643. }
  644. return projects;
  645. }
  646. Json::Value CodemodelConfig::DumpProject(Project& p)
  647. {
  648. Json::Value project = Json::objectValue;
  649. project["name"] = p.Snapshot.GetProjectName();
  650. if (p.ParentIndex != Project::NoParentIndex) {
  651. project["parentIndex"] = p.ParentIndex;
  652. }
  653. if (!p.ChildIndexes.empty()) {
  654. project["childIndexes"] = std::move(p.ChildIndexes);
  655. }
  656. project["directoryIndexes"] = std::move(p.DirectoryIndexes);
  657. if (!p.TargetIndexes.empty()) {
  658. project["targetIndexes"] = std::move(p.TargetIndexes);
  659. }
  660. return project;
  661. }
  662. Json::Value CodemodelConfig::DumpMinimumCMakeVersion(cmStateSnapshot s)
  663. {
  664. Json::Value minimumCMakeVersion;
  665. if (std::string const* def =
  666. s.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
  667. minimumCMakeVersion = Json::objectValue;
  668. minimumCMakeVersion["string"] = *def;
  669. }
  670. return minimumCMakeVersion;
  671. }
  672. Target::Target(cmGeneratorTarget* gt, std::string const& config)
  673. : GT(gt)
  674. , Config(config)
  675. , TopSource(gt->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
  676. , TopBuild(
  677. gt->GetGlobalGenerator()->GetCMakeInstance()->GetHomeOutputDirectory())
  678. , SourceGroupsLocal(this->GT->Makefile->GetSourceGroups())
  679. , Backtraces(this->TopSource)
  680. {
  681. }
  682. Json::Value Target::Dump()
  683. {
  684. Json::Value target = Json::objectValue;
  685. cmStateEnums::TargetType const type = this->GT->GetType();
  686. target["name"] = this->GT->GetName();
  687. target["type"] = cmState::GetTargetTypeName(type);
  688. target["id"] = TargetId(this->GT, this->TopBuild);
  689. target["paths"] = this->DumpPaths();
  690. if (this->GT->Target->GetIsGeneratorProvided()) {
  691. target["isGeneratorProvided"] = true;
  692. }
  693. this->AddBacktrace(target, this->GT->GetBacktrace());
  694. if (this->GT->Target->GetHaveInstallRule()) {
  695. target["install"] = this->DumpInstall();
  696. }
  697. if (this->GT->HaveWellDefinedOutputFiles()) {
  698. Json::Value artifacts = this->DumpArtifacts();
  699. if (!artifacts.empty()) {
  700. target["artifacts"] = std::move(artifacts);
  701. }
  702. }
  703. if (type == cmStateEnums::EXECUTABLE ||
  704. type == cmStateEnums::SHARED_LIBRARY ||
  705. type == cmStateEnums::MODULE_LIBRARY) {
  706. target["nameOnDisk"] = this->GT->GetFullName(this->Config);
  707. target["link"] = this->DumpLink();
  708. } else if (type == cmStateEnums::STATIC_LIBRARY) {
  709. target["nameOnDisk"] = this->GT->GetFullName(this->Config);
  710. target["archive"] = this->DumpArchive();
  711. }
  712. Json::Value dependencies = this->DumpDependencies();
  713. if (!dependencies.empty()) {
  714. target["dependencies"] = dependencies;
  715. }
  716. {
  717. this->ProcessLanguages();
  718. target["sources"] = this->DumpSources();
  719. Json::Value folder = this->DumpFolder();
  720. if (!folder.isNull()) {
  721. target["folder"] = std::move(folder);
  722. }
  723. Json::Value sourceGroups = this->DumpSourceGroups();
  724. if (!sourceGroups.empty()) {
  725. target["sourceGroups"] = std::move(sourceGroups);
  726. }
  727. Json::Value compileGroups = this->DumpCompileGroups();
  728. if (!compileGroups.empty()) {
  729. target["compileGroups"] = std::move(compileGroups);
  730. }
  731. }
  732. target["backtraceGraph"] = this->Backtraces.Dump();
  733. return target;
  734. }
  735. void Target::ProcessLanguages()
  736. {
  737. std::set<std::string> languages;
  738. this->GT->GetLanguages(languages, this->Config);
  739. for (std::string const& lang : languages) {
  740. this->ProcessLanguage(lang);
  741. }
  742. }
  743. void Target::ProcessLanguage(std::string const& lang)
  744. {
  745. CompileData& cd = this->CompileDataMap[lang];
  746. cd.Language = lang;
  747. if (cmProp sysrootCompile =
  748. this->GT->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE")) {
  749. cd.Sysroot = *sysrootCompile;
  750. } else if (cmProp sysroot =
  751. this->GT->Makefile->GetDefinition("CMAKE_SYSROOT")) {
  752. cd.Sysroot = *sysroot;
  753. }
  754. cmLocalGenerator* lg = this->GT->GetLocalGenerator();
  755. {
  756. // FIXME: Add flags from end section of ExpandRuleVariable,
  757. // which may need to be factored out.
  758. std::vector<BT<std::string>> flags =
  759. lg->GetTargetCompileFlags(this->GT, this->Config, lang);
  760. cd.Flags.reserve(flags.size());
  761. for (const BT<std::string>& f : flags) {
  762. cd.Flags.emplace_back(this->ToJBT(f));
  763. }
  764. }
  765. std::set<BT<std::string>> defines =
  766. lg->GetTargetDefines(this->GT, this->Config, lang);
  767. cd.Defines.reserve(defines.size());
  768. for (BT<std::string> const& d : defines) {
  769. cd.Defines.emplace_back(this->ToJBT(d));
  770. }
  771. std::vector<BT<std::string>> includePathList =
  772. lg->GetIncludeDirectories(this->GT, lang, this->Config);
  773. for (BT<std::string> const& i : includePathList) {
  774. cd.Includes.emplace_back(
  775. this->ToJBT(i),
  776. this->GT->IsSystemIncludeDirectory(i.Value, this->Config, lang));
  777. }
  778. std::vector<BT<std::string>> precompileHeaders =
  779. this->GT->GetPrecompileHeaders(this->Config, lang);
  780. for (BT<std::string> const& pch : precompileHeaders) {
  781. cd.PrecompileHeaders.emplace_back(this->ToJBT(pch));
  782. }
  783. BTs<std::string> const* languageStandard =
  784. this->GT->GetLanguageStandardProperty(lang, this->Config);
  785. if (languageStandard) {
  786. cd.LanguageStandard = this->ToJBTs(*languageStandard);
  787. }
  788. }
  789. Json::ArrayIndex Target::AddSourceGroup(cmSourceGroup* sg, Json::ArrayIndex si)
  790. {
  791. auto i = this->SourceGroupsMap.find(sg);
  792. if (i == this->SourceGroupsMap.end()) {
  793. auto sgIndex = static_cast<Json::ArrayIndex>(this->SourceGroups.size());
  794. i = this->SourceGroupsMap.emplace(sg, sgIndex).first;
  795. SourceGroup g;
  796. g.Name = sg->GetFullName();
  797. this->SourceGroups.push_back(std::move(g));
  798. }
  799. this->SourceGroups[i->second].SourceIndexes.append(si);
  800. return i->second;
  801. }
  802. CompileData Target::BuildCompileData(cmSourceFile* sf)
  803. {
  804. CompileData fd;
  805. fd.Language = sf->GetOrDetermineLanguage();
  806. if (fd.Language.empty()) {
  807. return fd;
  808. }
  809. cmLocalGenerator* lg = this->GT->GetLocalGenerator();
  810. cmGeneratorExpressionInterpreter genexInterpreter(lg, this->Config, this->GT,
  811. fd.Language);
  812. const std::string COMPILE_FLAGS("COMPILE_FLAGS");
  813. if (cmProp cflags = sf->GetProperty(COMPILE_FLAGS)) {
  814. std::string flags = genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS);
  815. fd.Flags.emplace_back(std::move(flags), JBTIndex());
  816. }
  817. const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
  818. for (BT<std::string> tmpOpt : sf->GetCompileOptions()) {
  819. tmpOpt.Value = genexInterpreter.Evaluate(tmpOpt.Value, COMPILE_OPTIONS);
  820. // After generator evaluation we need to use the AppendCompileOptions
  821. // method so we handle situations where backtrace entries have lists
  822. // and properly escape flags.
  823. std::string tmp;
  824. lg->AppendCompileOptions(tmp, tmpOpt.Value);
  825. BT<std::string> opt(tmp, tmpOpt.Backtrace);
  826. fd.Flags.emplace_back(this->ToJBT(opt));
  827. }
  828. // Add precompile headers compile options.
  829. std::vector<std::string> architectures;
  830. this->GT->GetAppleArchs(this->Config, architectures);
  831. if (architectures.empty()) {
  832. architectures.emplace_back();
  833. }
  834. std::unordered_map<std::string, std::string> pchSources;
  835. for (const std::string& arch : architectures) {
  836. const std::string pchSource =
  837. this->GT->GetPchSource(this->Config, fd.Language, arch);
  838. if (!pchSource.empty()) {
  839. pchSources.insert(std::make_pair(pchSource, arch));
  840. }
  841. }
  842. if (!pchSources.empty() && !sf->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
  843. std::string pchOptions;
  844. auto pchIt = pchSources.find(sf->ResolveFullPath());
  845. if (pchIt != pchSources.end()) {
  846. pchOptions = this->GT->GetPchCreateCompileOptions(
  847. this->Config, fd.Language, pchIt->second);
  848. } else {
  849. pchOptions =
  850. this->GT->GetPchUseCompileOptions(this->Config, fd.Language);
  851. }
  852. BT<std::string> tmpOpt(pchOptions);
  853. tmpOpt.Value = genexInterpreter.Evaluate(tmpOpt.Value, COMPILE_OPTIONS);
  854. // After generator evaluation we need to use the AppendCompileOptions
  855. // method so we handle situations where backtrace entries have lists
  856. // and properly escape flags.
  857. std::string tmp;
  858. lg->AppendCompileOptions(tmp, tmpOpt.Value);
  859. BT<std::string> opt(tmp, tmpOpt.Backtrace);
  860. fd.Flags.emplace_back(this->ToJBT(opt));
  861. }
  862. // Add include directories from source file properties.
  863. {
  864. const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
  865. for (BT<std::string> tmpInclude : sf->GetIncludeDirectories()) {
  866. tmpInclude.Value =
  867. genexInterpreter.Evaluate(tmpInclude.Value, INCLUDE_DIRECTORIES);
  868. // After generator evaluation we need to use the AppendIncludeDirectories
  869. // method so we handle situations where backtrace entries have lists.
  870. std::vector<std::string> tmp;
  871. lg->AppendIncludeDirectories(tmp, tmpInclude.Value, *sf);
  872. for (std::string& i : tmp) {
  873. bool const isSystemInclude =
  874. this->GT->IsSystemIncludeDirectory(i, this->Config, fd.Language);
  875. BT<std::string> include(i, tmpInclude.Backtrace);
  876. fd.Includes.emplace_back(this->ToJBT(include), isSystemInclude);
  877. }
  878. }
  879. }
  880. const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
  881. std::set<BT<std::string>> fileDefines;
  882. for (BT<std::string> tmpDef : sf->GetCompileDefinitions()) {
  883. tmpDef.Value =
  884. genexInterpreter.Evaluate(tmpDef.Value, COMPILE_DEFINITIONS);
  885. // After generator evaluation we need to use the AppendDefines method
  886. // so we handle situations where backtrace entries have lists.
  887. std::set<std::string> tmp;
  888. lg->AppendDefines(tmp, tmpDef.Value);
  889. for (const std::string& i : tmp) {
  890. BT<std::string> def(i, tmpDef.Backtrace);
  891. fileDefines.insert(def);
  892. }
  893. }
  894. std::set<std::string> configFileDefines;
  895. const std::string defPropName =
  896. "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(this->Config);
  897. if (cmProp config_defs = sf->GetProperty(defPropName)) {
  898. lg->AppendDefines(
  899. configFileDefines,
  900. genexInterpreter.Evaluate(*config_defs, COMPILE_DEFINITIONS));
  901. }
  902. fd.Defines.reserve(fileDefines.size() + configFileDefines.size());
  903. for (BT<std::string> const& def : fileDefines) {
  904. fd.Defines.emplace_back(this->ToJBT(def));
  905. }
  906. for (std::string const& d : configFileDefines) {
  907. fd.Defines.emplace_back(d, JBTIndex());
  908. }
  909. return fd;
  910. }
  911. CompileData Target::MergeCompileData(CompileData const& fd)
  912. {
  913. CompileData cd;
  914. cd.Language = fd.Language;
  915. if (cd.Language.empty()) {
  916. return cd;
  917. }
  918. CompileData const& td = this->CompileDataMap.at(cd.Language);
  919. // All compile groups share the sysroot of the target.
  920. cd.Sysroot = td.Sysroot;
  921. // All compile groups share the precompile headers of the target.
  922. cd.PrecompileHeaders = td.PrecompileHeaders;
  923. // All compile groups share the language standard of the target.
  924. cd.LanguageStandard = td.LanguageStandard;
  925. // Use target-wide flags followed by source-specific flags.
  926. cd.Flags.reserve(td.Flags.size() + fd.Flags.size());
  927. cd.Flags.insert(cd.Flags.end(), td.Flags.begin(), td.Flags.end());
  928. cd.Flags.insert(cd.Flags.end(), fd.Flags.begin(), fd.Flags.end());
  929. // Use source-specific includes followed by target-wide includes.
  930. cd.Includes.reserve(fd.Includes.size() + td.Includes.size());
  931. cd.Includes.insert(cd.Includes.end(), fd.Includes.begin(),
  932. fd.Includes.end());
  933. cd.Includes.insert(cd.Includes.end(), td.Includes.begin(),
  934. td.Includes.end());
  935. // Use target-wide defines followed by source-specific defines.
  936. cd.Defines.reserve(td.Defines.size() + fd.Defines.size());
  937. cd.Defines.insert(cd.Defines.end(), td.Defines.begin(), td.Defines.end());
  938. cd.Defines.insert(cd.Defines.end(), fd.Defines.begin(), fd.Defines.end());
  939. // De-duplicate defines.
  940. std::stable_sort(cd.Defines.begin(), cd.Defines.end(),
  941. JBT<std::string>::ValueLess);
  942. auto end = std::unique(cd.Defines.begin(), cd.Defines.end(),
  943. JBT<std::string>::ValueEq);
  944. cd.Defines.erase(end, cd.Defines.end());
  945. return cd;
  946. }
  947. Json::ArrayIndex Target::AddSourceCompileGroup(cmSourceFile* sf,
  948. Json::ArrayIndex si)
  949. {
  950. CompileData compileData = this->BuildCompileData(sf);
  951. auto i = this->CompileGroupMap.find(compileData);
  952. if (i == this->CompileGroupMap.end()) {
  953. Json::ArrayIndex cgIndex =
  954. static_cast<Json::ArrayIndex>(this->CompileGroups.size());
  955. i = this->CompileGroupMap.emplace(std::move(compileData), cgIndex).first;
  956. CompileGroup g;
  957. g.Entry = i;
  958. this->CompileGroups.push_back(std::move(g));
  959. }
  960. this->CompileGroups[i->second].SourceIndexes.append(si);
  961. return i->second;
  962. }
  963. void Target::AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt)
  964. {
  965. if (JBTIndex backtrace = this->Backtraces.Add(bt)) {
  966. object["backtrace"] = backtrace.Index;
  967. }
  968. }
  969. void Target::AddBacktrace(Json::Value& object, JBTIndex bt)
  970. {
  971. if (bt) {
  972. object["backtrace"] = bt.Index;
  973. }
  974. }
  975. Json::Value Target::DumpPaths()
  976. {
  977. Json::Value paths = Json::objectValue;
  978. cmLocalGenerator* lg = this->GT->GetLocalGenerator();
  979. std::string const& sourceDir = lg->GetCurrentSourceDirectory();
  980. paths["source"] = RelativeIfUnder(this->TopSource, sourceDir);
  981. std::string const& buildDir = lg->GetCurrentBinaryDirectory();
  982. paths["build"] = RelativeIfUnder(this->TopBuild, buildDir);
  983. return paths;
  984. }
  985. Json::Value Target::DumpSources()
  986. {
  987. Json::Value sources = Json::arrayValue;
  988. cmGeneratorTarget::KindedSources const& kinded =
  989. this->GT->GetKindedSources(this->Config);
  990. for (cmGeneratorTarget::SourceAndKind const& sk : kinded.Sources) {
  991. sources.append(this->DumpSource(sk, sources.size()));
  992. }
  993. return sources;
  994. }
  995. Json::Value Target::DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
  996. Json::ArrayIndex si)
  997. {
  998. Json::Value source = Json::objectValue;
  999. std::string const path = sk.Source.Value->ResolveFullPath();
  1000. source["path"] = RelativeIfUnder(this->TopSource, path);
  1001. if (sk.Source.Value->GetIsGenerated()) {
  1002. source["isGenerated"] = true;
  1003. }
  1004. this->AddBacktrace(source, sk.Source.Backtrace);
  1005. if (cmSourceGroup* sg =
  1006. this->GT->Makefile->FindSourceGroup(path, this->SourceGroupsLocal)) {
  1007. source["sourceGroupIndex"] = this->AddSourceGroup(sg, si);
  1008. }
  1009. switch (sk.Kind) {
  1010. case cmGeneratorTarget::SourceKindObjectSource: {
  1011. source["compileGroupIndex"] =
  1012. this->AddSourceCompileGroup(sk.Source.Value, si);
  1013. } break;
  1014. case cmGeneratorTarget::SourceKindAppManifest:
  1015. case cmGeneratorTarget::SourceKindCertificate:
  1016. case cmGeneratorTarget::SourceKindCustomCommand:
  1017. case cmGeneratorTarget::SourceKindExternalObject:
  1018. case cmGeneratorTarget::SourceKindExtra:
  1019. case cmGeneratorTarget::SourceKindHeader:
  1020. case cmGeneratorTarget::SourceKindIDL:
  1021. case cmGeneratorTarget::SourceKindManifest:
  1022. case cmGeneratorTarget::SourceKindModuleDefinition:
  1023. case cmGeneratorTarget::SourceKindResx:
  1024. case cmGeneratorTarget::SourceKindXaml:
  1025. case cmGeneratorTarget::SourceKindUnityBatched:
  1026. break;
  1027. }
  1028. return source;
  1029. }
  1030. Json::Value Target::DumpCompileData(CompileData const& cd)
  1031. {
  1032. Json::Value result = Json::objectValue;
  1033. if (!cd.Language.empty()) {
  1034. result["language"] = cd.Language;
  1035. }
  1036. if (!cd.Sysroot.empty()) {
  1037. result["sysroot"] = this->DumpSysroot(cd.Sysroot);
  1038. }
  1039. if (!cd.Flags.empty()) {
  1040. result["compileCommandFragments"] = this->DumpCommandFragments(cd.Flags);
  1041. }
  1042. if (!cd.Includes.empty()) {
  1043. Json::Value includes = Json::arrayValue;
  1044. for (auto const& i : cd.Includes) {
  1045. includes.append(this->DumpInclude(i));
  1046. }
  1047. result["includes"] = includes;
  1048. }
  1049. if (!cd.Defines.empty()) {
  1050. Json::Value defines = Json::arrayValue;
  1051. for (JBT<std::string> const& d : cd.Defines) {
  1052. defines.append(this->DumpDefine(d));
  1053. }
  1054. result["defines"] = std::move(defines);
  1055. }
  1056. if (!cd.PrecompileHeaders.empty()) {
  1057. Json::Value precompileHeaders = Json::arrayValue;
  1058. for (JBT<std::string> const& pch : cd.PrecompileHeaders) {
  1059. precompileHeaders.append(this->DumpPrecompileHeader(pch));
  1060. }
  1061. result["precompileHeaders"] = std::move(precompileHeaders);
  1062. }
  1063. if (!cd.LanguageStandard.Value.empty()) {
  1064. result["languageStandard"] =
  1065. this->DumpLanguageStandard(cd.LanguageStandard);
  1066. }
  1067. return result;
  1068. }
  1069. Json::Value Target::DumpInclude(CompileData::IncludeEntry const& inc)
  1070. {
  1071. Json::Value include = Json::objectValue;
  1072. include["path"] = inc.Path.Value;
  1073. if (inc.IsSystem) {
  1074. include["isSystem"] = true;
  1075. }
  1076. this->AddBacktrace(include, inc.Path.Backtrace);
  1077. return include;
  1078. }
  1079. Json::Value Target::DumpPrecompileHeader(JBT<std::string> const& header)
  1080. {
  1081. Json::Value precompileHeader = Json::objectValue;
  1082. precompileHeader["header"] = header.Value;
  1083. this->AddBacktrace(precompileHeader, header.Backtrace);
  1084. return precompileHeader;
  1085. }
  1086. Json::Value Target::DumpLanguageStandard(JBTs<std::string> const& standard)
  1087. {
  1088. Json::Value languageStandard = Json::objectValue;
  1089. languageStandard["standard"] = standard.Value;
  1090. if (!standard.Backtraces.empty()) {
  1091. Json::Value backtraces = Json::arrayValue;
  1092. for (JBTIndex backtrace : standard.Backtraces) {
  1093. backtraces.append(backtrace.Index);
  1094. }
  1095. languageStandard["backtraces"] = backtraces;
  1096. }
  1097. return languageStandard;
  1098. }
  1099. Json::Value Target::DumpDefine(JBT<std::string> const& def)
  1100. {
  1101. Json::Value define = Json::objectValue;
  1102. define["define"] = def.Value;
  1103. this->AddBacktrace(define, def.Backtrace);
  1104. return define;
  1105. }
  1106. Json::Value Target::DumpSourceGroups()
  1107. {
  1108. Json::Value sourceGroups = Json::arrayValue;
  1109. for (auto& sg : this->SourceGroups) {
  1110. sourceGroups.append(this->DumpSourceGroup(sg));
  1111. }
  1112. return sourceGroups;
  1113. }
  1114. Json::Value Target::DumpSourceGroup(SourceGroup& sg)
  1115. {
  1116. Json::Value group = Json::objectValue;
  1117. group["name"] = sg.Name;
  1118. group["sourceIndexes"] = std::move(sg.SourceIndexes);
  1119. return group;
  1120. }
  1121. Json::Value Target::DumpCompileGroups()
  1122. {
  1123. Json::Value compileGroups = Json::arrayValue;
  1124. for (auto& cg : this->CompileGroups) {
  1125. compileGroups.append(this->DumpCompileGroup(cg));
  1126. }
  1127. return compileGroups;
  1128. }
  1129. Json::Value Target::DumpCompileGroup(CompileGroup& cg)
  1130. {
  1131. Json::Value group =
  1132. this->DumpCompileData(this->MergeCompileData(cg.Entry->first));
  1133. group["sourceIndexes"] = std::move(cg.SourceIndexes);
  1134. return group;
  1135. }
  1136. Json::Value Target::DumpSysroot(std::string const& path)
  1137. {
  1138. Json::Value sysroot = Json::objectValue;
  1139. sysroot["path"] = path;
  1140. return sysroot;
  1141. }
  1142. Json::Value Target::DumpInstall()
  1143. {
  1144. Json::Value install = Json::objectValue;
  1145. install["prefix"] = this->DumpInstallPrefix();
  1146. install["destinations"] = this->DumpInstallDestinations();
  1147. return install;
  1148. }
  1149. Json::Value Target::DumpInstallPrefix()
  1150. {
  1151. Json::Value prefix = Json::objectValue;
  1152. std::string p =
  1153. this->GT->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
  1154. cmSystemTools::ConvertToUnixSlashes(p);
  1155. prefix["path"] = p;
  1156. return prefix;
  1157. }
  1158. Json::Value Target::DumpInstallDestinations()
  1159. {
  1160. Json::Value destinations = Json::arrayValue;
  1161. auto installGens = this->GT->Target->GetInstallGenerators();
  1162. for (auto* itGen : installGens) {
  1163. destinations.append(this->DumpInstallDestination(itGen));
  1164. }
  1165. return destinations;
  1166. }
  1167. Json::Value Target::DumpInstallDestination(cmInstallTargetGenerator* itGen)
  1168. {
  1169. Json::Value destination = Json::objectValue;
  1170. destination["path"] = itGen->GetDestination(this->Config);
  1171. this->AddBacktrace(destination, itGen->GetBacktrace());
  1172. return destination;
  1173. }
  1174. Json::Value Target::DumpArtifacts()
  1175. {
  1176. Json::Value artifacts = Json::arrayValue;
  1177. // Object libraries have only object files as artifacts.
  1178. if (this->GT->GetType() == cmStateEnums::OBJECT_LIBRARY) {
  1179. if (!this->GT->GetGlobalGenerator()->HasKnownObjectFileLocation(nullptr)) {
  1180. return artifacts;
  1181. }
  1182. std::vector<cmSourceFile const*> objectSources;
  1183. this->GT->GetObjectSources(objectSources, this->Config);
  1184. std::string const obj_dir = this->GT->GetObjectDirectory(this->Config);
  1185. for (cmSourceFile const* sf : objectSources) {
  1186. const std::string& obj = this->GT->GetObjectName(sf);
  1187. Json::Value artifact = Json::objectValue;
  1188. artifact["path"] = RelativeIfUnder(this->TopBuild, obj_dir + obj);
  1189. artifacts.append(std::move(artifact)); // NOLINT(*)
  1190. }
  1191. return artifacts;
  1192. }
  1193. // Other target types always have a "main" artifact.
  1194. {
  1195. Json::Value artifact = Json::objectValue;
  1196. artifact["path"] =
  1197. RelativeIfUnder(this->TopBuild,
  1198. this->GT->GetFullPath(
  1199. this->Config, cmStateEnums::RuntimeBinaryArtifact));
  1200. artifacts.append(std::move(artifact)); // NOLINT(*)
  1201. }
  1202. // Add Windows-specific artifacts produced by the linker.
  1203. if (this->GT->HasImportLibrary(this->Config)) {
  1204. Json::Value artifact = Json::objectValue;
  1205. artifact["path"] =
  1206. RelativeIfUnder(this->TopBuild,
  1207. this->GT->GetFullPath(
  1208. this->Config, cmStateEnums::ImportLibraryArtifact));
  1209. artifacts.append(std::move(artifact)); // NOLINT(*)
  1210. }
  1211. if (this->GT->IsDLLPlatform() &&
  1212. this->GT->GetType() != cmStateEnums::STATIC_LIBRARY) {
  1213. cmGeneratorTarget::OutputInfo const* output =
  1214. this->GT->GetOutputInfo(this->Config);
  1215. if (output && !output->PdbDir.empty()) {
  1216. Json::Value artifact = Json::objectValue;
  1217. artifact["path"] = RelativeIfUnder(this->TopBuild,
  1218. output->PdbDir + '/' +
  1219. this->GT->GetPDBName(this->Config));
  1220. artifacts.append(std::move(artifact)); // NOLINT(*)
  1221. }
  1222. }
  1223. return artifacts;
  1224. }
  1225. Json::Value Target::DumpLink()
  1226. {
  1227. Json::Value link = Json::objectValue;
  1228. std::string lang = this->GT->GetLinkerLanguage(this->Config);
  1229. link["language"] = lang;
  1230. {
  1231. Json::Value commandFragments = this->DumpLinkCommandFragments();
  1232. if (!commandFragments.empty()) {
  1233. link["commandFragments"] = std::move(commandFragments);
  1234. }
  1235. }
  1236. if (cmProp sysrootLink =
  1237. this->GT->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
  1238. link["sysroot"] = this->DumpSysroot(*sysrootLink);
  1239. } else if (cmProp sysroot =
  1240. this->GT->Makefile->GetDefinition("CMAKE_SYSROOT")) {
  1241. link["sysroot"] = this->DumpSysroot(*sysroot);
  1242. }
  1243. if (this->GT->IsIPOEnabled(lang, this->Config)) {
  1244. link["lto"] = true;
  1245. }
  1246. return link;
  1247. }
  1248. Json::Value Target::DumpArchive()
  1249. {
  1250. Json::Value archive = Json::objectValue;
  1251. {
  1252. // The "link" fragments not relevant to static libraries are empty.
  1253. Json::Value commandFragments = this->DumpLinkCommandFragments();
  1254. if (!commandFragments.empty()) {
  1255. archive["commandFragments"] = std::move(commandFragments);
  1256. }
  1257. }
  1258. std::string lang = this->GT->GetLinkerLanguage(this->Config);
  1259. if (this->GT->IsIPOEnabled(lang, this->Config)) {
  1260. archive["lto"] = true;
  1261. }
  1262. return archive;
  1263. }
  1264. Json::Value Target::DumpLinkCommandFragments()
  1265. {
  1266. Json::Value linkFragments = Json::arrayValue;
  1267. std::string linkLanguageFlags;
  1268. std::vector<BT<std::string>> linkFlags;
  1269. std::string frameworkPath;
  1270. std::vector<BT<std::string>> linkPath;
  1271. std::vector<BT<std::string>> linkLibs;
  1272. cmLocalGenerator* lg = this->GT->GetLocalGenerator();
  1273. cmLinkLineComputer linkLineComputer(lg,
  1274. lg->GetStateSnapshot().GetDirectory());
  1275. lg->GetTargetFlags(&linkLineComputer, this->Config, linkLibs,
  1276. linkLanguageFlags, linkFlags, frameworkPath, linkPath,
  1277. this->GT);
  1278. linkLanguageFlags = cmTrimWhitespace(linkLanguageFlags);
  1279. frameworkPath = cmTrimWhitespace(frameworkPath);
  1280. if (!linkLanguageFlags.empty()) {
  1281. linkFragments.append(
  1282. this->DumpCommandFragment(std::move(linkLanguageFlags), "flags"));
  1283. }
  1284. if (!linkFlags.empty()) {
  1285. for (BT<std::string> frag : linkFlags) {
  1286. frag.Value = cmTrimWhitespace(frag.Value);
  1287. linkFragments.append(
  1288. this->DumpCommandFragment(this->ToJBT(frag), "flags"));
  1289. }
  1290. }
  1291. if (!frameworkPath.empty()) {
  1292. linkFragments.append(
  1293. this->DumpCommandFragment(std::move(frameworkPath), "frameworkPath"));
  1294. }
  1295. if (!linkPath.empty()) {
  1296. for (BT<std::string> frag : linkPath) {
  1297. frag.Value = cmTrimWhitespace(frag.Value);
  1298. linkFragments.append(
  1299. this->DumpCommandFragment(this->ToJBT(frag), "libraryPath"));
  1300. }
  1301. }
  1302. if (!linkLibs.empty()) {
  1303. for (BT<std::string> frag : linkLibs) {
  1304. frag.Value = cmTrimWhitespace(frag.Value);
  1305. linkFragments.append(
  1306. this->DumpCommandFragment(this->ToJBT(frag), "libraries"));
  1307. }
  1308. }
  1309. return linkFragments;
  1310. }
  1311. Json::Value Target::DumpCommandFragments(
  1312. std::vector<JBT<std::string>> const& frags)
  1313. {
  1314. Json::Value commandFragments = Json::arrayValue;
  1315. for (JBT<std::string> const& f : frags) {
  1316. commandFragments.append(this->DumpCommandFragment(f));
  1317. }
  1318. return commandFragments;
  1319. }
  1320. Json::Value Target::DumpCommandFragment(JBT<std::string> const& frag,
  1321. std::string const& role)
  1322. {
  1323. Json::Value fragment = Json::objectValue;
  1324. fragment["fragment"] = frag.Value;
  1325. if (!role.empty()) {
  1326. fragment["role"] = role;
  1327. }
  1328. this->AddBacktrace(fragment, frag.Backtrace);
  1329. return fragment;
  1330. }
  1331. Json::Value Target::DumpDependencies()
  1332. {
  1333. Json::Value dependencies = Json::arrayValue;
  1334. cmGlobalGenerator* gg = this->GT->GetGlobalGenerator();
  1335. for (cmTargetDepend const& td : gg->GetTargetDirectDepends(this->GT)) {
  1336. dependencies.append(this->DumpDependency(td));
  1337. }
  1338. return dependencies;
  1339. }
  1340. Json::Value Target::DumpDependency(cmTargetDepend const& td)
  1341. {
  1342. Json::Value dependency = Json::objectValue;
  1343. dependency["id"] = TargetId(td, this->TopBuild);
  1344. this->AddBacktrace(dependency, td.GetBacktrace());
  1345. return dependency;
  1346. }
  1347. Json::Value Target::DumpFolder()
  1348. {
  1349. Json::Value folder;
  1350. if (cmProp f = this->GT->GetProperty("FOLDER")) {
  1351. folder = Json::objectValue;
  1352. folder["name"] = *f;
  1353. }
  1354. return folder;
  1355. }
  1356. }
  1357. Json::Value cmFileAPICodemodelDump(cmFileAPI& fileAPI, unsigned long version)
  1358. {
  1359. Codemodel codemodel(fileAPI, version);
  1360. return codemodel.Dump();
  1361. }