resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmExportLibraryDependenciesCommand.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmExportLibraryDependenciesCommand.h"
4
5 #include <map>
6 #include <utility>
7
8 #include <cm/memory>
9
10 #include "cmsys/FStream.hxx"
11
12 #include "cmExecutionStatus.h"
13 #include "cmGeneratedFileStream.h"
14 #include "cmGlobalGenerator.h"
15 #include "cmLocalGenerator.h"
16 #include "cmMakefile.h"
17 #include "cmStateTypes.h"
18 #include "cmStringAlgorithms.h"
19 #include "cmSystemTools.h"
20 #include "cmTarget.h"
21 #include "cmTargetLinkLibraryType.h"
22 #include "cmValue.h"
23 #include "cmake.h"
24
25 class cmListFileBacktrace;
26
27 static void FinalAction(cmMakefile& makefile, std::string const& filename,
28                         bool append)
29 {
30   // Use copy-if-different if not appending.
31   std::unique_ptr<cmsys::ofstream> foutPtr;
32   if (append) {
33     const auto openmodeApp = std::ios::app;
34     foutPtr = cm::make_unique<cmsys::ofstream>(filename.c_str(), openmodeApp);
35   } else {
36     std::unique_ptr<cmGeneratedFileStream> ap(
37       new cmGeneratedFileStream(filename, true));
38     ap->SetCopyIfDifferent(true);
39     foutPtr = std::move(ap);
40   }
41   std::ostream& fout = *foutPtr;
42
43   if (!fout) {
44     cmSystemTools::Error("Error Writing " + filename);
45     cmSystemTools::ReportLastSystemError("");
46     return;
47   }
48
49   // Collect dependency information about all library targets built in
50   // the project.
51   cmake* cm = makefile.GetCMakeInstance();
52   cmGlobalGenerator* global = cm->GetGlobalGenerator();
53   const auto& locals = global->GetMakefiles();
54   std::map<std::string, std::string> libDepsOld;
55   std::map<std::string, std::string> libDepsNew;
56   std::map<std::string, std::string> libTypes;
57   for (const auto& local : locals) {
58     for (auto const& tgt : local->GetTargets()) {
59       // Get the current target.
60       cmTarget const& target = tgt.second;
61
62       // Skip non-library targets.
63       if (target.GetType() < cmStateEnums::STATIC_LIBRARY ||
64           target.GetType() > cmStateEnums::MODULE_LIBRARY) {
65         continue;
66       }
67
68       // Construct the dependency variable name.
69       std::string targetEntry = cmStrCat(target.GetName(), "_LIB_DEPENDS");
70
71       // Construct the dependency variable value with the direct link
72       // dependencies.
73       std::string valueOld;
74       std::string valueNew;
75       cmTarget::LinkLibraryVectorType const& libs =
76         target.GetOriginalLinkLibraries();
77       for (cmTarget::LibraryID const& li : libs) {
78         std::string ltVar = cmStrCat(li.first, "_LINK_TYPE");
79         std::string ltValue;
80         switch (li.second) {
81           case GENERAL_LibraryType:
82             valueNew += "general;";
83             ltValue = "general";
84             break;
85           case DEBUG_LibraryType:
86             valueNew += "debug;";
87             ltValue = "debug";
88             break;
89           case OPTIMIZED_LibraryType:
90             valueNew += "optimized;";
91             ltValue = "optimized";
92             break;
93         }
94         std::string lib = li.first;
95         if (cmTarget* libtgt = global->FindTarget(lib)) {
96           // Handle simple output name changes.  This command is
97           // deprecated so we do not support full target name
98           // translation (which requires per-configuration info).
99           if (cmValue outname = libtgt->GetProperty("OUTPUT_NAME")) {
100             lib = *outname;
101           }
102         }
103         valueOld += lib;
104         valueOld += ";";
105         valueNew += lib;
106         valueNew += ";";
107
108         std::string& ltEntry = libTypes[ltVar];
109         if (ltEntry.empty()) {
110           ltEntry = ltValue;
111         } else if (ltEntry != ltValue) {
112           ltEntry = "general";
113         }
114       }
115       libDepsNew[targetEntry] = valueNew;
116       libDepsOld[targetEntry] = valueOld;
117     }
118   }
119
120   // Generate dependency information for both old and new style CMake
121   // versions.
122   const char* vertest =
123     "\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" GREATER 2.4";
124   fout << "# Generated by CMake\n\n";
125   fout << "if(" << vertest << ")\n";
126   fout << "  # Information for CMake 2.6 and above.\n";
127   for (auto const& i : libDepsNew) {
128     if (!i.second.empty()) {
129       fout << "  set(\"" << i.first << "\" \"" << i.second << "\")\n";
130     }
131   }
132   fout << "else()\n";
133   fout << "  # Information for CMake 2.4 and lower.\n";
134   for (auto const& i : libDepsOld) {
135     if (!i.second.empty()) {
136       fout << "  set(\"" << i.first << "\" \"" << i.second << "\")\n";
137     }
138   }
139   for (auto const& i : libTypes) {
140     if (i.second != "general") {
141       fout << "  set(\"" << i.first << "\" \"" << i.second << "\")\n";
142     }
143   }
144   fout << "endif()\n";
145 }
146
147 bool cmExportLibraryDependenciesCommand(std::vector<std::string> const& args,
148                                         cmExecutionStatus& status)
149 {
150   if (args.empty()) {
151     status.SetError("called with incorrect number of arguments");
152     return false;
153   }
154
155   std::string const& filename = args[0];
156   bool const append = args.size() > 1 && args[1] == "APPEND";
157   status.GetMakefile().AddGeneratorAction(
158     [filename, append](cmLocalGenerator& lg, const cmListFileBacktrace&) {
159       FinalAction(*lg.GetMakefile(), filename, append);
160     });
161
162   return true;
163 }